nutrition_calculator 1.0.4 → 1.2.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 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: