nemah 0.1.1
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 +7 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/Guardfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +44 -0
- data/Rakefile +6 -0
- data/lib/nemah.rb +2 -0
- data/lib/nemah/horse.rb +80 -0
- data/lib/nemah/need.rb +41 -0
- data/lib/nemah/specific_need/abstract_need.rb +49 -0
- data/lib/nemah/specific_need/calcium.rb +13 -0
- data/lib/nemah/specific_need/energy.rb +63 -0
- data/lib/nemah/specific_need/magnesium.rb +13 -0
- data/lib/nemah/specific_need/mineral_behaviour.rb +77 -0
- data/lib/nemah/specific_need/phosphor.rb +13 -0
- data/lib/nemah/specific_need/protein.rb +23 -0
- data/lib/nemah/specific_need/salt.rb +13 -0
- data/lib/nemah/specific_need/selenium.rb +23 -0
- data/lib/nemah/specific_need/solids.rb +27 -0
- data/lib/nemah/version.rb +3 -0
- data/lib/nemah/workload.rb +30 -0
- data/nemah.gemspec +27 -0
- data/spec/nemah/horse_spec.rb +93 -0
- data/spec/nemah/need_spec.rb +103 -0
- data/spec/nemah/specific_need/calcium_spec.rb +15 -0
- data/spec/nemah/specific_need/energy_spec.rb +76 -0
- data/spec/nemah/specific_need/magnesium_spec.rb +15 -0
- data/spec/nemah/specific_need/phosphor_spec.rb +15 -0
- data/spec/nemah/specific_need/protein_spec.rb +55 -0
- data/spec/nemah/specific_need/salt_spec.rb +15 -0
- data/spec/nemah/specific_need/selenium_spec.rb +57 -0
- data/spec/nemah/specific_need/solids_spec.rb +57 -0
- data/spec/nemah/workload_spec.rb +35 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/support/shared_examples_for_a_mineral.rb +73 -0
- data/spec/support/shared_examples_for_a_specific_need.rb +12 -0
- metadata +182 -0
@@ -0,0 +1,13 @@
|
|
1
|
+
module Nemah
|
2
|
+
module SpecificNeed
|
3
|
+
class Phosphor < AbstractNeed
|
4
|
+
include Nemah::SpecificNeed::MineralBehaviour
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def factor_table
|
9
|
+
FactorTable.new(no_work: 2.8, below_30: 3.6, below_50: 4.2, below_75: 5.8, above_75: 5.8)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Nemah
|
2
|
+
module SpecificNeed
|
3
|
+
class Protein < AbstractNeed
|
4
|
+
private
|
5
|
+
|
6
|
+
def _ideal
|
7
|
+
ideal_energy * 6
|
8
|
+
end
|
9
|
+
|
10
|
+
def _min
|
11
|
+
0.90 * _ideal
|
12
|
+
end
|
13
|
+
|
14
|
+
def _max
|
15
|
+
1.10 * _ideal
|
16
|
+
end
|
17
|
+
|
18
|
+
def ideal_energy
|
19
|
+
need.energy.ideal(decimals: 4)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Nemah
|
2
|
+
module SpecificNeed
|
3
|
+
class Salt < AbstractNeed
|
4
|
+
include Nemah::SpecificNeed::MineralBehaviour
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def factor_table
|
9
|
+
FactorTable.new(no_work: 5.1, below_30: 7.0, below_50: 9.0, below_75: 9.0, above_75: 13.0)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Nemah
|
2
|
+
module SpecificNeed
|
3
|
+
class Selenium < AbstractNeed
|
4
|
+
def unit
|
5
|
+
:mg
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def _ideal
|
11
|
+
min
|
12
|
+
end
|
13
|
+
|
14
|
+
def _min
|
15
|
+
horse.weight_in_deciton * 0.20
|
16
|
+
end
|
17
|
+
|
18
|
+
def _max
|
19
|
+
horse.weight_in_deciton * 5.00
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Nemah
|
2
|
+
module SpecificNeed
|
3
|
+
class Solids < AbstractNeed
|
4
|
+
def max(decimals: 2)
|
5
|
+
_max
|
6
|
+
end
|
7
|
+
|
8
|
+
def unit
|
9
|
+
:kg
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def _ideal
|
15
|
+
min
|
16
|
+
end
|
17
|
+
|
18
|
+
def _min
|
19
|
+
horse.weight_in_deciton * 1.50
|
20
|
+
end
|
21
|
+
|
22
|
+
def _max
|
23
|
+
Float::INFINITY
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Nemah
|
2
|
+
class Workload
|
3
|
+
ATTRIBUTES = [:walk, :trot_and_canter, :days_per_week].freeze
|
4
|
+
|
5
|
+
attr_reader *ATTRIBUTES
|
6
|
+
|
7
|
+
def initialize(args = {})
|
8
|
+
attributes.each do |attribute|
|
9
|
+
instance_variable_set "@#{attribute}", args.fetch(attribute, 0)
|
10
|
+
end
|
11
|
+
assert_valid_days_per_week
|
12
|
+
end
|
13
|
+
|
14
|
+
def ==(other)
|
15
|
+
attributes.all? do |attribute|
|
16
|
+
send(attribute) == other.send(attribute)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def attributes
|
23
|
+
ATTRIBUTES.dup
|
24
|
+
end
|
25
|
+
|
26
|
+
def assert_valid_days_per_week
|
27
|
+
raise ArgumentError.new('days_per_week must be between 0 and 7') unless (0..7).include? days_per_week
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/nemah.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'nemah/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'nemah'
|
8
|
+
spec.version = Nemah::VERSION
|
9
|
+
spec.authors = ['Kim Persson', 'Lennart Fridén']
|
10
|
+
spec.email = ['forgetmenotox@notingham.se']
|
11
|
+
spec.description = 'Nemah is a library for calculating the proper amount of fodder for your horse.'
|
12
|
+
spec.summary = 'Horse fodder calculations library.'
|
13
|
+
spec.homepage = 'https://github.com/Lavinia/Nemah'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
22
|
+
spec.add_development_dependency 'byebug', '~> 2.5'
|
23
|
+
spec.add_development_dependency 'guard', '~> 2.2'
|
24
|
+
spec.add_development_dependency 'guard-rspec', '~> 4.2'
|
25
|
+
spec.add_development_dependency 'rake', '~> 10.1'
|
26
|
+
spec.add_development_dependency 'rspec', '~> 2.14'
|
27
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Nemah do
|
4
|
+
describe Nemah::Horse do
|
5
|
+
it 'must have a weight' do
|
6
|
+
expect { a_horse_without(:weight) }.to raise_error(ArgumentError, 'weight required')
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'must have a gender' do
|
10
|
+
expect { a_horse_without(:gender) }.to raise_error(ArgumentError, 'gender required')
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'cannot have a non-existing gender' do
|
14
|
+
expect {
|
15
|
+
a_horse_with(gender: :non_existing)
|
16
|
+
}.to raise_error(ArgumentError, ':non_existing is not an allowed gender')
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'can be named' do
|
20
|
+
expect(a_horse_named('Nemah').name).to eq('Nemah')
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'is considered to be of normal difficulty to feed' do
|
24
|
+
expect(a_horse.feedability).to eq(:normal)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'can be hard to feed' do
|
28
|
+
expect(a_horse_with(feedability: :hard).feedability).to eq(:hard)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'can be easy to feed' do
|
32
|
+
expect(a_horse_with(feedability: :easy).feedability).to eq(:easy)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'cannot be impossible to feed' do
|
36
|
+
expect {
|
37
|
+
a_horse_with(feedability: :impossible)
|
38
|
+
}.to raise_error(ArgumentError, ':impossible is not an allowed feedability')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'cannot have a negative weight' do
|
42
|
+
expect {
|
43
|
+
a_horse_with(weight: -50)
|
44
|
+
}.to raise_error(ArgumentError, '-50 is not an allowed weight')
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'defaults to no workload' do
|
48
|
+
no_workload = Nemah::Workload.new(walk: 0, trot_and_canter: 0, days_per_week: 0)
|
49
|
+
expect(a_horse_without(:workload).workload).to eq(no_workload)
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#stallion?' do
|
53
|
+
it 'returns true if the horse is a stallion' do
|
54
|
+
expect(a_horse_with gender: :stallion).to be_stallion
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#weight_in_deciton' do
|
59
|
+
it 'returns the weight divided by a hundred' do
|
60
|
+
expect(a_horse_with(weight: 650).weight_in_deciton).to eq(6.5)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def workload_for_a_horse_told(method)
|
67
|
+
workload = double(walk: 30, trot_and_canter: 20, days_per_week: 3)
|
68
|
+
horse = a_horse_with(workload: workload)
|
69
|
+
horse.send(method)
|
70
|
+
workload
|
71
|
+
end
|
72
|
+
|
73
|
+
def a_horse
|
74
|
+
Nemah::Horse.new(default_attributes)
|
75
|
+
end
|
76
|
+
|
77
|
+
def a_horse_with(attributes)
|
78
|
+
Nemah::Horse.new(default_attributes.merge(attributes))
|
79
|
+
end
|
80
|
+
|
81
|
+
def a_horse_without(attribute)
|
82
|
+
Nemah::Horse.new(default_attributes.delete_if { |key, _| key == attribute })
|
83
|
+
end
|
84
|
+
|
85
|
+
def a_horse_named(name)
|
86
|
+
a_horse_with(name: name)
|
87
|
+
end
|
88
|
+
|
89
|
+
def default_attributes
|
90
|
+
{ weight: 450, gender: :mare }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Nemah::Need do
|
4
|
+
describe 'calculating solids' do
|
5
|
+
it 'for an arabian princess' do
|
6
|
+
expect(need_for_nemah.solids.to_rounded_range).to eq(6.75..Float::INFINITY)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'for a huge horse' do
|
10
|
+
expect(need_for_samson.solids.to_rounded_range).to eq(13.50..Float::INFINITY)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'calculating energy need with a ±3 variance' do
|
15
|
+
it 'for a non-working, hard to feed mare' do
|
16
|
+
expect(need_for_nemah.energy.to_rounded_range).to eq(50.74..56.74)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'for a non-working, easy to feed gelding' do
|
20
|
+
expect(need_for_samson.energy.to_rounded_range).to eq(79.16..85.16)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'for a non-working, normal to feed stallion' do
|
24
|
+
expect(need_for_janus.energy.to_rounded_range).to eq(67.01..73.01)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'for a moderately-working, hard to feed mare' do
|
28
|
+
expect(need_for_nemah(workload: moderate_workload).energy.to_rounded_range).to eq(71.31..77.31)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'for a hard-working, easy to feed gelding' do
|
32
|
+
expect(need_for_samson(workload: hard_workload).energy.to_rounded_range).to eq(164.66..170.66)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'calculating protein need with a ±10% variance' do
|
37
|
+
it 'for a non-working easy to feed gelding' do
|
38
|
+
expect(need_for_samson.protein.to_rounded_range).to eq(443.66..542.25)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'for a moderately-working, hard to feed mare' do
|
42
|
+
expect(need_for_nemah(workload: moderate_workload).protein.to_rounded_range).to eq(401.26..490.43)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
describe 'calculating calcium' do
|
48
|
+
it 'for an arabian princess' do
|
49
|
+
expect(need_for_nemah.calcium.to_rounded_range).to eq(18.00..Float::INFINITY)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe 'calculating magnesium' do
|
54
|
+
it 'for an arabian princess' do
|
55
|
+
expect(need_for_nemah.magnesium.to_rounded_range).to eq(6.75..Float::INFINITY)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe 'calculating phosphor' do
|
60
|
+
it 'for an arabian princess' do
|
61
|
+
expect(need_for_nemah.phosphor.to_rounded_range).to eq(12.60..Float::INFINITY)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe 'calculating selenium' do
|
66
|
+
it 'for an arabian princess' do
|
67
|
+
expect(need_for_nemah.selenium.to_rounded_range).to eq(0.90..22.50)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'calculating salt' do
|
72
|
+
it 'for an arabian princess' do
|
73
|
+
expect(need_for_nemah.salt.to_rounded_range).to eq(22.95..Float::INFINITY)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def moderate_workload
|
81
|
+
Nemah::Workload.new(walk: 60, trot_and_canter: 40, days_per_week: 5)
|
82
|
+
end
|
83
|
+
|
84
|
+
def hard_workload
|
85
|
+
Nemah::Workload.new(walk: 85, trot_and_canter: 60, days_per_week: 7)
|
86
|
+
end
|
87
|
+
|
88
|
+
def need_for_horse_with(args)
|
89
|
+
Nemah::Need.new(Nemah::Horse.new(args))
|
90
|
+
end
|
91
|
+
|
92
|
+
def need_for_samson(args = {})
|
93
|
+
need_for_horse_with({weight: 900, gender: :gelding, feedability: :easy}.merge args)
|
94
|
+
end
|
95
|
+
|
96
|
+
def need_for_nemah(args = {})
|
97
|
+
need_for_horse_with({weight: 450, gender: :mare, feedability: :hard}.merge args)
|
98
|
+
end
|
99
|
+
|
100
|
+
def need_for_janus
|
101
|
+
need_for_horse_with(weight: 600, gender: :stallion, feedability: :normal)
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Nemah::SpecificNeed::Calcium do
|
4
|
+
it_behaves_like 'a specific need' do
|
5
|
+
let(:unit) { :g }
|
6
|
+
end
|
7
|
+
|
8
|
+
it_behaves_like 'a mineral' do
|
9
|
+
let(:no_workload_min_need) { 21.20 }
|
10
|
+
let(:light_workload_min_need) { 31.80 }
|
11
|
+
let(:medium_workload_min_need) { 37.10 }
|
12
|
+
let(:hard_workload_min_need) { 42.40 }
|
13
|
+
let(:very_hard_workload_min_need) { 42.40 }
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Nemah::SpecificNeed::Energy do
|
4
|
+
it_behaves_like 'a specific need' do
|
5
|
+
let(:unit) { :MJ }
|
6
|
+
end
|
7
|
+
|
8
|
+
describe '#for_workload' do
|
9
|
+
it 'returns the workload portion of the energy need' do
|
10
|
+
expect(energy.for_workload).to eq(10.97)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#for_maintenance' do
|
15
|
+
it 'returns the maintenance energy need' do
|
16
|
+
expect(energy.for_maintenance).to eq(70.01)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#to_rounded_range' do
|
21
|
+
it 'returns a range between minimum and maximum allowed amounts, rounded to two decimals' do
|
22
|
+
expect(energy.to_rounded_range).to eq(77.98..83.98)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'optionally takes the number of decimals' do
|
26
|
+
expect(energy.to_rounded_range(decimals: 3)).to eq(77.982..83.982)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#ideal' do
|
31
|
+
it 'returns the ideal energy need' do
|
32
|
+
expect(energy.ideal).to eq(80.98)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'optionally takes the number of decimals' do
|
36
|
+
expect(energy.ideal(decimals: 5)).to eq(80.98229)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#min' do
|
41
|
+
it 'returns the minimum energy need' do
|
42
|
+
expect(energy.min).to eq(77.98)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'optionally takes the number of decimals' do
|
46
|
+
expect(energy.min(decimals: 4)).to eq(77.9823)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'cannot be less than 0' do
|
50
|
+
feather_weight_horse_energy = Nemah::SpecificNeed::Energy.new(need(weight: 0.1))
|
51
|
+
expect(feather_weight_horse_energy.min).to eq(0)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '#max' do
|
56
|
+
it 'returns the maximum energy need' do
|
57
|
+
expect(energy.max).to eq(83.98)
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'optionally takes the number of decimals' do
|
61
|
+
expect(energy.max(decimals: 0)).to eq(84)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def energy
|
68
|
+
Nemah::SpecificNeed::Energy.new(need)
|
69
|
+
end
|
70
|
+
|
71
|
+
def need(weight: 600)
|
72
|
+
workload = double('workload', walk: 30, trot_and_canter: 20, days_per_week: 4)
|
73
|
+
horse = double('horse', stallion?: true, weight: weight, weight_in_deciton: weight / 100.0, feedability: :normal, workload: workload)
|
74
|
+
double('need', horse: horse)
|
75
|
+
end
|
76
|
+
end
|