meal_planner 1.0.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.
- data/LICENSE +19 -0
- data/README +21 -0
- data/bin/mealplan +95 -0
- data/bin/meals.csv +8 -0
- data/lib/meal_planner/array.rb +12 -0
- data/lib/meal_planner/meal.rb +34 -0
- data/lib/meal_planner/menu.rb +72 -0
- data/lib/meal_planner/menu_day.rb +36 -0
- data/lib/meal_planner/recipe.rb +20 -0
- data/lib/meal_planner/regex_test.rb +16 -0
- data/lib/meal_planner/validator.rb +13 -0
- data/spec/meal_planner/array_spec.rb +27 -0
- data/spec/meal_planner/meal_spec.rb +52 -0
- data/spec/meal_planner/menu_day_spec.rb +57 -0
- data/spec/meal_planner/menu_spec.rb +112 -0
- data/spec/meal_planner/regex_test_spec.rb +16 -0
- metadata +137 -0
data/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2013 Peter Sumsion
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
|
11
|
+
all copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
+
THE SOFTWARE.
|
data/README
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
A program to ease and automate the planning of meals.
|
|
2
|
+
|
|
3
|
+
Each meal has a main dish and optionally side dishes as well. These are currently loaded from the meals.csv file in the directory of the command line script. That will be changed in a future release when they will be loaded from a database instead.
|
|
4
|
+
|
|
5
|
+
A menu consists of any number of days that the user chooses. Each day can have any meal as user wishes. When the program is run, the meals are loaded at random from the meal source and presented to the user. The user then has the option to switch out any that she doesn't want on a particular day. If two meals are given, the two meals are switched between each other. If only one meal is given, that meal is switched with another from the meal source that isn't already in the menu.
|
|
6
|
+
|
|
7
|
+
When the user quits the program, the current menu is stored in a menu.txt file so that it can be printed and used in shopping, preparing meals, etc.
|
|
8
|
+
|
|
9
|
+
In a future release, each dish in a meal will be associated with a recipe so that a shopping list and recipe book can be created directly from the same source.
|
|
10
|
+
|
|
11
|
+
Known Issues:
|
|
12
|
+
|
|
13
|
+
Switching Lunches with themselves or with other meals doesn't work well. This may need a redesign of how switch is called.
|
|
14
|
+
|
|
15
|
+
If too many meals are replaced, the meal store eventually gets emptied and so meals are replaced with blanks
|
|
16
|
+
|
|
17
|
+
FIXED: If more than 4 meals are planned at a time, the regular expression gathering meal numbers is no longer valid
|
|
18
|
+
This was fixed by updating the regular expression so that it accepts any numbers as long as they are comma separated.
|
|
19
|
+
|
|
20
|
+
FIXED: For now, this makes it possible for invalid numbers to be entered. This is not acceptable and must be changed as it could result in loss of the entire list of planned meals because of a simple user error.
|
|
21
|
+
This was fixed by checking the gathered values to see if they are in the range covered by the planned_meals array indexes
|
data/bin/mealplan
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'date'
|
|
4
|
+
require_relative '../lib/meal_planner/validator'
|
|
5
|
+
require_relative '../lib/meal_planner/meal'
|
|
6
|
+
require_relative '../lib/meal_planner/menu_day'
|
|
7
|
+
require_relative '../lib/meal_planner/menu'
|
|
8
|
+
|
|
9
|
+
meals = []
|
|
10
|
+
|
|
11
|
+
default_meals_file = File.join(File.dirname(__FILE__), 'meals.csv')
|
|
12
|
+
|
|
13
|
+
File.open(default_meals_file, "r") do |file|
|
|
14
|
+
file.readlines.each { |line| meals << MealPlanner::Meal.new(line) }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
loop do
|
|
18
|
+
puts "\nWelcome to Meal Planner"
|
|
19
|
+
|
|
20
|
+
puts "\nPlease enter the number of days to plan for"
|
|
21
|
+
number_of_days = MealPlanner::Validator.validate(/^\d+$/) do
|
|
22
|
+
puts "example: 7"
|
|
23
|
+
gets.chomp
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
#puts "\nPlease enter the date to start menu or Enter if today"
|
|
27
|
+
#start_date = MealPlanner::Validator.validate(/^(0{,1}[1-9]|1[0-2])\/(0{,1}[1-9]|[12][0-9]|3[01])\/\d{4}$/) do
|
|
28
|
+
#puts "example: 2/13/2013 for Feb. 13, 2013"
|
|
29
|
+
#gets.chomp
|
|
30
|
+
#end
|
|
31
|
+
|
|
32
|
+
puts "\nPlanning for #{number_of_days} days." #starting on #{start_date}."
|
|
33
|
+
|
|
34
|
+
menu = MealPlanner::Menu.new(Integer(number_of_days))
|
|
35
|
+
menu.plan(meals)
|
|
36
|
+
|
|
37
|
+
menu.each_menu_day do |menu_day|
|
|
38
|
+
puts menu_day
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
loop do
|
|
42
|
+
|
|
43
|
+
planned_meals = []
|
|
44
|
+
menu.each_planned_meal do |meal|
|
|
45
|
+
planned_meals << meal
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
puts "\nPlease enter 'quit' to exit or hit Enter key to continue"
|
|
49
|
+
command = gets.chomp
|
|
50
|
+
|
|
51
|
+
if command == 'quit'
|
|
52
|
+
File.open("menu.txt", "w") do |file|
|
|
53
|
+
menu.each_menu_day { |menu_day| file << menu_day }
|
|
54
|
+
end
|
|
55
|
+
break
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
puts "\nPlease choose a meal or two to switch:\n"
|
|
59
|
+
planned_meals.each_with_index do |meal, i|
|
|
60
|
+
puts "#{i} #{meal}"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
validated = false
|
|
64
|
+
|
|
65
|
+
until validated do
|
|
66
|
+
|
|
67
|
+
meal_numbers_string = MealPlanner::Validator.validate(/^([0-9])([0-9]{1,})?(,([0-9])([0-9]{1,})?)?$/) do
|
|
68
|
+
puts "Example: 5\nExample: 2,4"
|
|
69
|
+
gets.chomp
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
meal_numbers = []
|
|
73
|
+
|
|
74
|
+
meal_numbers_string.split(",").each do |meal_number_string|
|
|
75
|
+
if (0..planned_meals.size).to_a.include? meal_number_string.to_i
|
|
76
|
+
meal_numbers << Integer(meal_number_string)
|
|
77
|
+
validated = true
|
|
78
|
+
else
|
|
79
|
+
validated = false
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
if meal_numbers.size == 1
|
|
85
|
+
meal1, meal2 = planned_meals[meal_numbers[0]], nil
|
|
86
|
+
else
|
|
87
|
+
meal1, meal2 = planned_meals[meal_numbers[0]], planned_meals[meal_numbers[1]]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
menu.switch(meal1, meal2)
|
|
91
|
+
|
|
92
|
+
menu.each_menu_day { |menu_day| puts menu_day }
|
|
93
|
+
end
|
|
94
|
+
break
|
|
95
|
+
end
|
data/bin/meals.csv
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module MealPlanner
|
|
2
|
+
class Meal
|
|
3
|
+
attr_reader :main_dish
|
|
4
|
+
|
|
5
|
+
def initialize(main_dish)
|
|
6
|
+
@main_dish = main_dish
|
|
7
|
+
@sides = []
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def add_side(side)
|
|
11
|
+
@sides << side
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def each_side
|
|
15
|
+
if block_given?
|
|
16
|
+
@sides.each do |side|
|
|
17
|
+
yield side
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def to_s
|
|
23
|
+
string = "Main Dish: #{@main_dish}"
|
|
24
|
+
each_side do |side|
|
|
25
|
+
string += ", Side: #{side}"
|
|
26
|
+
end
|
|
27
|
+
string
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def ==(other)
|
|
31
|
+
@main_dish == other.main_dish
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
require 'date'
|
|
2
|
+
require_relative 'array'
|
|
3
|
+
require_relative 'menu_day'
|
|
4
|
+
|
|
5
|
+
module MealPlanner
|
|
6
|
+
class Menu
|
|
7
|
+
|
|
8
|
+
attr_reader :days, :unplanned_meals
|
|
9
|
+
|
|
10
|
+
def initialize(number_of_days)
|
|
11
|
+
@number_of_days = number_of_days
|
|
12
|
+
@start_date = Time.new.to_date
|
|
13
|
+
@unplanned_meals = []
|
|
14
|
+
@menu_days = []
|
|
15
|
+
|
|
16
|
+
0.upto(@number_of_days - 1) do |i|
|
|
17
|
+
@menu_days << MenuDay.new(@start_date + i)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def each_menu_day
|
|
22
|
+
if block_given?
|
|
23
|
+
@menu_days.each { |menu_day| yield menu_day }
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def each_planned_meal
|
|
28
|
+
if block_given?
|
|
29
|
+
|
|
30
|
+
each_menu_day do |menu_day|
|
|
31
|
+
menu_day.each_meal do |time, meal|
|
|
32
|
+
unless meal.nil?
|
|
33
|
+
yield meal
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def add_unplanned_meal(meal)
|
|
41
|
+
@unplanned_meals << meal
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def plan(meals)
|
|
45
|
+
@unplanned_meals = meals
|
|
46
|
+
|
|
47
|
+
each_menu_day do |menu_day|
|
|
48
|
+
menu_day.add_meal(:lunch, Meal.new("Leftovers from yesterday"))
|
|
49
|
+
menu_day.add_meal(:dinner, @unplanned_meals.sample!)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def switch(switch_meal1, switch_meal2=nil)
|
|
54
|
+
menu_days = []
|
|
55
|
+
each_menu_day do |menu_day|
|
|
56
|
+
menu_day.each_meal do |time, meal|
|
|
57
|
+
if meal == switch_meal1 || (! switch_meal2.nil? && meal == switch_meal2)
|
|
58
|
+
menu_days << [menu_day, time, meal]
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
if switch_meal2.nil?
|
|
64
|
+
menu_days[0][0].switch_meal(menu_days[0][1], @unplanned_meals.sample!)
|
|
65
|
+
elsif menu_days.size == 2
|
|
66
|
+
menu_days[0][0].switch_meal(menu_days[1][1], menu_days[1][2])
|
|
67
|
+
menu_days[1][0].switch_meal(menu_days[0][1], menu_days[0][2])
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require_relative 'meal'
|
|
2
|
+
|
|
3
|
+
module MealPlanner
|
|
4
|
+
class MenuDay
|
|
5
|
+
attr_reader :date
|
|
6
|
+
|
|
7
|
+
def initialize(date)
|
|
8
|
+
@date = date
|
|
9
|
+
@meals = {}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def add_meal(time, meal)
|
|
13
|
+
@meals[time] = meal
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def switch_meal(time, meal)
|
|
17
|
+
add_meal(time, meal)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def each_meal
|
|
21
|
+
if block_given?
|
|
22
|
+
@meals.each do |time, meal|
|
|
23
|
+
yield time, meal
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def to_s
|
|
29
|
+
menu_day_string = "\nPlan for #{@date}"
|
|
30
|
+
each_meal do |time, meal|
|
|
31
|
+
menu_day_string += "\n\t#{time.capitalize} is: #{meal}"
|
|
32
|
+
end
|
|
33
|
+
menu_day_string
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module MealPlanner
|
|
2
|
+
Ingredient = Struct.new(:amount, :measure, :description)
|
|
3
|
+
|
|
4
|
+
class Recipe
|
|
5
|
+
attr_reader :name
|
|
6
|
+
def initialize(name)
|
|
7
|
+
@name = name
|
|
8
|
+
@ingredients = []
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def add_ingredient(ingredient)
|
|
12
|
+
@ingredients << ingredient
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
if __FILE__ == $0
|
|
17
|
+
ingredient = Ingredient.new(2, "T.", "Chili Powder")
|
|
18
|
+
puts ingredient
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'meal_planner/array.rb'
|
|
2
|
+
|
|
3
|
+
module MealPlanner
|
|
4
|
+
describe Array do
|
|
5
|
+
|
|
6
|
+
before do
|
|
7
|
+
@original = %w(why would I do that)
|
|
8
|
+
@original_size = @original.size
|
|
9
|
+
@sample_size = 2
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "samples from an array and removes the sample from original" do
|
|
13
|
+
@sample = @original.sample!(@sample_size)
|
|
14
|
+
@sample.size.should == @sample_size
|
|
15
|
+
@original.size.should == @original_size - @sample_size
|
|
16
|
+
@original.should_not include(@sample)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "samples only one from the array" do
|
|
20
|
+
sample = @original.sample!
|
|
21
|
+
|
|
22
|
+
@original.should_not include(sample)
|
|
23
|
+
sample.should be_an_instance_of String
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'meal_planner/meal'
|
|
2
|
+
|
|
3
|
+
module MealPlanner
|
|
4
|
+
describe Meal do
|
|
5
|
+
before do
|
|
6
|
+
@main_dish = "Rice and Meat Sauce"
|
|
7
|
+
@meal = Meal.new(@main_dish)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "has a main dish" do
|
|
11
|
+
@meal.main_dish.should == @main_dish
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "has a string representation" do
|
|
15
|
+
@meal.to_s.should == "Main Dish: #{@main_dish}"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "compares to others by main dish" do
|
|
19
|
+
@meal.should == Meal.new(@main_dish)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
context "suggested sides have been added" do
|
|
23
|
+
before do
|
|
24
|
+
@main_dish = "Hashed Browns"
|
|
25
|
+
@meal = Meal.new(@main_dish)
|
|
26
|
+
|
|
27
|
+
@side1 = "Bacon"
|
|
28
|
+
@side2 = "Salsa"
|
|
29
|
+
@meal.add_side(@side1)
|
|
30
|
+
@meal.add_side(@side2)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "returns each side" do
|
|
34
|
+
|
|
35
|
+
expected_sides = [@side1, @side2]
|
|
36
|
+
sides = []
|
|
37
|
+
|
|
38
|
+
@meal.each_side do |side|
|
|
39
|
+
sides << side
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
sides.should == expected_sides
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "lists sides in string representation" do
|
|
46
|
+
@meal.to_s.should ==
|
|
47
|
+
"Main Dish: #{@main_dish}, Side: #{@side1}, Side: #{@side2}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'meal_planner/menu_day'
|
|
2
|
+
|
|
3
|
+
module MealPlanner
|
|
4
|
+
describe MenuDay do
|
|
5
|
+
|
|
6
|
+
before do
|
|
7
|
+
@date = Date.new(2013, 10, 21)
|
|
8
|
+
@lunch = Meal.new("Sandwiches")
|
|
9
|
+
@dinner = Meal.new("Spaghetti")
|
|
10
|
+
|
|
11
|
+
@meals = { :lunch => @lunch, :dinner => @dinner }
|
|
12
|
+
|
|
13
|
+
@lunch2 = Meal.new("Leftovers")
|
|
14
|
+
@dinner2 = Meal.new("Chicken and Rice")
|
|
15
|
+
|
|
16
|
+
@meals2 = { :lunch => @lunch2, :dinner => @dinner2 }
|
|
17
|
+
|
|
18
|
+
@menu_day = MenuDay.new(@date)
|
|
19
|
+
|
|
20
|
+
@menu_day.add_meal(:lunch, @lunch)
|
|
21
|
+
@menu_day.add_meal(:dinner, @dinner)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "has a date" do
|
|
25
|
+
@menu_day.date.should == @date
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "has a string representation" do
|
|
29
|
+
@menu_day.to_s.should == "\nPlan for #{@date}\n\tLunch is: #{@lunch}\n\tDinner is: #{@dinner}"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "has a hash of meals" do
|
|
33
|
+
|
|
34
|
+
expected_meals = {}
|
|
35
|
+
|
|
36
|
+
@menu_day.each_meal do |time, meal|
|
|
37
|
+
expected_meals[time] = meal
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
expected_meals.should == @meals
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "substitutes meals with new meals" do
|
|
44
|
+
@menu_day.switch_meal(:lunch, @lunch2)
|
|
45
|
+
@menu_day.switch_meal(:dinner, @dinner2)
|
|
46
|
+
|
|
47
|
+
expected_meals = {}
|
|
48
|
+
|
|
49
|
+
@menu_day.each_meal do |time, meal|
|
|
50
|
+
expected_meals[time] = meal
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
expected_meals.should == @meals2
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
require 'meal_planner/menu.rb'
|
|
2
|
+
require 'timecop'
|
|
3
|
+
require 'date'
|
|
4
|
+
|
|
5
|
+
module MealPlanner
|
|
6
|
+
describe Menu do
|
|
7
|
+
before do
|
|
8
|
+
Timecop.freeze(Date.new(2013, 7, 24))
|
|
9
|
+
@number_of_days = 2
|
|
10
|
+
@menu = Menu.new(@number_of_days)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "returns each menu day" do
|
|
14
|
+
test_dates = [Date.new(2013, 7, 24), Date.new(2013, 7, 25)]
|
|
15
|
+
expected_dates = []
|
|
16
|
+
|
|
17
|
+
@menu.each_menu_day do |menu_day|
|
|
18
|
+
expected_dates << menu_day.date
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
expected_dates.should == test_dates
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "returns each planned meal" do
|
|
25
|
+
expected_meals = []
|
|
26
|
+
|
|
27
|
+
@menu.each_planned_meal do |planned_meal|
|
|
28
|
+
expected_meals << planned_meal
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
expected_meals.should == []
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "has a list of unplanned meals" do
|
|
35
|
+
@menu.unplanned_meals.should == []
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "adds an unplanned meal" do
|
|
39
|
+
meal = Meal.new("Coconut Currie Soup")
|
|
40
|
+
@menu.add_unplanned_meal(meal)
|
|
41
|
+
@menu.unplanned_meals.should == [meal]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context "meals have been planned" do
|
|
45
|
+
|
|
46
|
+
before do
|
|
47
|
+
Timecop.freeze(Date.new(2013, 7, 24))
|
|
48
|
+
@number_of_days = 2
|
|
49
|
+
@menu = Menu.new(@number_of_days)
|
|
50
|
+
|
|
51
|
+
@meals = [
|
|
52
|
+
Meal.new("Chicken and Rice"),
|
|
53
|
+
Meal.new("Sausage and Saurkraut"),
|
|
54
|
+
Meal.new("Steak, potatoes, and gravy"),
|
|
55
|
+
Meal.new("Hot tortilla sandwiches"),
|
|
56
|
+
Meal.new("Chicken Soup"),
|
|
57
|
+
Meal.new("Leftover Roast Soup")
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
@menu.plan(@meals)
|
|
61
|
+
|
|
62
|
+
@planned_meals = []
|
|
63
|
+
@menu.each_planned_meal do |meal|
|
|
64
|
+
meal.should_not be_nil
|
|
65
|
+
@planned_meals << meal
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "has planned meals" do
|
|
71
|
+
|
|
72
|
+
@planned_meals.length.should == @number_of_days * 2
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "switches the places of two planned meals" do
|
|
77
|
+
|
|
78
|
+
switch_meal1 = @planned_meals[1]
|
|
79
|
+
switch_meal2 = @planned_meals[3]
|
|
80
|
+
|
|
81
|
+
@menu.switch(switch_meal1, switch_meal2)
|
|
82
|
+
|
|
83
|
+
@planned_meals = []
|
|
84
|
+
@menu.each_planned_meal do |meal|
|
|
85
|
+
@planned_meals << meal
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
@planned_meals[1].should == switch_meal2
|
|
89
|
+
@planned_meals[3].should == switch_meal1
|
|
90
|
+
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "switches a meal with another not yet on the menu" do
|
|
94
|
+
|
|
95
|
+
switch_meal = @planned_meals[1]
|
|
96
|
+
|
|
97
|
+
@menu.switch(switch_meal)
|
|
98
|
+
|
|
99
|
+
@planned_meals = []
|
|
100
|
+
@menu.each_planned_meal do |meal|
|
|
101
|
+
@planned_meals << meal
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
@planned_meals.size.should == 4
|
|
105
|
+
@planned_meals.should_not include(switch_meal)
|
|
106
|
+
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'meal_planner/regex_test.rb'
|
|
2
|
+
|
|
3
|
+
module MealPlanner
|
|
4
|
+
describe RegexTest do
|
|
5
|
+
|
|
6
|
+
it "should match" do
|
|
7
|
+
RegexTest.test(/[1-9]/, ('1'..'9').to_a).should be_true
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "shouldn't match" do
|
|
11
|
+
RegexTest.test(/test/, ('a'..'z').to_a).should be_false
|
|
12
|
+
RegexTest.test(/[1-9]/, (1..9).to_a).should be_false
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
end
|
|
16
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: meal_planner
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Peter Sumsion
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2013-12-21 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: activesupport
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - '='
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: 4.0.0
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - '='
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: 4.0.0
|
|
30
|
+
- !ruby/object:Gem::Dependency
|
|
31
|
+
name: rspec
|
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
|
33
|
+
none: false
|
|
34
|
+
requirements:
|
|
35
|
+
- - ! '>='
|
|
36
|
+
- !ruby/object:Gem::Version
|
|
37
|
+
version: '0'
|
|
38
|
+
type: :development
|
|
39
|
+
prerelease: false
|
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
+
none: false
|
|
42
|
+
requirements:
|
|
43
|
+
- - ! '>='
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '0'
|
|
46
|
+
- !ruby/object:Gem::Dependency
|
|
47
|
+
name: timecop
|
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
|
49
|
+
none: false
|
|
50
|
+
requirements:
|
|
51
|
+
- - ! '>='
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: 0.6.3
|
|
54
|
+
type: :development
|
|
55
|
+
prerelease: false
|
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
+
none: false
|
|
58
|
+
requirements:
|
|
59
|
+
- - ! '>='
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: 0.6.3
|
|
62
|
+
description: ! "A program to ease and automate the planning of meals.\n\nEach meal
|
|
63
|
+
has a main dish and optionally side dishes as well. These are currently loaded from
|
|
64
|
+
the meals.csv file in the directory of the command line script. That will be changed
|
|
65
|
+
in a future release when they will be loaded from a database instead.\n\nA menu
|
|
66
|
+
consists of any number of days that the user chooses. Each day can have any meal
|
|
67
|
+
as user wishes. When the program is run, the meals are loaded at random from the
|
|
68
|
+
meal source and presented to the user. The user then has the option to switch out
|
|
69
|
+
any that she doesn't want on a particular day. If two meals are given, the two meals
|
|
70
|
+
are switched between each other. If only one meal is given, that meal is switched
|
|
71
|
+
with another from the meal source that isn't already in the menu.\n\nWhen the user
|
|
72
|
+
quits the program, the current menu is stored in a menu.txt file so that it can
|
|
73
|
+
be printed and used in shopping, preparing meals, etc.\n\nIn a future release, each
|
|
74
|
+
dish in a meal will be associated with a recipe so that a shopping list and recipe
|
|
75
|
+
book can be created directly from the same source.\n\nKnown Issues:\n\nSwitching
|
|
76
|
+
Lunches with themselves or with other meals doesn't work well. This may need a redesign
|
|
77
|
+
of how switch is called.\n\nIf too many meals are replaced, the meal store eventually
|
|
78
|
+
gets emptied and so meals are replaced with blanks\n\nFIXED: If more than 4 meals
|
|
79
|
+
are planned at a time, the regular expression gathering meal numbers is no longer
|
|
80
|
+
valid\n This was fixed by updating the regular expression so that it accepts any
|
|
81
|
+
numbers as long as they are comma separated.\n\nFIXED: For now, this makes it possible
|
|
82
|
+
for invalid numbers to be entered. This is not acceptable and must be changed as
|
|
83
|
+
it could result in loss of the entire list of planned meals because of a simple
|
|
84
|
+
user error.\n This was fixed by checking the gathered values to see if they are
|
|
85
|
+
in the range covered by the planned_meals array indexes\n"
|
|
86
|
+
email: sumsionp@gmail.com
|
|
87
|
+
executables:
|
|
88
|
+
- mealplan
|
|
89
|
+
extensions: []
|
|
90
|
+
extra_rdoc_files: []
|
|
91
|
+
files:
|
|
92
|
+
- bin/mealplan
|
|
93
|
+
- bin/meals.csv
|
|
94
|
+
- lib/meal_planner/array.rb
|
|
95
|
+
- lib/meal_planner/meal.rb
|
|
96
|
+
- lib/meal_planner/menu.rb
|
|
97
|
+
- lib/meal_planner/menu_day.rb
|
|
98
|
+
- lib/meal_planner/recipe.rb
|
|
99
|
+
- lib/meal_planner/regex_test.rb
|
|
100
|
+
- lib/meal_planner/validator.rb
|
|
101
|
+
- spec/meal_planner/array_spec.rb
|
|
102
|
+
- spec/meal_planner/meal_spec.rb
|
|
103
|
+
- spec/meal_planner/menu_day_spec.rb
|
|
104
|
+
- spec/meal_planner/menu_spec.rb
|
|
105
|
+
- spec/meal_planner/regex_test_spec.rb
|
|
106
|
+
- LICENSE
|
|
107
|
+
- README
|
|
108
|
+
homepage: http://rubygems.org/gems/meal_planner
|
|
109
|
+
licenses: []
|
|
110
|
+
post_install_message:
|
|
111
|
+
rdoc_options: []
|
|
112
|
+
require_paths:
|
|
113
|
+
- lib
|
|
114
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
115
|
+
none: false
|
|
116
|
+
requirements:
|
|
117
|
+
- - ! '>='
|
|
118
|
+
- !ruby/object:Gem::Version
|
|
119
|
+
version: '1.9'
|
|
120
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
|
+
none: false
|
|
122
|
+
requirements:
|
|
123
|
+
- - ! '>='
|
|
124
|
+
- !ruby/object:Gem::Version
|
|
125
|
+
version: '0'
|
|
126
|
+
requirements: []
|
|
127
|
+
rubyforge_project:
|
|
128
|
+
rubygems_version: 1.8.25
|
|
129
|
+
signing_key:
|
|
130
|
+
specification_version: 3
|
|
131
|
+
summary: Command line meal planning program
|
|
132
|
+
test_files:
|
|
133
|
+
- spec/meal_planner/array_spec.rb
|
|
134
|
+
- spec/meal_planner/meal_spec.rb
|
|
135
|
+
- spec/meal_planner/menu_day_spec.rb
|
|
136
|
+
- spec/meal_planner/menu_spec.rb
|
|
137
|
+
- spec/meal_planner/regex_test_spec.rb
|