nutrition_calculator 1.0.3 → 1.0.4
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/bin/run_calorie_budgeter +9 -40
- data/lib/nutrition_calculator/cached_outputs_with_recalculation.rb +22 -3
- data/lib/nutrition_calculator/calorie_budgeter.rb +21 -6
- data/lib/nutrition_calculator/data_summarizer.rb +50 -0
- data/lib/nutrition_calculator/version.rb +1 -1
- data/spec/nutrition_calculator/cached_outputs_with_recalculation_spec.rb +19 -0
- data/spec/nutrition_calculator/data_summarizer_spec.rb +79 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d192a9cd1ea3c900f999599597c9c6f9549e3dc7
|
4
|
+
data.tar.gz: 6ea66889e0f2ea5be1f40f1bf1557220c37de9b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a3de99ed764a0e07b3234f75968530828fb931b93771754750a3b0195726c11ca7868ca9d8bb0eb5304d78e71413e8c2cb1f8204821b2feabfcb0322127d7548
|
7
|
+
data.tar.gz: 2a9cc36e2a69593def04b9834310acea0eb916a9ee5cbdb56576cd8b14ba965e2046e4c010d1fc0af17b486a67d61e6b312caf394ac8c06fe950f053ef011bf9
|
data/bin/run_calorie_budgeter
CHANGED
@@ -54,57 +54,26 @@ end
|
|
54
54
|
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
|
55
55
|
|
56
56
|
require 'nutrition_calculator/calorie_budgeter'
|
57
|
+
require 'nutrition_calculator/data_summarizer'
|
57
58
|
require 'yaml'
|
58
|
-
require 'date'
|
59
|
-
|
60
59
|
|
61
60
|
def data
|
62
61
|
@data ||= YAML.load_file(ARGV.first)
|
63
62
|
end
|
64
63
|
|
65
|
-
|
66
|
-
day = Date.today.wday
|
67
|
-
day = 7 if day == 0 # Sunday is the 7th day of the diet week
|
68
|
-
day
|
69
|
-
end
|
70
|
-
|
71
|
-
def data_for_day(day_num)
|
72
|
-
data.fetch(day_num) do
|
73
|
-
{ 'calories_burned' => 0, 'calories_consumed' => 0 }
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def prior_days_net_calories
|
78
|
-
values = (1...current_day_num).map { |day_num|
|
79
|
-
day_data = data_for_day(day_num)
|
80
|
-
day_data['calories_consumed'] - day_data['calories_burned']
|
81
|
-
}
|
82
|
-
values.reduce { |sum, daily_net_calories|
|
83
|
-
sum + daily_net_calories
|
84
|
-
}
|
85
|
-
end
|
86
|
-
|
87
|
-
def today
|
88
|
-
data_for_day(current_day_num)
|
89
|
-
end
|
90
|
-
|
91
|
-
def calories_burned_today
|
92
|
-
today['calories_burned']
|
93
|
-
end
|
94
|
-
|
95
|
-
def calories_consumed_today
|
96
|
-
today['calories_consumed']
|
97
|
-
end
|
98
|
-
|
64
|
+
summarizer = NutritionCalculator::DataSummarizer.new(source_data: data)
|
99
65
|
cb = NutritionCalculator::CalorieBudgeter.new
|
66
|
+
|
100
67
|
# require 'logger'
|
101
68
|
# cb.logger = Logger.new(STDERR)
|
69
|
+
#
|
102
70
|
cb.resting_metabolic_rate = data['resting_metabolic_rate']
|
103
71
|
cb.weekly_calorie_goal = data['weekly_calorie_goal']
|
104
|
-
|
105
|
-
cb.
|
106
|
-
cb.
|
107
|
-
cb.
|
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
|
108
77
|
|
109
78
|
puts "You have consumed #{cb.calories_consumed} calories today."
|
110
79
|
puts "You have burned #{cb.calories_burned} calories today."
|
@@ -10,6 +10,10 @@ module NutritionCalculator
|
|
10
10
|
#
|
11
11
|
# def_input :bar
|
12
12
|
#
|
13
|
+
# def_input :spam, validate_with: ->(value) {
|
14
|
+
# value != 'ham'
|
15
|
+
# }
|
16
|
+
#
|
13
17
|
# def_output :baz do
|
14
18
|
# bar.expensive_operation
|
15
19
|
# end
|
@@ -20,6 +24,11 @@ module NutritionCalculator
|
|
20
24
|
# x.baz
|
21
25
|
# #=> Raises a RuntimeError because input bar was not set
|
22
26
|
#
|
27
|
+
# x.spam = 'ham'
|
28
|
+
# #=> Raises a
|
29
|
+
# NutritionCalculator::CachedOutputsWithRecalculation::InvalidInputError
|
30
|
+
# because the validation returned false.
|
31
|
+
#
|
23
32
|
# a_thing = ExpensiveObject.new
|
24
33
|
#
|
25
34
|
# x.bar = a_thing
|
@@ -37,6 +46,8 @@ module NutritionCalculator
|
|
37
46
|
# #=> result of `a_thing.expensive_operation`
|
38
47
|
#
|
39
48
|
module CachedOutputsWithRecalculation
|
49
|
+
class InvalidInputError < RuntimeError; end
|
50
|
+
|
40
51
|
# @private
|
41
52
|
def self.extended(other)
|
42
53
|
other.include(InstanceMethods)
|
@@ -48,8 +59,8 @@ module NutritionCalculator
|
|
48
59
|
# recalculated the next time they are called.
|
49
60
|
#
|
50
61
|
# @param name [Symbol]
|
51
|
-
def def_input(name)
|
52
|
-
def_input_writer name
|
62
|
+
def def_input(name, validate_with: ->(_) { true })
|
63
|
+
def_input_writer name, validator: validate_with
|
53
64
|
def_input_reader name
|
54
65
|
end
|
55
66
|
|
@@ -71,8 +82,9 @@ module NutritionCalculator
|
|
71
82
|
|
72
83
|
private
|
73
84
|
|
74
|
-
def def_input_writer(name)
|
85
|
+
def def_input_writer(name, validator:)
|
75
86
|
define_method("#{name}=") do |value|
|
87
|
+
validate_input!(name, value, validator)
|
76
88
|
recalculate!
|
77
89
|
instance_variable_set("@#{name}", value)
|
78
90
|
end
|
@@ -96,6 +108,13 @@ module NutritionCalculator
|
|
96
108
|
@cached_values ||= {}
|
97
109
|
end
|
98
110
|
|
111
|
+
def validate_input!(name, value, validator)
|
112
|
+
success = validator.(value)
|
113
|
+
if !success
|
114
|
+
raise InvalidInputError, "#{value.inspect} is not a valid input value for '##{name}'."
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
99
118
|
def recalculate!
|
100
119
|
logger.debug "Input received; clearing cached calculations."
|
101
120
|
@cached_values = {}
|
@@ -44,12 +44,17 @@ module NutritionCalculator
|
|
44
44
|
|
45
45
|
# @!attribute
|
46
46
|
# @return [Integer] The daily resting metabolic rate in calories
|
47
|
-
def_input :resting_metabolic_rate
|
47
|
+
def_input :resting_metabolic_rate, validate_with: ->(value) {
|
48
|
+
value.kind_of?(Integer) \
|
49
|
+
&& value > 0
|
50
|
+
}
|
48
51
|
|
49
52
|
# @!attribute
|
50
53
|
# @return [Integer] The total net calories (consumed - burned) planned for
|
51
54
|
# the week
|
52
|
-
def_input :weekly_calorie_goal
|
55
|
+
def_input :weekly_calorie_goal, validate_with: ->(value) {
|
56
|
+
value.kind_of?(Integer)
|
57
|
+
}
|
53
58
|
|
54
59
|
# @!attribute
|
55
60
|
# @return [Integer] The total net calories from all days this week prior
|
@@ -60,7 +65,9 @@ module NutritionCalculator
|
|
60
65
|
# And on Tuesday you consumed 200 calories and burned 100 for a net of 100
|
61
66
|
# Then you don't care about today's calories
|
62
67
|
# And the value for this input should be 125 (Monday + Tuesday)
|
63
|
-
def_input :prior_days_calories
|
68
|
+
def_input :prior_days_calories, validate_with: ->(value) {
|
69
|
+
value.kind_of?(Integer)
|
70
|
+
}
|
64
71
|
|
65
72
|
# @!attribute
|
66
73
|
# @return [Integer] The number of the day of the week
|
@@ -72,15 +79,23 @@ module NutritionCalculator
|
|
72
79
|
# 5 - Friday
|
73
80
|
# 6 - Saturday
|
74
81
|
# 7 - Sunday
|
75
|
-
def_input :current_day_of_week
|
82
|
+
def_input :current_day_of_week, validate_with: ->(value) {
|
83
|
+
(1..7).include?(value)
|
84
|
+
}
|
76
85
|
|
77
86
|
# @!attribute
|
78
87
|
# @return [Integer] The total number of calories consumed today
|
79
|
-
def_input :calories_consumed
|
88
|
+
def_input :calories_consumed, validate_with: ->(value) {
|
89
|
+
value.kind_of?(Integer) \
|
90
|
+
&& value >= 0
|
91
|
+
}
|
80
92
|
|
81
93
|
# @!attribute
|
82
94
|
# @return [Integer] The total number of calories burned via exercise today
|
83
|
-
def_input :calories_burned
|
95
|
+
def_input :calories_burned, validate_with: ->(value) {
|
96
|
+
value.kind_of?(Integer) \
|
97
|
+
&& value >= 0
|
98
|
+
}
|
84
99
|
|
85
100
|
# @!group Outputs
|
86
101
|
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module NutritionCalculator
|
4
|
+
class DataSummarizer
|
5
|
+
SUNDAY = 7
|
6
|
+
MONDAY = 1
|
7
|
+
|
8
|
+
def initialize(source_data:, calendar: Date)
|
9
|
+
self.source_data = source_data
|
10
|
+
self.calendar = calendar
|
11
|
+
end
|
12
|
+
|
13
|
+
def prior_days_net_calories
|
14
|
+
return 0 if current_day == MONDAY
|
15
|
+
values = (1...current_day).map { |day| net_calories_for_day(day) }
|
16
|
+
values.reduce { |weekly_net, daily_net| weekly_net + daily_net }
|
17
|
+
end
|
18
|
+
|
19
|
+
def calories_consumed_today
|
20
|
+
source_data_for_day(current_day)['calories_consumed']
|
21
|
+
end
|
22
|
+
|
23
|
+
def calories_burned_today
|
24
|
+
source_data_for_day(current_day)['calories_burned']
|
25
|
+
end
|
26
|
+
|
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.
|
30
|
+
def current_day
|
31
|
+
day = calendar.today.wday
|
32
|
+
day = SUNDAY if day < MONDAY
|
33
|
+
day
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
attr_accessor :source_data, :calendar
|
38
|
+
|
39
|
+
def net_calories_for_day(day)
|
40
|
+
data = source_data_for_day(day)
|
41
|
+
data['calories_consumed'] - data['calories_burned']
|
42
|
+
end
|
43
|
+
|
44
|
+
def source_data_for_day(day)
|
45
|
+
source_data.fetch(day) do
|
46
|
+
{'calories_consumed' => 0, 'calories_burned' => 0}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -8,6 +8,10 @@ describe NutritionCalculator::CachedOutputsWithRecalculation do
|
|
8
8
|
|
9
9
|
def_input :foo
|
10
10
|
|
11
|
+
def_input :spam, validate_with: ->(value) {
|
12
|
+
value != 'ham'
|
13
|
+
}
|
14
|
+
|
11
15
|
def_output :baz do
|
12
16
|
foo.bar
|
13
17
|
end
|
@@ -28,6 +32,21 @@ describe NutritionCalculator::CachedOutputsWithRecalculation do
|
|
28
32
|
raise_error(RuntimeError, "Required input missing: `foo`.")
|
29
33
|
end
|
30
34
|
|
35
|
+
context 'when an input has a validator' do
|
36
|
+
it 'raises an exception on assignment if the validation fails' do
|
37
|
+
expect { subject.spam = 'ham' }.to \
|
38
|
+
raise_error(
|
39
|
+
NutritionCalculator::CachedOutputsWithRecalculation::InvalidInputError,
|
40
|
+
"#{'ham'.inspect} is not a valid input value for '#spam'."
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'does not raise an exception if the validation passes' do
|
45
|
+
subject.foo = 'canned ham'
|
46
|
+
expect(subject.foo).to eq 'canned ham'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
31
50
|
it 'creates attr_readers for outputs' do
|
32
51
|
subject.foo = foo_value
|
33
52
|
expect(subject.baz).to eq 'baz'
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'nutrition_calculator/data_summarizer'
|
3
|
+
|
4
|
+
describe NutritionCalculator::DataSummarizer do
|
5
|
+
let(:source_data) {{
|
6
|
+
1 => {
|
7
|
+
'calories_consumed' => 1000,
|
8
|
+
'calories_burned' => 500
|
9
|
+
},
|
10
|
+
2 => {
|
11
|
+
'calories_consumed' => 1001,
|
12
|
+
'calories_burned' => 500
|
13
|
+
},
|
14
|
+
3 => {
|
15
|
+
'calories_consumed' => 1000,
|
16
|
+
'calories_burned' => 501
|
17
|
+
},
|
18
|
+
4 => {
|
19
|
+
'calories_consumed' => 1002,
|
20
|
+
'calories_burned' => 500
|
21
|
+
},
|
22
|
+
5 => {
|
23
|
+
'calories_consumed' => 1000,
|
24
|
+
'calories_burned' => 502
|
25
|
+
},
|
26
|
+
6 => {
|
27
|
+
'calories_consumed' => 1003,
|
28
|
+
'calories_burned' => 500
|
29
|
+
},
|
30
|
+
7 => {
|
31
|
+
'calories_consumed' => 1000,
|
32
|
+
'calories_burned' => 503
|
33
|
+
},
|
34
|
+
}}
|
35
|
+
|
36
|
+
let(:calendar) { double(:calendar, today: today) }
|
37
|
+
|
38
|
+
subject { described_class.new(source_data: source_data, calendar: calendar) }
|
39
|
+
|
40
|
+
context "on day 1" do
|
41
|
+
let(:today) { Date.new(2015,2,16) }
|
42
|
+
|
43
|
+
it 'reports prior_days_net_calories as 0' do
|
44
|
+
expect(subject.prior_days_net_calories).to eq 0
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'reports calories burned today' do
|
48
|
+
expect(subject.calories_burned_today).to eq 500
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'reports calories consumed today' do
|
52
|
+
expect(subject.calories_consumed_today).to eq 1000
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'reports that the current day number is 1' do
|
56
|
+
expect(subject.current_day).to eq 1
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "on day 7" do
|
61
|
+
let(:today) { Date.new(2015,2,22) }
|
62
|
+
|
63
|
+
it 'reports prior_days_net_calories as the sum of calories consumed less the sum of calories burned' do
|
64
|
+
expect(subject.prior_days_net_calories).to eq 3_003
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'reports calories burned today' do
|
68
|
+
expect(subject.calories_burned_today).to eq 503
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'reports calories consumed today' do
|
72
|
+
expect(subject.calories_consumed_today).to eq 1000
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'reports that the current day number is 7' do
|
76
|
+
expect(subject.current_day).to eq 7
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nutrition_calculator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Wilger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-02-
|
11
|
+
date: 2015-02-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -121,11 +121,13 @@ files:
|
|
121
121
|
- lib/nutrition_calculator.rb
|
122
122
|
- lib/nutrition_calculator/cached_outputs_with_recalculation.rb
|
123
123
|
- lib/nutrition_calculator/calorie_budgeter.rb
|
124
|
+
- lib/nutrition_calculator/data_summarizer.rb
|
124
125
|
- lib/nutrition_calculator/has_logging.rb
|
125
126
|
- lib/nutrition_calculator/version.rb
|
126
127
|
- nutrition_calculator.gemspec
|
127
128
|
- spec/nutrition_calculator/cached_outputs_with_recalculation_spec.rb
|
128
129
|
- spec/nutrition_calculator/calorie_budgeter_spec.rb
|
130
|
+
- spec/nutrition_calculator/data_summarizer_spec.rb
|
129
131
|
- spec/nutrition_calculator_spec.rb
|
130
132
|
- spec/spec_helper.rb
|
131
133
|
homepage: ''
|
@@ -160,6 +162,7 @@ test_files:
|
|
160
162
|
- features/support/helper_methods.rb
|
161
163
|
- spec/nutrition_calculator/cached_outputs_with_recalculation_spec.rb
|
162
164
|
- spec/nutrition_calculator/calorie_budgeter_spec.rb
|
165
|
+
- spec/nutrition_calculator/data_summarizer_spec.rb
|
163
166
|
- spec/nutrition_calculator_spec.rb
|
164
167
|
- spec/spec_helper.rb
|
165
168
|
has_rdoc:
|