nutrition_calculator 1.0.4 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d192a9cd1ea3c900f999599597c9c6f9549e3dc7
4
- data.tar.gz: 6ea66889e0f2ea5be1f40f1bf1557220c37de9b6
3
+ metadata.gz: 6bea8053da1b46ce8fa17fcec9d5b1a26bc76aed
4
+ data.tar.gz: b267488d45929aca0494205317222a5e3337d967
5
5
  SHA512:
6
- metadata.gz: a3de99ed764a0e07b3234f75968530828fb931b93771754750a3b0195726c11ca7868ca9d8bb0eb5304d78e71413e8c2cb1f8204821b2feabfcb0322127d7548
7
- data.tar.gz: 2a9cc36e2a69593def04b9834310acea0eb916a9ee5cbdb56576cd8b14ba965e2046e4c010d1fc0af17b486a67d61e6b312caf394ac8c06fe950f053ef011bf9
6
+ metadata.gz: 790daa540bea0f2c0589ed225234d242085ca89191bccee879f66ab49b70c7ad57ccd0de69bdd796fe944be2b328e0e65d2b008924160d5e079f472236c2931b
7
+ data.tar.gz: a495afdf1964d806e1ebb928fc54ed7267046fa72fc2370140a1728dcd112298075104a6b2d99a83fe916dd0e6292f5a14b9561547c0e4b4194688e270c4a457
@@ -55,25 +55,28 @@ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
55
55
 
56
56
  require 'nutrition_calculator/calorie_budgeter'
57
57
  require 'nutrition_calculator/data_summarizer'
58
+ require 'nutrition_calculator/diet_period'
58
59
  require 'yaml'
59
60
 
60
61
  def data
61
62
  @data ||= YAML.load_file(ARGV.first)
62
63
  end
63
64
 
64
- summarizer = NutritionCalculator::DataSummarizer.new(source_data: data)
65
- cb = NutritionCalculator::CalorieBudgeter.new
65
+ diet_period = NutritionCalculator::DietPeriod.new(
66
+ start_date: data['start_date'],
67
+ length: data['period_length'],
68
+ resting_metabolic_rate: data['resting_metabolic_rate'],
69
+ weight_loss_goal_in_kg: data['weight_loss_goal_in_kg']
70
+ )
71
+
72
+ summarizer = NutritionCalculator::DataSummarizer.new(source_data: data,
73
+ diet_period: diet_period)
74
+
75
+ cb = NutritionCalculator::CalorieBudgeter.new(diet_period: diet_period,
76
+ source_data: summarizer)
66
77
 
67
78
  # require 'logger'
68
79
  # cb.logger = Logger.new(STDERR)
69
- #
70
- cb.resting_metabolic_rate = data['resting_metabolic_rate']
71
- cb.weekly_calorie_goal = data['weekly_calorie_goal']
72
-
73
- cb.current_day_of_week = summarizer.current_day
74
- cb.prior_days_calories = summarizer.prior_days_net_calories
75
- cb.calories_burned = summarizer.calories_burned_today
76
- cb.calories_consumed = summarizer.calories_consumed_today
77
80
 
78
81
  puts "You have consumed #{cb.calories_consumed} calories today."
79
82
  puts "You have burned #{cb.calories_burned} calories today."
@@ -11,7 +11,8 @@ Given(/^I have consumed (\d+) net calories on prior days this week$/) do |cals|
11
11
  end
12
12
 
13
13
  Given(/^it is the (\d+)(st|nd|rd|th) day of the week$/) do |day, _|
14
- inputs.current_day_of_week = day.to_i
14
+ day = day.to_i
15
+ inputs.num_days_to_budget = 8 - day
15
16
  end
16
17
 
17
18
  Given(/^I have consumed (\d+) calories today$/) do |cals|
@@ -16,9 +16,14 @@ module NutritionCalculator
16
16
  # cb = NutritionCalculator::CalorieBudgeter.new
17
17
  #
18
18
  # cb.resting_metabolic_rate = 2_000 # calories per day
19
- # cb.weekly_calorie_goal = 10_500 # creates an average deficit of 500 calories/day
20
- # cb.current_day_of_week = 3 # if your week starts on Monday, this would be Wednesday
21
- # cb.prior_days_calories = 3_524 # net calories from Monday and Tuesday
19
+ #
20
+ # cb.weekly_calorie_goal = 10_500 # creates an average deficit of 500
21
+ # # calories/day
22
+ #
23
+ # cb.num_days_to_budget = 5 # The number of days remaining in the
24
+ # # week, including the current day
25
+ #
26
+ # cb.prior_days_calories = 3_524 # net calories from days 1 and 2
22
27
  #
23
28
  # cb.calories_consumed = 0
24
29
  # cb.calories_burned = 0
@@ -40,6 +45,23 @@ module NutritionCalculator
40
45
  class CalorieBudgeter
41
46
  extend CachedOutputsWithRecalculation
42
47
 
48
+ def initialize(diet_period: nil, source_data: nil)
49
+ self.diet_period = diet_period if diet_period
50
+ self.source_data = source_data if source_data
51
+ end
52
+
53
+ def diet_period=(diet_period)
54
+ self.resting_metabolic_rate = diet_period.resting_metabolic_rate
55
+ self.weekly_calorie_goal = diet_period.net_calorie_goal
56
+ self.num_days_to_budget = diet_period.days_remaining
57
+ end
58
+
59
+ def source_data=(source_data)
60
+ self.prior_days_calories = source_data.prior_days_net_calories
61
+ self.calories_consumed = source_data.calories_consumed_today
62
+ self.calories_burned = source_data.calories_burned_today
63
+ end
64
+
43
65
  # @!group Inputs
44
66
 
45
67
  # @!attribute
@@ -70,16 +92,10 @@ module NutritionCalculator
70
92
  }
71
93
 
72
94
  # @!attribute
73
- # @return [Integer] The number of the day of the week
74
- # @example If you start your week on Monday
75
- # 1 - Monday
76
- # 2 - Tuesday
77
- # 3 - Wednesday
78
- # 4 - Thursday
79
- # 5 - Friday
80
- # 6 - Saturday
81
- # 7 - Sunday
82
- def_input :current_day_of_week, validate_with: ->(value) {
95
+ # @return [Integer] The number of days across which to budget the remaining
96
+ # net calorie goal for the week. This includes the current
97
+ # day.
98
+ def_input :num_days_to_budget, validate_with: ->(value) {
83
99
  (1..7).include?(value)
84
100
  }
85
101
 
@@ -152,7 +168,7 @@ module NutritionCalculator
152
168
  # @return [Integer] The number of net calories that should be consumed today
153
169
  # to meet the weekly calorie goal
154
170
  def_output :daily_calorie_goal do
155
- (remaining_calories_this_week.to_f / remaining_days_of_week).round
171
+ (remaining_calories_this_week.to_f / num_days_to_budget).round
156
172
  end
157
173
 
158
174
  # @!attribute [r]
@@ -162,12 +178,5 @@ module NutritionCalculator
162
178
  def_output :remaining_calories_this_week do
163
179
  weekly_calorie_goal - prior_days_calories
164
180
  end
165
-
166
- # @!attribute [r]
167
- # @return [Integer] The number of days remaining in the week, including the
168
- # current day
169
- def_output :remaining_days_of_week do
170
- 8 - current_day_of_week
171
- end
172
181
  end
173
182
  end
@@ -1,18 +1,15 @@
1
- require 'date'
2
-
3
1
  module NutritionCalculator
4
2
  class DataSummarizer
5
- SUNDAY = 7
6
- MONDAY = 1
7
-
8
- def initialize(source_data:, calendar: Date)
3
+ def initialize(source_data:, diet_period:)
9
4
  self.source_data = source_data
10
- self.calendar = calendar
5
+ self.diet_period = diet_period
11
6
  end
12
7
 
13
8
  def prior_days_net_calories
14
- return 0 if current_day == MONDAY
15
- values = (1...current_day).map { |day| net_calories_for_day(day) }
9
+ return 0 if current_day == 0
10
+ values = (0...current_day).map { |day|
11
+ net_calories_for_day(day)
12
+ }
16
13
  values.reduce { |weekly_net, daily_net| weekly_net + daily_net }
17
14
  end
18
15
 
@@ -24,18 +21,13 @@ module NutritionCalculator
24
21
  source_data_for_day(current_day)['calories_burned']
25
22
  end
26
23
 
27
- # TODO: this probably isn't the right place to put this, since it looks like
28
- # it does need to be exposed to the CalorieBudgeter as well. Still, this is
29
- # better than having it live in the CLI script itself for now.
24
+ private
25
+ attr_accessor :source_data, :diet_period
26
+
30
27
  def current_day
31
- day = calendar.today.wday
32
- day = SUNDAY if day < MONDAY
33
- day
28
+ diet_period.current_day
34
29
  end
35
30
 
36
- private
37
- attr_accessor :source_data, :calendar
38
-
39
31
  def net_calories_for_day(day)
40
32
  data = source_data_for_day(day)
41
33
  data['calories_consumed'] - data['calories_burned']
@@ -0,0 +1,81 @@
1
+ require 'date'
2
+ require 'nutrition_calculator/cached_outputs_with_recalculation'
3
+
4
+ module NutritionCalculator
5
+ class DietPeriod
6
+ extend CachedOutputsWithRecalculation
7
+ include Comparable
8
+
9
+ CALORIES_PER_KG = 7_500
10
+
11
+ def initialize(length:, start_date:, resting_metabolic_rate:,
12
+ weight_loss_goal_in_kg:, calendar: Date)
13
+ self.length = length
14
+ self.start_date = start_date
15
+ self.resting_metabolic_rate = resting_metabolic_rate
16
+ self.weight_loss_goal_in_kg = weight_loss_goal_in_kg
17
+ self.calendar = calendar
18
+ end
19
+
20
+ def_input :length, validate_with: ->(value) {
21
+ value.kind_of?(Integer) \
22
+ && value > 0
23
+ }
24
+
25
+ def_input :start_date, validate_with: ->(value) {
26
+ value.kind_of?(Date)
27
+ }
28
+ alias_method :to_date, :start_date
29
+
30
+ def_input :resting_metabolic_rate, validate_with: ->(value) {
31
+ value.kind_of?(Integer) \
32
+ && value > 0
33
+ }
34
+
35
+ def_input :weight_loss_goal_in_kg, validate_with: ->(value) {
36
+ value.kind_of?(Numeric)
37
+ }
38
+
39
+ def_output :current_day do
40
+ (calendar.today - current_cycle_start_date).to_i
41
+ end
42
+
43
+ def_output :days_remaining do
44
+ length - current_day
45
+ end
46
+
47
+ def_output :net_calorie_goal do
48
+ rmr_for_period - planned_calorie_deficit
49
+ end
50
+
51
+ def succ
52
+ self.clone.tap do |period|
53
+ period.start_date = start_date + length
54
+ end
55
+ end
56
+
57
+ def <=>(other)
58
+ start_date <=> other.to_date
59
+ end
60
+
61
+ private
62
+
63
+ attr_accessor :calendar
64
+
65
+ def current_cycle_start_date
66
+ current_cycle.start_date
67
+ end
68
+
69
+ def current_cycle
70
+ (self..calendar.today).to_a.last
71
+ end
72
+
73
+ def rmr_for_period
74
+ resting_metabolic_rate * length
75
+ end
76
+
77
+ def planned_calorie_deficit
78
+ (weight_loss_goal_in_kg * CALORIES_PER_KG).ceil
79
+ end
80
+ end
81
+ end
@@ -1,3 +1,3 @@
1
1
  module NutritionCalculator
2
- VERSION = "1.0.4"
2
+ VERSION = "1.2.0"
3
3
  end
@@ -23,18 +23,18 @@ describe NutritionCalculator::CalorieBudgeter do
23
23
  end
24
24
 
25
25
  describe '#daily_calorie_goal' do
26
- let(:days_left) { 8 - day }
27
26
  let(:weekly_goal) { 10_000 }
27
+ let(:days_left_in_week) { 8 - day }
28
28
 
29
29
  before(:each) do
30
- subject.current_day_of_week = day
30
+ subject.num_days_to_budget = days_left_in_week
31
31
  subject.weekly_calorie_goal = weekly_goal
32
32
  subject.prior_days_calories = weekly_consumed
33
33
  end
34
34
 
35
35
  shared_examples_for 'it calculates the daily calorie goal' do
36
36
  it 'is the number of calories remaining for the week divided by the remaining days in the week' do
37
- expected = ((weekly_goal - weekly_consumed).to_f / days_left).round
37
+ expected = ((weekly_goal - weekly_consumed).to_f / days_left_in_week).round
38
38
  expect(subject.daily_calorie_goal).to eq expected
39
39
  end
40
40
  end
@@ -50,7 +50,7 @@ describe NutritionCalculator::CalorieBudgeter do
50
50
 
51
51
  describe '#target_daily_calorie_consumption' do
52
52
  before(:each) do
53
- subject.current_day_of_week = 1
53
+ subject.num_days_to_budget = 7
54
54
  subject.prior_days_calories = 0
55
55
  subject.resting_metabolic_rate = 2_000
56
56
  end
@@ -158,7 +158,7 @@ describe NutritionCalculator::CalorieBudgeter do
158
158
  before(:each) do
159
159
  subject.resting_metabolic_rate = 2_000
160
160
  subject.weekly_calorie_goal = 14_000
161
- subject.current_day_of_week = 1
161
+ subject.num_days_to_budget = 7
162
162
  subject.prior_days_calories = 0
163
163
  subject.calories_burned = 0
164
164
  end
@@ -178,7 +178,7 @@ describe NutritionCalculator::CalorieBudgeter do
178
178
  before(:each) do
179
179
  subject.resting_metabolic_rate = 2_000
180
180
  subject.weekly_calorie_goal = 14_000
181
- subject.current_day_of_week = 1
181
+ subject.num_days_to_budget = 7
182
182
  subject.prior_days_calories = 0
183
183
  subject.calories_burned = 0
184
184
  end
@@ -196,7 +196,7 @@ describe NutritionCalculator::CalorieBudgeter do
196
196
 
197
197
  describe '#predicted_calorie_consumption' do
198
198
  before(:each) do
199
- subject.current_day_of_week = 1
199
+ subject.num_days_to_budget = 7
200
200
  subject.prior_days_calories = 0
201
201
  subject.resting_metabolic_rate = 2_000
202
202
  subject.weekly_calorie_goal = 14_000
@@ -3,42 +3,44 @@ require 'nutrition_calculator/data_summarizer'
3
3
 
4
4
  describe NutritionCalculator::DataSummarizer do
5
5
  let(:source_data) {{
6
- 1 => {
6
+ 0 => {
7
7
  'calories_consumed' => 1000,
8
8
  'calories_burned' => 500
9
9
  },
10
- 2 => {
10
+ 1 => {
11
11
  'calories_consumed' => 1001,
12
12
  'calories_burned' => 500
13
13
  },
14
- 3 => {
14
+ 2 => {
15
15
  'calories_consumed' => 1000,
16
16
  'calories_burned' => 501
17
17
  },
18
- 4 => {
18
+ 3 => {
19
19
  'calories_consumed' => 1002,
20
20
  'calories_burned' => 500
21
21
  },
22
- 5 => {
22
+ 4 => {
23
23
  'calories_consumed' => 1000,
24
24
  'calories_burned' => 502
25
25
  },
26
- 6 => {
26
+ 5 => {
27
27
  'calories_consumed' => 1003,
28
28
  'calories_burned' => 500
29
29
  },
30
- 7 => {
30
+ 6 => {
31
31
  'calories_consumed' => 1000,
32
32
  'calories_burned' => 503
33
33
  },
34
34
  }}
35
35
 
36
- let(:calendar) { double(:calendar, today: today) }
36
+ let(:diet_period) { double(:diet_period, current_day: current_day) }
37
37
 
38
- subject { described_class.new(source_data: source_data, calendar: calendar) }
38
+ subject {
39
+ described_class.new(source_data: source_data, diet_period: diet_period)
40
+ }
39
41
 
40
- context "on day 1" do
41
- let(:today) { Date.new(2015,2,16) }
42
+ context "on day 0" do
43
+ let(:current_day) { 0 }
42
44
 
43
45
  it 'reports prior_days_net_calories as 0' do
44
46
  expect(subject.prior_days_net_calories).to eq 0
@@ -51,14 +53,10 @@ describe NutritionCalculator::DataSummarizer do
51
53
  it 'reports calories consumed today' do
52
54
  expect(subject.calories_consumed_today).to eq 1000
53
55
  end
54
-
55
- it 'reports that the current day number is 1' do
56
- expect(subject.current_day).to eq 1
57
- end
58
56
  end
59
57
 
60
- context "on day 7" do
61
- let(:today) { Date.new(2015,2,22) }
58
+ context "on day 6" do
59
+ let(:current_day) { 6 }
62
60
 
63
61
  it 'reports prior_days_net_calories as the sum of calories consumed less the sum of calories burned' do
64
62
  expect(subject.prior_days_net_calories).to eq 3_003
@@ -71,9 +69,5 @@ describe NutritionCalculator::DataSummarizer do
71
69
  it 'reports calories consumed today' do
72
70
  expect(subject.calories_consumed_today).to eq 1000
73
71
  end
74
-
75
- it 'reports that the current day number is 7' do
76
- expect(subject.current_day).to eq 7
77
- end
78
72
  end
79
73
  end
@@ -0,0 +1,138 @@
1
+ require 'spec_helper'
2
+ require 'nutrition_calculator/diet_period'
3
+
4
+ describe NutritionCalculator::DietPeriod do
5
+ CALORIES_PER_KG = 7_500
6
+
7
+ subject {
8
+ described_class.new(length: period_length, start_date: start_date,
9
+ resting_metabolic_rate: rmr,
10
+ weight_loss_goal_in_kg: loss_goal,
11
+ calendar: calendar)
12
+ }
13
+
14
+ let(:calendar) { double(:calendar, today: current_date) }
15
+
16
+ let(:rmr) { 2000 }
17
+
18
+ let(:expected_net_calorie_goal) {
19
+ (rmr * period_length) - (loss_goal * CALORIES_PER_KG)
20
+ }
21
+
22
+ let(:start_date) { Date.new(2015,2,16) }
23
+ let(:current_date) { Date.new(2015,2,16) }
24
+
25
+ context 'when the period is 7 days long' do
26
+ let(:period_length) { 7 }
27
+ let(:loss_goal) { 0.5 }
28
+
29
+ it 'calculates the calorie budget for the entire period' do
30
+ expect(subject.net_calorie_goal).to eq expected_net_calorie_goal
31
+ end
32
+
33
+ context 'it is the first day of the first cycle of the period' do
34
+ let(:current_date) { Date.new(2015,2,16) }
35
+
36
+ it 'reports that today is the 0th day of the period' do
37
+ expect(subject.current_day).to eq 0
38
+ end
39
+
40
+ it 'reports that there are 7 days remaining in the period' do
41
+ expect(subject.days_remaining).to eq 7
42
+ end
43
+ end
44
+
45
+ context 'it is the last day of the first cycle of the period' do
46
+ let(:current_date) { Date.new(2015,2,22) }
47
+
48
+ it 'reports that today is the 6th day of the period' do
49
+ expect(subject.current_day).to eq 6
50
+ end
51
+
52
+ it 'reports that there is 1 day remaining in the period' do
53
+ expect(subject.days_remaining).to eq 1
54
+ end
55
+ end
56
+
57
+ context 'it is the first day of the third cycle of the period' do
58
+ let(:current_date) { Date.new(2015,3,2) }
59
+
60
+ it 'reports that today is the 0th day of the period' do
61
+ expect(subject.current_day).to eq 0
62
+ end
63
+
64
+ it 'reports that there are 7 days remaining in the period' do
65
+ expect(subject.days_remaining).to eq 7
66
+ end
67
+ end
68
+
69
+ context 'it is the last day of the first cycle of the period' do
70
+ let(:current_date) { Date.new(2015,3,8) }
71
+
72
+ it 'reports that today is the 6th day of the period' do
73
+ expect(subject.current_day).to eq 6
74
+ end
75
+
76
+ it 'reports that there is 1 day remaining in the period' do
77
+ expect(subject.days_remaining).to eq 1
78
+ end
79
+ end
80
+ end
81
+
82
+ context 'when the period is 10 days long' do
83
+ let(:period_length) { 10 }
84
+ let(:loss_goal) { 0.5 }
85
+
86
+ it 'calculates the calorie budget for the entire period' do
87
+ expect(subject.net_calorie_goal).to eq expected_net_calorie_goal
88
+ end
89
+
90
+ context 'it is the first day of the first cycle of the period' do
91
+ let(:current_date) { Date.new(2015,2,16) }
92
+
93
+ it 'reports that today is the 0th day of the period' do
94
+ expect(subject.current_day).to eq 0
95
+ end
96
+
97
+ it 'reports that there are 10 days remaining in the period' do
98
+ expect(subject.days_remaining).to eq 10
99
+ end
100
+ end
101
+
102
+ context 'it is the last day of the first cycle of the period' do
103
+ let(:current_date) { Date.new(2015,2,25) }
104
+
105
+ it 'reports that today is the 9th day of the period' do
106
+ expect(subject.current_day).to eq 9
107
+ end
108
+
109
+ it 'reports that there is 1 day remaining in the period' do
110
+ expect(subject.days_remaining).to eq 1
111
+ end
112
+ end
113
+
114
+ context 'it is the first day of the third cycle of the period' do
115
+ let(:current_date) { Date.new(2015,3,8) }
116
+
117
+ it 'reports that today is the 0th day of the period' do
118
+ expect(subject.current_day).to eq 0
119
+ end
120
+
121
+ it 'reports that there are 7 days remaining in the period' do
122
+ expect(subject.days_remaining).to eq 10
123
+ end
124
+ end
125
+
126
+ context 'it is the last day of the third cycle of the period' do
127
+ let(:current_date) { Date.new(2015,3,17) }
128
+
129
+ it 'reports that today is the 6th day of the period' do
130
+ expect(subject.current_day).to eq 9
131
+ end
132
+
133
+ it 'reports that there is 1 day remaining in the period' do
134
+ expect(subject.days_remaining).to eq 1
135
+ end
136
+ end
137
+ end
138
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nutrition_calculator
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Wilger
@@ -122,12 +122,14 @@ files:
122
122
  - lib/nutrition_calculator/cached_outputs_with_recalculation.rb
123
123
  - lib/nutrition_calculator/calorie_budgeter.rb
124
124
  - lib/nutrition_calculator/data_summarizer.rb
125
+ - lib/nutrition_calculator/diet_period.rb
125
126
  - lib/nutrition_calculator/has_logging.rb
126
127
  - lib/nutrition_calculator/version.rb
127
128
  - nutrition_calculator.gemspec
128
129
  - spec/nutrition_calculator/cached_outputs_with_recalculation_spec.rb
129
130
  - spec/nutrition_calculator/calorie_budgeter_spec.rb
130
131
  - spec/nutrition_calculator/data_summarizer_spec.rb
132
+ - spec/nutrition_calculator/diet_period_spec.rb
131
133
  - spec/nutrition_calculator_spec.rb
132
134
  - spec/spec_helper.rb
133
135
  homepage: ''
@@ -163,6 +165,7 @@ test_files:
163
165
  - spec/nutrition_calculator/cached_outputs_with_recalculation_spec.rb
164
166
  - spec/nutrition_calculator/calorie_budgeter_spec.rb
165
167
  - spec/nutrition_calculator/data_summarizer_spec.rb
168
+ - spec/nutrition_calculator/diet_period_spec.rb
166
169
  - spec/nutrition_calculator_spec.rb
167
170
  - spec/spec_helper.rb
168
171
  has_rdoc: