emeals 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +8 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +33 -0
- data/Rakefile +6 -0
- data/emeals.gemspec +19 -0
- data/lib/emeals.rb +6 -0
- data/lib/emeals/client.rb +34 -0
- data/lib/emeals/dish.rb +61 -0
- data/lib/emeals/meal.rb +135 -0
- data/lib/emeals/menu.rb +34 -0
- data/lib/emeals/version.rb +3 -0
- data/spec/client_spec.rb +179 -0
- data/spec/fixtures/menu.pdf +8380 -1
- data/spec/fixtures/menu.txt +285 -0
- data/spec/ingredient_spec.rb +51 -0
- data/spec/spec_helper.rb +17 -0
- metadata +68 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c883efc225e72b90fe4943bcce321f9933664452
|
4
|
+
data.tar.gz: f7b246806d4fc330a5bf42235871ec8ae4615e48
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4f3596e65d12aeb0d1a58362eb83b408aa83fa05210b4b53b81fd63ecf921eebf1f39818edf17481bbb3f28cc0c1e39995888ad82cc68c2cbafc88e70586033f
|
7
|
+
data.tar.gz: 27e5874c713d6de1662e74a9d56cb4d54385eb794ee5369925db7f81e6e447fc9d5986c02153f8fb26c8ee8ba509a03a2b604608b69eb4ac5e2634e8aba1ed5f
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.0.0
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Matt Moriarity
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
[![Build Status](https://travis-ci.org/mjm/emeals.png?branch=master)](https://travis-ci.org/mjm/emeals)
|
2
|
+
|
3
|
+
# Emeals
|
4
|
+
|
5
|
+
A library for reading menus from [eMeals][].
|
6
|
+
|
7
|
+
[emeals]: http://emeals.com
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'emeals'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install emeals
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Contributing
|
28
|
+
|
29
|
+
1. Fork it
|
30
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
31
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
32
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
33
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/emeals.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'emeals/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "emeals"
|
8
|
+
gem.version = Emeals::VERSION
|
9
|
+
gem.authors = ["Matt Moriarity"]
|
10
|
+
gem.email = ["matt@mattmoriarity.com"]
|
11
|
+
gem.description = %q{A client for interpreting eMeals menus.}
|
12
|
+
gem.summary = %q{eMeals Client}
|
13
|
+
gem.homepage = ""
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
end
|
data/lib/emeals.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'emeals/menu'
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'tempfile'
|
5
|
+
|
6
|
+
class Emeals::Client
|
7
|
+
def parse(filename_or_file)
|
8
|
+
temp_file = copy_to_temp_file(filename_or_file)
|
9
|
+
text = pdf_to_text(temp_file.path)
|
10
|
+
|
11
|
+
Emeals::Menu.parse(text)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def copy_to_temp_file(filename_or_file)
|
17
|
+
Tempfile.open(['menu', '.pdf']) do |temp|
|
18
|
+
temp.binmode
|
19
|
+
temp.write(filename_or_file.is_a?(String) ? File.read(filename_or_file) : filename_or_file.read)
|
20
|
+
temp
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def pdf_to_text(filename)
|
25
|
+
system(pdf_to_text_path, '-raw', '-enc', 'UTF-8', filename)
|
26
|
+
File.read(filename.sub(/\.pdf$/, '.txt'))
|
27
|
+
end
|
28
|
+
|
29
|
+
def pdf_to_text_path
|
30
|
+
path = `which pdftotext`.chop
|
31
|
+
return '/opt/boxen/homebrew/bin/pdftotext' if path.empty?
|
32
|
+
path
|
33
|
+
end
|
34
|
+
end
|
data/lib/emeals/dish.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class Emeals::Dish
|
4
|
+
attr_accessor :name, :ingredients, :instructions
|
5
|
+
|
6
|
+
def initialize(name)
|
7
|
+
@name = name
|
8
|
+
@ingredients = []
|
9
|
+
@instructions = []
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Emeals::Quantity
|
14
|
+
UNITS = %w(teaspoon tablespoon cup oz lb bag clove).map(&:to_sym)
|
15
|
+
UNITS_WITH_PLURALS = UNITS + UNITS.map {|u| "#{u}s".to_sym }
|
16
|
+
|
17
|
+
attr_reader :amount, :unit
|
18
|
+
|
19
|
+
def initialize(amount, unit = nil)
|
20
|
+
@amount = to_amount(amount)
|
21
|
+
@unit = unit && unit.to_sym
|
22
|
+
end
|
23
|
+
|
24
|
+
def ==(other)
|
25
|
+
other.amount == @amount && other.unit == @unit
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def to_amount(str)
|
31
|
+
case str
|
32
|
+
when "\xC2\xBC"; '1/4'
|
33
|
+
when "\xC2\xBD"; '1/2'
|
34
|
+
else str
|
35
|
+
end.to_r
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class Emeals::Ingredient
|
40
|
+
attr_accessor :quantity, :description
|
41
|
+
|
42
|
+
def initialize(amount, unit, description)
|
43
|
+
@quantity = Emeals::Quantity.new(amount, unit)
|
44
|
+
@description = description
|
45
|
+
end
|
46
|
+
|
47
|
+
PARSE_REGEX = /((?:\d|\xC2\xBC|\xC2\xBD)+) (?:(#{Emeals::Quantity::UNITS_WITH_PLURALS.join("|")}) )?(.+)/
|
48
|
+
|
49
|
+
def self.parse(line)
|
50
|
+
if line =~ PARSE_REGEX
|
51
|
+
amount, unit, description = $1, $2, $3
|
52
|
+
new(amount, unit && unit.sub(/s$/, ''), description)
|
53
|
+
else
|
54
|
+
raise "tried to parse improperly formatted ingredient: #{line.inspect}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def ==(other)
|
59
|
+
other.quantity == @quantity && other.description == @description
|
60
|
+
end
|
61
|
+
end
|
data/lib/emeals/meal.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
# encoding:utf-8
|
2
|
+
|
3
|
+
require 'emeals/dish'
|
4
|
+
|
5
|
+
class Emeals::Meal
|
6
|
+
attr_reader :entree, :side, :flags, :times
|
7
|
+
|
8
|
+
def initialize(entree = nil, side = nil)
|
9
|
+
@entree = entree
|
10
|
+
@side = side
|
11
|
+
@flags = []
|
12
|
+
@times = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse!(meal_text)
|
16
|
+
parse_state = :header
|
17
|
+
names = []
|
18
|
+
entree_instructions = []
|
19
|
+
side_instructions = []
|
20
|
+
meal_text.split("\n").each do |line|
|
21
|
+
case parse_state
|
22
|
+
when :header
|
23
|
+
parse_flags(line)
|
24
|
+
parse_state = :names
|
25
|
+
when :names
|
26
|
+
if line =~ /Prep Cook Total/
|
27
|
+
entree_name, side_name = separate_entree_and_side_names(names)
|
28
|
+
@entree = Emeals::Dish.new(entree_name)
|
29
|
+
@side = Emeals::Dish.new(side_name)
|
30
|
+
parse_state = :times
|
31
|
+
else
|
32
|
+
names << line
|
33
|
+
end
|
34
|
+
when :times
|
35
|
+
parse_times(line)
|
36
|
+
parse_state = :entree_ingredients
|
37
|
+
when :entree_ingredients
|
38
|
+
if line.include? "-------"
|
39
|
+
parse_state = :side_ingredients
|
40
|
+
else
|
41
|
+
add_ingredients_to_dish(line, @entree)
|
42
|
+
end
|
43
|
+
when :side_ingredients
|
44
|
+
if line =~ /^[A-Z]/
|
45
|
+
entree_instructions << line
|
46
|
+
parse_state = :entree_instructions
|
47
|
+
else
|
48
|
+
add_ingredients_to_dish(line, @side)
|
49
|
+
end
|
50
|
+
when :entree_instructions
|
51
|
+
if line.include? "-------"
|
52
|
+
add_instructions_to_dish(entree_instructions, @entree)
|
53
|
+
parse_state = :side_instructions
|
54
|
+
else
|
55
|
+
entree_instructions << line
|
56
|
+
end
|
57
|
+
when :side_instructions
|
58
|
+
if line =~ /^Copyright/
|
59
|
+
side_instructions = side_instructions[0..-3]
|
60
|
+
break
|
61
|
+
else
|
62
|
+
side_instructions << line
|
63
|
+
end
|
64
|
+
else
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
add_instructions_to_dish(side_instructions, @side)
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
73
|
+
FLAGS = {
|
74
|
+
"Slow Cooker" => :slow_cooker,
|
75
|
+
"On the Grill" => :on_the_grill,
|
76
|
+
"Super Fast" => :super_fast,
|
77
|
+
"Marinate Ahead" => :marinate_ahead
|
78
|
+
}
|
79
|
+
|
80
|
+
%w(slow_cooker on_the_grill super_fast marinate_ahead).each do |flag|
|
81
|
+
define_method "#{flag}?" do
|
82
|
+
@flags.include? flag.to_sym
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def separate_entree_and_side_names(names)
|
89
|
+
case names.size
|
90
|
+
when 2
|
91
|
+
names
|
92
|
+
when 3
|
93
|
+
if names[1].length < names[0].length
|
94
|
+
[join_names(names[0..1]), names[2]]
|
95
|
+
else
|
96
|
+
[names[0], join_names(names[1..2])]
|
97
|
+
end
|
98
|
+
else
|
99
|
+
[join_names(names[0..1]), join_names(names[2..-1])]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def join_names(names)
|
104
|
+
names.join(" ").gsub('- ', '-')
|
105
|
+
end
|
106
|
+
|
107
|
+
def parse_flags(line)
|
108
|
+
FLAGS.each do |flag, sym|
|
109
|
+
@flags << sym if line.include? flag
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def parse_times(line)
|
114
|
+
times = line.split(" ")
|
115
|
+
@times[:prep] = times.first
|
116
|
+
@times[:cook] = times[1]
|
117
|
+
@times[:total] = times[2..-1].join(" ")
|
118
|
+
end
|
119
|
+
|
120
|
+
INGREDIENT_REGEX = /(?:\d|\xC2\xBC|\xC2\xBD)+ .+?(?=, (?:\d|\xC2\xBC|\xC2\xBD)+|$)/
|
121
|
+
|
122
|
+
def add_ingredients_to_dish(line, dish)
|
123
|
+
if line =~ /^\d|\xC2\xBC|\xC2\xBD/
|
124
|
+
line.scan(INGREDIENT_REGEX).each do |match|
|
125
|
+
dish.ingredients << Emeals::Ingredient.parse(match)
|
126
|
+
end
|
127
|
+
else
|
128
|
+
dish.ingredients.last.description << " #{line}"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def add_instructions_to_dish(lines, dish)
|
133
|
+
dish.instructions = lines.join(" ").split(/\. ?/)
|
134
|
+
end
|
135
|
+
end
|
data/lib/emeals/menu.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'emeals/meal'
|
2
|
+
|
3
|
+
class Emeals::Menu
|
4
|
+
attr_reader :count, :meals
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@count = 0
|
8
|
+
@meals = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse!(menu_text)
|
12
|
+
buffer = []
|
13
|
+
add_to_buffer = false
|
14
|
+
menu_text.split("\n").each do |line|
|
15
|
+
if line =~ /Meal (\d+)/
|
16
|
+
unless buffer.empty? and !add_to_buffer
|
17
|
+
@count = @count + 1
|
18
|
+
@meals << Emeals::Meal.new.parse!(buffer.join("\n"))
|
19
|
+
end
|
20
|
+
|
21
|
+
add_to_buffer = @count < $1.to_i
|
22
|
+
buffer = add_to_buffer ? [line] : []
|
23
|
+
next unless add_to_buffer
|
24
|
+
else
|
25
|
+
buffer << line if add_to_buffer
|
26
|
+
end
|
27
|
+
end
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.parse(menu_text)
|
32
|
+
new.parse!(menu_text)
|
33
|
+
end
|
34
|
+
end
|
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'emeals'
|
3
|
+
|
4
|
+
describe Emeals::Client do
|
5
|
+
subject(:client) { Emeals::Client.new }
|
6
|
+
let(:menu_path) { File.join(File.dirname(__FILE__), 'fixtures', 'menu.pdf') }
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
@menu = client.parse(menu_path)
|
10
|
+
@meals = @menu.meals
|
11
|
+
end
|
12
|
+
|
13
|
+
context "when given a File handle instead of a filename" do
|
14
|
+
it "completes successfully" do
|
15
|
+
File.open(menu_path) do |file|
|
16
|
+
expect(client.parse(file).count).to eq 7
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "counts the number of meals in the menu" do
|
22
|
+
expect(@menu.count).to eq 7
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "entree names" do
|
26
|
+
it "reads the names of entrees when the side wraps to two lines" do
|
27
|
+
expect(@meals[5].entree.name).to eq "Baked Cod Provencal"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "reads the names of entrees which wrap to two lines" do
|
31
|
+
expect(@meals.first.entree.name).to eq "Spicy Sausage and Egg Scramble"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "reads the names of entrees when both the side and entree wrap to two lines" do
|
35
|
+
expect(@meals.last.entree.name).to eq "Peppery Grilled Ribeye Steaks"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "side names" do
|
40
|
+
it "reads the names of sides that are a single line" do
|
41
|
+
expect(@meals.first.side.name).to eq "Oregano Roasted Zucchini"
|
42
|
+
end
|
43
|
+
|
44
|
+
it "reads the names of sides that wrap to two lines" do
|
45
|
+
expect(@meals[5].side.name).to eq "Roasted Asparagus with Sun-Dried Tomatoes"
|
46
|
+
end
|
47
|
+
|
48
|
+
it "reads the names of sides when both the side and entree wrap to two lines" do
|
49
|
+
expect(@meals.last.side.name).to eq "Heirloom Tomato and Spinach Salad"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "flags" do
|
54
|
+
it "reads a meal with no flags correctly" do
|
55
|
+
expect(@meals.first.flags).to be_empty
|
56
|
+
end
|
57
|
+
|
58
|
+
it "reads the slow cooker flag correctly" do
|
59
|
+
expect(@meals[1].flags).to eq [:slow_cooker]
|
60
|
+
expect(@meals[1]).to be_slow_cooker
|
61
|
+
end
|
62
|
+
|
63
|
+
it "reads the on the grill flag correctly" do
|
64
|
+
expect(@meals[3].flags).to eq [:on_the_grill]
|
65
|
+
expect(@meals[3]).to be_on_the_grill
|
66
|
+
end
|
67
|
+
|
68
|
+
it "reads the super fast flag correctly" do
|
69
|
+
expect(@meals[5].flags).to eq [:super_fast]
|
70
|
+
expect(@meals[5]).to be_super_fast
|
71
|
+
end
|
72
|
+
|
73
|
+
it "reads the marinate ahead flag correctly" do
|
74
|
+
expect(@meals[6].flags).to eq [:marinate_ahead]
|
75
|
+
expect(@meals[6]).to be_marinate_ahead
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "times" do
|
80
|
+
it "reads prep times correctly" do
|
81
|
+
expect(@meals.first.times[:prep]).to eq "10m"
|
82
|
+
expect(@meals[5].times[:prep]).to eq "15m"
|
83
|
+
end
|
84
|
+
|
85
|
+
it "reads cook times correctly" do
|
86
|
+
expect(@meals.first.times[:cook]).to eq "20m"
|
87
|
+
expect(@meals[1].times[:cook]).to eq "4h"
|
88
|
+
end
|
89
|
+
|
90
|
+
it "reads total times correctly" do
|
91
|
+
expect(@meals.first.times[:total]).to eq "30m"
|
92
|
+
expect(@meals[1].times[:total]).to eq "4h 10m"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "entree ingredients" do
|
97
|
+
include Emeals
|
98
|
+
|
99
|
+
let(:dish) { @meals.first.entree }
|
100
|
+
|
101
|
+
it "reads the correct number of ingredients" do
|
102
|
+
expect(dish.ingredients.size).to be 5
|
103
|
+
end
|
104
|
+
|
105
|
+
it "reads the correct descriptions of ingredients" do
|
106
|
+
expect(dish.ingredients[1].description).to eq "small onion, minced"
|
107
|
+
expect(dish.ingredients[3].description).to eq "kosher salt"
|
108
|
+
expect(dish.ingredients[4].description).to eq "pepper"
|
109
|
+
end
|
110
|
+
|
111
|
+
it "reads the correct quantities of ingredients" do
|
112
|
+
expect(dish.ingredients[0].quantity).to eq Emeals::Quantity.new('1/4', 'lb')
|
113
|
+
expect(dish.ingredients[1].quantity).to eq Emeals::Quantity.new('1/2')
|
114
|
+
expect(dish.ingredients[2].quantity).to eq Emeals::Quantity.new('4')
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "side ingredients" do
|
119
|
+
include Emeals
|
120
|
+
|
121
|
+
let(:dish) { @meals[3].side }
|
122
|
+
|
123
|
+
it "reads the correct number of ingredients" do
|
124
|
+
expect(dish.ingredients.size).to be 5
|
125
|
+
end
|
126
|
+
|
127
|
+
it "reads the correct descriptions of ingredients" do
|
128
|
+
expect(dish.ingredients[0].description).to eq "(5-oz) bag baby spinach"
|
129
|
+
expect(dish.ingredients[1].description).to eq "drained and chopped roasted red bell peppers"
|
130
|
+
expect(dish.ingredients[2].description).to eq "pitted kalamata olives, cut in half"
|
131
|
+
end
|
132
|
+
|
133
|
+
it "reads the correct quantities of ingredients" do
|
134
|
+
expect(dish.ingredients[0].quantity).to eq Emeals::Quantity.new('1/2')
|
135
|
+
expect(dish.ingredients[3].quantity).to eq Emeals::Quantity.new('2')
|
136
|
+
expect(dish.ingredients[4].quantity).to eq Emeals::Quantity.new('1/4', 'cup')
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe "entree instructions" do
|
141
|
+
let(:dish) { @meals[2].entree }
|
142
|
+
|
143
|
+
it "reads the correct number of instructions" do
|
144
|
+
expect(dish.instructions.size).to be 7
|
145
|
+
end
|
146
|
+
|
147
|
+
it "reads the correct text of the instructions" do
|
148
|
+
expect(dish.instructions[0]).to eq "Preheat oven to 425 degrees"
|
149
|
+
expect(dish.instructions[4]).to eq "Dip fish in egg mixture; dredge in almond flour"
|
150
|
+
expect(dish.instructions[6]).to eq "Bake 8 minutes or until fish flakes with a fork"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe "side instructions" do
|
155
|
+
let(:dish) { @meals[2].side }
|
156
|
+
|
157
|
+
it "reads the correct number of instructions" do
|
158
|
+
expect(dish.instructions.size).to be 7
|
159
|
+
end
|
160
|
+
|
161
|
+
it "reads the correct text of the instructions" do
|
162
|
+
expect(dish.instructions[0]).to eq "Preheat oven to 425 degrees"
|
163
|
+
expect(dish.instructions[1]).to eq "Toss zucchini, 1 tablespoon oil, salt and pepper on a large baking sheet; spread into a single layer"
|
164
|
+
expect(dish.instructions[6]).to eq "Bake 20 minutes or until center is set"
|
165
|
+
end
|
166
|
+
|
167
|
+
context "when the meal is the last on the page" do
|
168
|
+
let(:dish) { @meals[3].side }
|
169
|
+
|
170
|
+
it "reads the correct number of instructions" do
|
171
|
+
expect(dish.instructions.size).to be 1
|
172
|
+
end
|
173
|
+
|
174
|
+
it "reads the correct instruction text" do
|
175
|
+
expect(dish.instructions.first).to eq "Combine spinach, roasted bell peppers, olives, pepperoncini peppers and vinaigrette in a large bowl; toss well to coat"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|