nutrition_calculator 1.0.3 → 1.0.4

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: 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: