emeals 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/lib/emeals/dish.rb +6 -6
- data/lib/emeals/meal.rb +107 -85
- data/lib/emeals/menu.rb +27 -15
- data/lib/emeals/version.rb +1 -1
- data/spec/client_spec.rb +1 -76
- data/spec/fixtures/meal.erb +31 -0
- data/spec/meal_parser_spec.rb +103 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/templates.rb +29 -0
- metadata +9 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 88f64929d0e17e3a429aef954e2508bf354afb6c
         | 
| 4 | 
            +
              data.tar.gz: 7811beff315cd7d5b8a06720f1b696611f4a1658
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: ba0a4c7c3ea79ba9a535569d33b97ac40429341d4fa219f908e02a35dd068c8852469486d0537e87e2845f521abf33a14b15e0127da7a0dd75849bea44083e1f
         | 
| 7 | 
            +
              data.tar.gz: 9056e857a31afc51ad2ac0429a26c6f70a3ed51566c7d0097b2dc560c36c3426632a4a0054546d63f949b7e2ac090223d3e3557cd691c9fbebac3729eae1f547
         | 
    
        data/.ruby-version
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            2.0.0
         | 
| 1 | 
            +
            2.0.0-p0
         | 
    
        data/lib/emeals/dish.rb
    CHANGED
    
    | @@ -1,12 +1,12 @@ | |
| 1 1 | 
             
            # encoding: utf-8
         | 
| 2 2 |  | 
| 3 3 | 
             
            class Emeals::Dish
         | 
| 4 | 
            -
               | 
| 4 | 
            +
              attr_reader :name, :ingredients, :instructions
         | 
| 5 5 |  | 
| 6 | 
            -
              def initialize(name)
         | 
| 6 | 
            +
              def initialize(name, ingredients = [], instructions = [])
         | 
| 7 7 | 
             
                @name = name
         | 
| 8 | 
            -
                @ingredients =  | 
| 9 | 
            -
                @instructions =  | 
| 8 | 
            +
                @ingredients = ingredients
         | 
| 9 | 
            +
                @instructions = instructions
         | 
| 10 10 | 
             
              end
         | 
| 11 11 | 
             
            end
         | 
| 12 12 |  | 
| @@ -37,7 +37,7 @@ class Emeals::Quantity | |
| 37 37 | 
             
            end
         | 
| 38 38 |  | 
| 39 39 | 
             
            class Emeals::Ingredient
         | 
| 40 | 
            -
               | 
| 40 | 
            +
              attr_reader :quantity, :description
         | 
| 41 41 |  | 
| 42 42 | 
             
              def initialize(amount, unit, description)
         | 
| 43 43 | 
             
                @quantity = Emeals::Quantity.new(amount, unit)
         | 
| @@ -58,4 +58,4 @@ class Emeals::Ingredient | |
| 58 58 | 
             
              def ==(other)
         | 
| 59 59 | 
             
                other.quantity == @quantity && other.description == @description
         | 
| 60 60 | 
             
              end
         | 
| 61 | 
            -
            end
         | 
| 61 | 
            +
            end
         | 
    
        data/lib/emeals/meal.rb
    CHANGED
    
    | @@ -5,98 +5,81 @@ require 'emeals/dish' | |
| 5 5 | 
             
            class Emeals::Meal
         | 
| 6 6 | 
             
              attr_reader :entree, :side, :flags, :times
         | 
| 7 7 |  | 
| 8 | 
            -
              def initialize(entree = nil, side = nil)
         | 
| 8 | 
            +
              def initialize(entree = nil, side = nil, flags = [], times = {})
         | 
| 9 9 | 
             
                @entree = entree
         | 
| 10 10 | 
             
                @side = side
         | 
| 11 | 
            -
                @flags =  | 
| 12 | 
            -
                @times =  | 
| 11 | 
            +
                @flags = flags
         | 
| 12 | 
            +
                @times = times
         | 
| 13 13 | 
             
              end
         | 
| 14 14 |  | 
| 15 | 
            -
              def parse | 
| 16 | 
            -
                 | 
| 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
         | 
| 15 | 
            +
              def self.parse(meal_text)
         | 
| 16 | 
            +
                Emeals::MealParser.new(meal_text).parse
         | 
| 71 17 | 
             
              end
         | 
| 72 18 |  | 
| 73 19 | 
             
              FLAGS = {
         | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 76 | 
            -
             | 
| 77 | 
            -
             | 
| 20 | 
            +
                "Slow Cooker"    => :slow_cooker,
         | 
| 21 | 
            +
                "On the Grill"   => :on_the_grill,
         | 
| 22 | 
            +
                "Super Fast"     => :super_fast,
         | 
| 23 | 
            +
                "Marinate Ahead" => :marinate_ahead
         | 
| 78 24 | 
             
              }
         | 
| 79 25 |  | 
| 80 | 
            -
               | 
| 26 | 
            +
              FLAGS.values.each do |flag|
         | 
| 81 27 | 
             
                define_method "#{flag}?" do
         | 
| 82 | 
            -
                  @flags.include? flag | 
| 28 | 
            +
                  @flags.include? flag
         | 
| 83 29 | 
             
                end
         | 
| 84 30 | 
             
              end
         | 
| 31 | 
            +
            end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            class Emeals::MealParser
         | 
| 34 | 
            +
              def initialize(meal_text)
         | 
| 35 | 
            +
                @meal_text = meal_text
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              def parse
         | 
| 39 | 
            +
                entree_name = side_name = flags = times = nil
         | 
| 40 | 
            +
                names = entree_ingredients = side_ingredients = []
         | 
| 41 | 
            +
                parse_state = :header
         | 
| 42 | 
            +
                entree_instructions = []
         | 
| 43 | 
            +
                side_instructions = []
         | 
| 44 | 
            +
                @meal_text.split("\n").each do |line|
         | 
| 45 | 
            +
                  case parse_state
         | 
| 46 | 
            +
                  when :header
         | 
| 47 | 
            +
                    flags, parse_state = parse_flags(line)
         | 
| 48 | 
            +
                  when :names
         | 
| 49 | 
            +
                    entree_name, side_name, names, parse_state = parse_names(line, names)
         | 
| 50 | 
            +
                  when :times
         | 
| 51 | 
            +
                    times, parse_state = parse_times(line)
         | 
| 52 | 
            +
                  when :entree_ingredients
         | 
| 53 | 
            +
                    entree_ingredients, parse_state = parse_entree_ingredients(line, entree_ingredients)
         | 
| 54 | 
            +
                  when :side_ingredients
         | 
| 55 | 
            +
                    side_ingredients, entree_instructions, parse_state = parse_side_ingredients(line, side_ingredients)
         | 
| 56 | 
            +
                  when :entree_instructions
         | 
| 57 | 
            +
                    entree_instructions, parse_state = parse_entree_instructions(line, entree_instructions)
         | 
| 58 | 
            +
                  when :side_instructions
         | 
| 59 | 
            +
                    side_instructions, parse_state = parse_side_instructions(line, side_instructions)
         | 
| 60 | 
            +
                  else
         | 
| 61 | 
            +
                    break
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
                entree = Emeals::Dish.new(entree_name, entree_ingredients, format_instructions(entree_instructions))
         | 
| 65 | 
            +
                side   = Emeals::Dish.new(side_name,   side_ingredients,   format_instructions(side_instructions))
         | 
| 66 | 
            +
                Emeals::Meal.new(entree, side, flags, times)
         | 
| 67 | 
            +
              end
         | 
| 85 68 |  | 
| 86 69 | 
             
              private
         | 
| 87 70 |  | 
| 88 71 | 
             
              def separate_entree_and_side_names(names)
         | 
| 89 72 | 
             
                case names.size
         | 
| 90 | 
            -
             | 
| 91 | 
            -
             | 
| 92 | 
            -
             | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 95 | 
            -
                    else
         | 
| 96 | 
            -
                      [names[0], join_names(names[1..2])]
         | 
| 97 | 
            -
                    end
         | 
| 73 | 
            +
                when 2
         | 
| 74 | 
            +
                  names
         | 
| 75 | 
            +
                when 3
         | 
| 76 | 
            +
                  if names[1].length < names[0].length
         | 
| 77 | 
            +
                    [join_names(names[0..1]), names[2]]
         | 
| 98 78 | 
             
                  else
         | 
| 99 | 
            -
                    [ | 
| 79 | 
            +
                    [names[0], join_names(names[1..2])]
         | 
| 80 | 
            +
                  end
         | 
| 81 | 
            +
                else
         | 
| 82 | 
            +
                  [join_names(names[0..1]), join_names(names[2..-1])]
         | 
| 100 83 | 
             
                end
         | 
| 101 84 | 
             
              end
         | 
| 102 85 |  | 
| @@ -105,31 +88,70 @@ class Emeals::Meal | |
| 105 88 | 
             
              end
         | 
| 106 89 |  | 
| 107 90 | 
             
              def parse_flags(line)
         | 
| 108 | 
            -
                FLAGS. | 
| 109 | 
            -
             | 
| 91 | 
            +
                [Emeals::Meal::FLAGS.select {|flag, sym| line.include? flag }.values, :names]
         | 
| 92 | 
            +
              end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
              def parse_names(line, names)
         | 
| 95 | 
            +
                if line =~ /Prep Cook Total/
         | 
| 96 | 
            +
                  entree_name, side_name = separate_entree_and_side_names(names)
         | 
| 97 | 
            +
                  [entree_name, side_name, nil, :times]
         | 
| 98 | 
            +
                else
         | 
| 99 | 
            +
                  [nil, nil, names + [line], :names]
         | 
| 110 100 | 
             
                end
         | 
| 111 101 | 
             
              end
         | 
| 112 102 |  | 
| 113 103 | 
             
              def parse_times(line)
         | 
| 114 104 | 
             
                times = line.split(" ")
         | 
| 115 | 
            -
                 | 
| 116 | 
            -
             | 
| 117 | 
            -
             | 
| 105 | 
            +
                [{prep: times.first, cook: times[1], total: times[2..-1].join(" ")}, :entree_ingredients]
         | 
| 106 | 
            +
              end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
              def parse_entree_ingredients(line, ingredients)
         | 
| 109 | 
            +
                if line.include? "-------"
         | 
| 110 | 
            +
                  [ingredients, :side_ingredients]
         | 
| 111 | 
            +
                else
         | 
| 112 | 
            +
                  [find_ingredients(ingredients, line), :entree_ingredients]
         | 
| 113 | 
            +
                end
         | 
| 114 | 
            +
              end
         | 
| 115 | 
            +
             | 
| 116 | 
            +
              def parse_side_ingredients(line, ingredients)
         | 
| 117 | 
            +
                if line =~ /^[A-Z]/
         | 
| 118 | 
            +
                  [ingredients, [line], :entree_instructions]
         | 
| 119 | 
            +
                else
         | 
| 120 | 
            +
                  [find_ingredients(ingredients, line), nil, :side_ingredients]
         | 
| 121 | 
            +
                end
         | 
| 122 | 
            +
              end
         | 
| 123 | 
            +
             | 
| 124 | 
            +
              def parse_entree_instructions(line, instructions)
         | 
| 125 | 
            +
                if line.include? "-------"
         | 
| 126 | 
            +
                  [instructions, :side_instructions]
         | 
| 127 | 
            +
                else
         | 
| 128 | 
            +
                  [instructions + [line], :entree_instructions]
         | 
| 129 | 
            +
                end
         | 
| 130 | 
            +
              end
         | 
| 131 | 
            +
             | 
| 132 | 
            +
              def parse_side_instructions(line, instructions)
         | 
| 133 | 
            +
                if line =~ /^Copyright/
         | 
| 134 | 
            +
                  [instructions[0..-3], nil]
         | 
| 135 | 
            +
                else
         | 
| 136 | 
            +
                  [instructions + [line], :side_instructions]
         | 
| 137 | 
            +
                end
         | 
| 118 138 | 
             
              end
         | 
| 119 139 |  | 
| 120 140 | 
             
              INGREDIENT_REGEX = /(?:\d|\xC2\xBC|\xC2\xBD)+ .+?(?=, (?:\d|\xC2\xBC|\xC2\xBD)+|$)/
         | 
| 121 141 |  | 
| 122 | 
            -
              def  | 
| 142 | 
            +
              def find_ingredients(ingredients, line)
         | 
| 123 143 | 
             
                if line =~ /^\d|\xC2\xBC|\xC2\xBD/
         | 
| 124 | 
            -
                  line.scan(INGREDIENT_REGEX). | 
| 125 | 
            -
                     | 
| 144 | 
            +
                  ingredients + line.scan(INGREDIENT_REGEX).map do |match|
         | 
| 145 | 
            +
                    Emeals::Ingredient.parse(match)
         | 
| 126 146 | 
             
                  end
         | 
| 127 147 | 
             
                else
         | 
| 128 | 
            -
                   | 
| 148 | 
            +
                  # TODO we shouldn't be modifying this in-place
         | 
| 149 | 
            +
                  ingredients.last.description << " #{line}"
         | 
| 150 | 
            +
                  ingredients
         | 
| 129 151 | 
             
                end
         | 
| 130 152 | 
             
              end
         | 
| 131 153 |  | 
| 132 | 
            -
              def  | 
| 133 | 
            -
                 | 
| 154 | 
            +
              def format_instructions(instructions)
         | 
| 155 | 
            +
                instructions.join(" ").split(/\. ?/)
         | 
| 134 156 | 
             
              end
         | 
| 135 157 | 
             
            end
         | 
    
        data/lib/emeals/menu.rb
    CHANGED
    
    | @@ -1,34 +1,46 @@ | |
| 1 1 | 
             
            require 'emeals/meal'
         | 
| 2 2 |  | 
| 3 3 | 
             
            class Emeals::Menu
         | 
| 4 | 
            -
              attr_reader : | 
| 4 | 
            +
              attr_reader :meals
         | 
| 5 5 |  | 
| 6 | 
            -
              def initialize
         | 
| 7 | 
            -
                @ | 
| 8 | 
            -
                @meals = []
         | 
| 6 | 
            +
              def initialize(meals)
         | 
| 7 | 
            +
                @meals = meals
         | 
| 9 8 | 
             
              end
         | 
| 10 9 |  | 
| 11 | 
            -
              def  | 
| 10 | 
            +
              def count
         | 
| 11 | 
            +
                @meals.size
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              def self.parse(menu_text)
         | 
| 15 | 
            +
                Emeals::MenuParser.new(menu_text).parse
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            class Emeals::MenuParser
         | 
| 20 | 
            +
              def initialize(menu_text)
         | 
| 21 | 
            +
                @menu_text = menu_text
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              def parse
         | 
| 12 25 | 
             
                buffer = []
         | 
| 26 | 
            +
                meals  = []
         | 
| 13 27 | 
             
                add_to_buffer = false
         | 
| 14 | 
            -
             | 
| 28 | 
            +
             | 
| 29 | 
            +
                @menu_text.split("\n").each do |line|
         | 
| 15 30 | 
             
                  if line =~ /Meal (\d+)/
         | 
| 16 | 
            -
                     | 
| 17 | 
            -
                       | 
| 18 | 
            -
                      @meals << Emeals::Meal.new.parse!(buffer.join("\n"))
         | 
| 31 | 
            +
                    if add_to_buffer and !buffer.empty?
         | 
| 32 | 
            +
                      meals << Emeals::Meal.parse(buffer.join("\n"))
         | 
| 19 33 | 
             
                    end
         | 
| 20 34 |  | 
| 21 | 
            -
                    add_to_buffer =  | 
| 35 | 
            +
                    add_to_buffer = meals.size < $1.to_i
         | 
| 22 36 | 
             
                    buffer = add_to_buffer ? [line] : []
         | 
| 23 37 | 
             
                    next unless add_to_buffer
         | 
| 24 38 | 
             
                  else
         | 
| 25 39 | 
             
                    buffer << line if add_to_buffer
         | 
| 26 40 | 
             
                  end
         | 
| 27 41 | 
             
                end
         | 
| 28 | 
            -
                self
         | 
| 29 | 
            -
              end
         | 
| 30 42 |  | 
| 31 | 
            -
             | 
| 32 | 
            -
                new.parse!(menu_text)
         | 
| 43 | 
            +
                Emeals::Menu.new(meals)
         | 
| 33 44 | 
             
              end
         | 
| 34 | 
            -
            end
         | 
| 45 | 
            +
            end
         | 
| 46 | 
            +
             | 
    
        data/lib/emeals/version.rb
    CHANGED
    
    
    
        data/spec/client_spec.rb
    CHANGED
    
    | @@ -22,80 +22,7 @@ describe Emeals::Client do | |
| 22 22 | 
             
                expect(@menu.count).to eq 7
         | 
| 23 23 | 
             
              end
         | 
| 24 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 25 | 
             
              describe "entree ingredients" do
         | 
| 97 | 
            -
                include Emeals
         | 
| 98 | 
            -
             | 
| 99 26 | 
             
                let(:dish) { @meals.first.entree }
         | 
| 100 27 |  | 
| 101 28 | 
             
                it "reads the correct number of ingredients" do
         | 
| @@ -116,8 +43,6 @@ describe Emeals::Client do | |
| 116 43 | 
             
              end
         | 
| 117 44 |  | 
| 118 45 | 
             
              describe "side ingredients" do
         | 
| 119 | 
            -
                include Emeals
         | 
| 120 | 
            -
             | 
| 121 46 | 
             
                let(:dish) { @meals[3].side }
         | 
| 122 47 |  | 
| 123 48 | 
             
                it "reads the correct number of ingredients" do
         | 
| @@ -176,4 +101,4 @@ describe Emeals::Client do | |
| 176 101 | 
             
                  end
         | 
| 177 102 | 
             
                end
         | 
| 178 103 | 
             
              end
         | 
| 179 | 
            -
            end
         | 
| 104 | 
            +
            end
         | 
| @@ -0,0 +1,31 @@ | |
| 1 | 
            +
            Meal 1 <%= @flags %>
         | 
| 2 | 
            +
            <%= @entree %>
         | 
| 3 | 
            +
            <%= @side %>
         | 
| 4 | 
            +
            Prep Cook Total
         | 
| 5 | 
            +
            <%= [@prep_time, @cook_time, @total_time].join(" ") %>
         | 
| 6 | 
            +
            ¼ lb ground pork sausage
         | 
| 7 | 
            +
            ½ small onion, minced
         | 
| 8 | 
            +
            <%= "#{@entree_ingredients}\n" unless @entree_ingredients == "" -%>
         | 
| 9 | 
            +
            4 large eggs, lightly beaten
         | 
| 10 | 
            +
            ¼ teaspoon kosher salt, ¼ teaspoon pepper
         | 
| 11 | 
            +
            ---------------------------------------------------------------
         | 
| 12 | 
            +
            1 lb fresh zucchini, trimmed and thinly sliced
         | 
| 13 | 
            +
            1 tablespoon chopped fresh oregano
         | 
| 14 | 
            +
            <%= "#{@side_ingredients}\n" unless @side_ingredients == "" -%>
         | 
| 15 | 
            +
            1 tablespoon olive oil
         | 
| 16 | 
            +
            ¼ teaspoon kosher salt, ¼ teaspoon pepper
         | 
| 17 | 
            +
            Heat a nonstick skillet over medium-high heat.
         | 
| 18 | 
            +
            Add sausage to pan; cook 6 minutes or until
         | 
| 19 | 
            +
            done. Drain on a paper towel-lined plate,
         | 
| 20 | 
            +
            reserving 1 tablespoon drippings in pan. <%= "#{@entree_instructions} " unless @entree_instructions == "" %>Add
         | 
| 21 | 
            +
            onion to pan over medium heat. Cook 3
         | 
| 22 | 
            +
            minutes or until lightly browned. Add eggs; cook
         | 
| 23 | 
            +
            2 minutes, stirring constantly. Stir in sausage,
         | 
| 24 | 
            +
            salt and pepper; cook until eggs are thickened
         | 
| 25 | 
            +
            and set. Note: Remaining pork sausage can be
         | 
| 26 | 
            +
            frozen for up to 2 months.
         | 
| 27 | 
            +
            ---------------------------------------------------------------
         | 
| 28 | 
            +
            Preheat oven to 425 degrees. Toss zucchini,
         | 
| 29 | 
            +
            oregano, oil, salt and pepper in a large roasting
         | 
| 30 | 
            +
            pan. <%= "#{@side_instructions} " unless @side_instructions == "" %>Bake 20 minutes or until just tender.
         | 
| 31 | 
            +
             | 
| @@ -0,0 +1,103 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'emeals/meal'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            describe Emeals::MealParser do
         | 
| 6 | 
            +
              describe "entree names" do
         | 
| 7 | 
            +
                let(:entree1) { make_meal(entree: 'Baked Cod Provencal').entree.name }
         | 
| 8 | 
            +
                let(:entree2) { make_meal(entree: 'Baked Cod Provencal',
         | 
| 9 | 
            +
                                          side:   "A Side That Wraps Onto\nTwo Lines").entree.name }
         | 
| 10 | 
            +
                let(:entree3) { make_meal.entree.name }
         | 
| 11 | 
            +
                let(:entree4) { make_meal(side: "A Side That Wraps Onto\nTwo Lines").entree.name }
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                it "reads the names of entrees when entree and side are single-line" do
         | 
| 14 | 
            +
                  expect(entree1).to eq "Baked Cod Provencal"
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                it "reads the names of entrees when the side wraps to two lines" do
         | 
| 18 | 
            +
                  expect(entree2).to eq "Baked Cod Provencal"
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                it "reads the names of entrees which wrap to two lines" do
         | 
| 22 | 
            +
                  expect(entree3).to eq "Spicy Sausage and Egg Scramble"
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                it "reads the names of entrees when both the side and entree wrap to two lines" do
         | 
| 26 | 
            +
                  expect(entree4).to eq "Spicy Sausage and Egg Scramble"
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              describe "side names" do
         | 
| 31 | 
            +
                let(:side1) { make_meal(entree: 'Baked Cod Provencal').side.name }
         | 
| 32 | 
            +
                let(:side2) { make_meal.side.name }
         | 
| 33 | 
            +
                let(:side3) { make_meal(entree: 'Baked Cod Provencal',
         | 
| 34 | 
            +
                                          side:   "A Side That Wraps Onto\nTwo Lines").side.name }
         | 
| 35 | 
            +
                let(:side4) { make_meal(side: "A Side That Wraps Onto\nTwo Lines").side.name }
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                it "reads the names of sides when entree and side are single-line" do
         | 
| 38 | 
            +
                  expect(side1).to eq "Oregano Roasted Zucchini"
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                it "reads the names of sides when the side wraps to two lines" do
         | 
| 42 | 
            +
                  expect(side2).to eq "Oregano Roasted Zucchini"
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                it "reads the names of sides which wrap to two lines" do
         | 
| 46 | 
            +
                  expect(side3).to eq "A Side That Wraps Onto Two Lines"
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                it "reads the names of sides when both the side and entree wrap to two lines" do
         | 
| 50 | 
            +
                  expect(side4).to eq "A Side That Wraps Onto Two Lines"
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              describe "flags" do
         | 
| 55 | 
            +
                let(:slow_cooker)    { make_meal flags: "Slow Cooker" }
         | 
| 56 | 
            +
                let(:on_the_grill)   { make_meal flags: "On the Grill" }
         | 
| 57 | 
            +
                let(:super_fast)     { make_meal flags: "Super Fast" }
         | 
| 58 | 
            +
                let(:marinate_ahead) { make_meal flags: "Marinate Ahead" }
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                it "reads the slow cooker flag correctly" do
         | 
| 61 | 
            +
                  expect(slow_cooker.flags).to eq [:slow_cooker]
         | 
| 62 | 
            +
                  expect(slow_cooker).to be_slow_cooker
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                it "reads the on the grill flag correctly" do
         | 
| 66 | 
            +
                  expect(on_the_grill.flags).to eq [:on_the_grill]
         | 
| 67 | 
            +
                  expect(on_the_grill).to be_on_the_grill
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                it "reads the super fast flag correctly" do
         | 
| 71 | 
            +
                  expect(super_fast.flags).to eq [:super_fast]
         | 
| 72 | 
            +
                  expect(super_fast).to be_super_fast
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                it "reads the marinate ahead flag correctly" do
         | 
| 76 | 
            +
                  expect(marinate_ahead.flags).to eq [:marinate_ahead]
         | 
| 77 | 
            +
                  expect(marinate_ahead).to be_marinate_ahead
         | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                it "reads a meal with no flags correctly" do
         | 
| 81 | 
            +
                  expect(make_meal.flags).to eq []
         | 
| 82 | 
            +
                  expect(make_meal).to_not be_slow_cooker
         | 
| 83 | 
            +
                end
         | 
| 84 | 
            +
              end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
              describe "times" do
         | 
| 87 | 
            +
                it "reads prep times correctly" do
         | 
| 88 | 
            +
                  expect(make_meal.times[:prep]).to eq "10m"
         | 
| 89 | 
            +
                  expect(make_meal(prep_time: "15m").times[:prep]).to eq "15m"
         | 
| 90 | 
            +
                end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                it "reads cook times correctly" do
         | 
| 93 | 
            +
                  expect(make_meal.times[:cook]).to eq "20m"
         | 
| 94 | 
            +
                  expect(make_meal(cook_time: "4h").times[:cook]).to eq "4h"
         | 
| 95 | 
            +
                end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                it "reads total times correctly" do
         | 
| 98 | 
            +
                  expect(make_meal.times[:total]).to eq "30m"
         | 
| 99 | 
            +
                  expect(make_meal(total_time: "4h 10m").times[:total]).to eq "4h 10m"
         | 
| 100 | 
            +
                end
         | 
| 101 | 
            +
              end
         | 
| 102 | 
            +
            end
         | 
| 103 | 
            +
             | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    | @@ -4,6 +4,9 @@ | |
| 4 4 | 
             
            # loaded once.
         | 
| 5 5 | 
             
            #
         | 
| 6 6 | 
             
            # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            Dir[File.join(File.dirname(__FILE__), "support/**/*.rb")].each {|f| require f}
         | 
| 9 | 
            +
             | 
| 7 10 | 
             
            RSpec.configure do |config|
         | 
| 8 11 | 
             
              config.treat_symbols_as_metadata_keys_with_true_values = true
         | 
| 9 12 | 
             
              config.run_all_when_everything_filtered = true
         | 
| @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            require 'emeals'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            TEMPLATE_DIR = File.join(File.dirname(__FILE__), '..', 'fixtures')
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            DEFAULT_MEAL_OPTIONS = {
         | 
| 6 | 
            +
              entree: "Spicy Sausage and Egg\nScramble",
         | 
| 7 | 
            +
              side: "Oregano Roasted Zucchini",
         | 
| 8 | 
            +
              flags: "",
         | 
| 9 | 
            +
              prep_time: '10m',
         | 
| 10 | 
            +
              cook_time: '20m',
         | 
| 11 | 
            +
              total_time: '30m',
         | 
| 12 | 
            +
              entree_ingredients: "",
         | 
| 13 | 
            +
              side_ingredients: "",
         | 
| 14 | 
            +
              entree_instructions: "",
         | 
| 15 | 
            +
              side_instructions: "",
         | 
| 16 | 
            +
              before: "",
         | 
| 17 | 
            +
              after: ""
         | 
| 18 | 
            +
            }
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            def make_meal(options = {})
         | 
| 21 | 
            +
              options = DEFAULT_MEAL_OPTIONS.merge(options)
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              ctx = Object.new
         | 
| 24 | 
            +
              def ctx.evaluate(options)
         | 
| 25 | 
            +
                options.each {|k,v| instance_variable_set("@#{k}", v) }
         | 
| 26 | 
            +
                ERB.new(File.read(File.join(TEMPLATE_DIR, 'meal.erb')), nil, '-').result(binding)
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
              Emeals::MealParser.new(ctx.evaluate(options)).parse
         | 
| 29 | 
            +
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: emeals
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0 | 
| 4 | 
            +
              version: 0.1.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Matt Moriarity
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2013-07- | 
| 11 | 
            +
            date: 2013-07-21 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies: []
         | 
| 13 13 | 
             
            description: A client for interpreting eMeals menus.
         | 
| 14 14 | 
             
            email:
         | 
| @@ -33,10 +33,13 @@ files: | |
| 33 33 | 
             
            - lib/emeals/menu.rb
         | 
| 34 34 | 
             
            - lib/emeals/version.rb
         | 
| 35 35 | 
             
            - spec/client_spec.rb
         | 
| 36 | 
            +
            - spec/fixtures/meal.erb
         | 
| 36 37 | 
             
            - spec/fixtures/menu.pdf
         | 
| 37 38 | 
             
            - spec/fixtures/menu.txt
         | 
| 38 39 | 
             
            - spec/ingredient_spec.rb
         | 
| 40 | 
            +
            - spec/meal_parser_spec.rb
         | 
| 39 41 | 
             
            - spec/spec_helper.rb
         | 
| 42 | 
            +
            - spec/support/templates.rb
         | 
| 40 43 | 
             
            homepage: ''
         | 
| 41 44 | 
             
            licenses: []
         | 
| 42 45 | 
             
            metadata: {}
         | 
| @@ -56,13 +59,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 56 59 | 
             
                  version: '0'
         | 
| 57 60 | 
             
            requirements: []
         | 
| 58 61 | 
             
            rubyforge_project: 
         | 
| 59 | 
            -
            rubygems_version: 2.0. | 
| 62 | 
            +
            rubygems_version: 2.0.0
         | 
| 60 63 | 
             
            signing_key: 
         | 
| 61 64 | 
             
            specification_version: 4
         | 
| 62 65 | 
             
            summary: eMeals Client
         | 
| 63 66 | 
             
            test_files:
         | 
| 64 67 | 
             
            - spec/client_spec.rb
         | 
| 68 | 
            +
            - spec/fixtures/meal.erb
         | 
| 65 69 | 
             
            - spec/fixtures/menu.pdf
         | 
| 66 70 | 
             
            - spec/fixtures/menu.txt
         | 
| 67 71 | 
             
            - spec/ingredient_spec.rb
         | 
| 72 | 
            +
            - spec/meal_parser_spec.rb
         | 
| 68 73 | 
             
            - spec/spec_helper.rb
         | 
| 74 | 
            +
            - spec/support/templates.rb
         |