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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bdf1b1d1d82d53bc441aa174ac25a7c18230ba18
4
- data.tar.gz: 89dfd108e4ae7d1aa81935174bd61c26728a2dd4
3
+ metadata.gz: d192a9cd1ea3c900f999599597c9c6f9549e3dc7
4
+ data.tar.gz: 6ea66889e0f2ea5be1f40f1bf1557220c37de9b6
5
5
  SHA512:
6
- metadata.gz: fd8e4e88e9e99e18c4311b2c43e95d78bd6cd79e95fdfd1c8eaf4589e3072ad789dd4e1814762315097639e2a409e4c1ec91251b3307f1176e2bc29bfc6c8bc1
7
- data.tar.gz: 3d9120ab0259503793d2b40a70248b97a360f387b642e400f2e18868f9c26c839e0f6dd756fc100767588ec719384a683fa7bfe976b45baedf0d9068cc7efd06
6
+ metadata.gz: a3de99ed764a0e07b3234f75968530828fb931b93771754750a3b0195726c11ca7868ca9d8bb0eb5304d78e71413e8c2cb1f8204821b2feabfcb0322127d7548
7
+ data.tar.gz: 2a9cc36e2a69593def04b9834310acea0eb916a9ee5cbdb56576cd8b14ba965e2046e4c010d1fc0af17b486a67d61e6b312caf394ac8c06fe950f053ef011bf9
@@ -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
- def current_day_num
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
- cb.current_day_of_week = current_day_num
105
- cb.prior_days_calories = prior_days_net_calories
106
- cb.calories_burned = calories_burned_today
107
- cb.calories_consumed = calories_consumed_today
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
@@ -1,3 +1,3 @@
1
1
  module NutritionCalculator
2
- VERSION = "1.0.3"
2
+ VERSION = "1.0.4"
3
3
  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.3
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-10 00:00:00.000000000 Z
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: