zymurgy 0.10.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.
- data/.document +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +22 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/lib/zymurgy.rb +16 -0
- data/lib/zymurgy/acts_as_brew_recipe.rb +53 -0
- data/lib/zymurgy/acts_as_brewery.rb +23 -0
- data/lib/zymurgy/acts_as_fermentable.rb +31 -0
- data/lib/zymurgy/acts_as_hop_addition.rb +33 -0
- data/lib/zymurgy/utils.rb +46 -0
- data/spec/acts_as_brew_recipe_spec.rb +87 -0
- data/spec/acts_as_brewery_spec.rb +32 -0
- data/spec/acts_as_fermentable_spec.rb +123 -0
- data/spec/acts_as_hop_addition_spec.rb +116 -0
- data/spec/database.yml +9 -0
- data/spec/patches/float.rb +7 -0
- data/spec/schema.rb +46 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/zymurgy_utils_spec.rb +51 -0
- data/zymurgy.gemspec +75 -0
- metadata +116 -0
data/.document
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Mike Breeze
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
= zymurgy
|
2
|
+
|
3
|
+
(n) The branch of chemistry that deals with fermentation processes, as in brewing.
|
4
|
+
|
5
|
+
Zymurgy is a collection of libraries to help with beer brewing calculations:
|
6
|
+
* Gravity points
|
7
|
+
* Hop utilisation
|
8
|
+
* Boil times and volumes
|
9
|
+
|
10
|
+
== Note on Patches/Pull Requests
|
11
|
+
|
12
|
+
* Fork the project.
|
13
|
+
* Make your feature addition or bug fix.
|
14
|
+
* Add tests for it. This is important so I don't break it in a
|
15
|
+
future version unintentionally.
|
16
|
+
* Commit, do not mess with rakefile, version, or history.
|
17
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
18
|
+
* Send me a pull request. Bonus points for topic branches.
|
19
|
+
|
20
|
+
== Copyright
|
21
|
+
|
22
|
+
Copyright (c) 2010 Mike Breeze. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "zymurgy"
|
8
|
+
gem.summary = %Q{A beer brewing gem}
|
9
|
+
gem.description = %Q{(n) The branch of chemistry that deals with fermentation processes, as in brewing.
|
10
|
+
|
11
|
+
Zymurgy is a collection of libraries to help with beer brewing calculations:
|
12
|
+
* Gravity points
|
13
|
+
* Hop utilisation
|
14
|
+
* Boil times and volumes}
|
15
|
+
gem.email = "breezy@binningup.com"
|
16
|
+
gem.homepage = "http://github.com/breezy/zymurgy"
|
17
|
+
gem.authors = ["Mike Breeze"]
|
18
|
+
gem.add_development_dependency "rspec", ">= 1.2.8"
|
19
|
+
#gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
20
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
21
|
+
end
|
22
|
+
Jeweler::GemcutterTasks.new
|
23
|
+
rescue LoadError
|
24
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'spec/rake/spectask'
|
28
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
29
|
+
spec.libs << 'lib' << 'spec'
|
30
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
31
|
+
spec.spec_opts = ['--color', '--reverse', '--backtrace']
|
32
|
+
end
|
33
|
+
|
34
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
35
|
+
spec.libs << 'lib' << 'spec'
|
36
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
37
|
+
spec.rcov = true
|
38
|
+
end
|
39
|
+
|
40
|
+
task :spec => :check_dependencies
|
41
|
+
|
42
|
+
task :default => :spec
|
43
|
+
|
44
|
+
require 'rake/rdoctask'
|
45
|
+
Rake::RDocTask.new do |rdoc|
|
46
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
47
|
+
|
48
|
+
rdoc.rdoc_dir = 'rdoc'
|
49
|
+
rdoc.title = "zymurgy #{version}"
|
50
|
+
rdoc.rdoc_files.include('README*')
|
51
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
52
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.10.0
|
data/lib/zymurgy.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
$LOAD_PATH << File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'active_record'
|
5
|
+
require "zymurgy/acts_as_brewery"
|
6
|
+
require "zymurgy/acts_as_brew_recipe"
|
7
|
+
require "zymurgy/acts_as_fermentable"
|
8
|
+
require "zymurgy/acts_as_hop_addition"
|
9
|
+
|
10
|
+
module Zymurgy
|
11
|
+
|
12
|
+
autoload :Utils, "zymurgy/utils"
|
13
|
+
|
14
|
+
ZymurgyError = Class.new(StandardError)
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Zymurgy
|
2
|
+
def self.included(base)
|
3
|
+
base.send :extend, ClassMethods
|
4
|
+
end
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def acts_as_brew_recipe(options = {})
|
8
|
+
send :include, InstanceMethods
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# TODO: Add hardening for when :send returns with null values.
|
13
|
+
module InstanceMethods
|
14
|
+
|
15
|
+
# bigness factor => 1.65*(0.000125^((original_gravity/1000)-1))
|
16
|
+
# round to 2dp
|
17
|
+
def bigness_factor
|
18
|
+
1.65 * 0.000125**(send(:original_gravity)/1000.0 - 1.0)
|
19
|
+
end
|
20
|
+
|
21
|
+
# ((original gravity - final gravity)/6.8)+0.2
|
22
|
+
def alcohol_by_volume
|
23
|
+
(send(:original_gravity) - send(:final_gravity)) / 6.8 + 0.2
|
24
|
+
end
|
25
|
+
|
26
|
+
def post_boil_volume_litres
|
27
|
+
send(:fermentation_volume_litres) + send(:kettle_tax_litres)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Mashout volume = Post Boil Volume + (Boil Time Minutes / 60) * evaporation_rate_litres_per_hour
|
31
|
+
def mash_out_volume_litres
|
32
|
+
post_boil_volume_litres() + boil_time_hours() * send(:evaporation_rate_litres_per_hour)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Mash In volume = Mash Out volume + (volume_lost_to_mash_litres_per_kg * weight of total grain bill)
|
36
|
+
def mash_in_volume_litres weight_of_total_grain_bill_kg
|
37
|
+
mash_out_volume_litres + send(:volume_lost_to_mash_litres_per_kg) * weight_of_total_grain_bill_kg
|
38
|
+
end
|
39
|
+
|
40
|
+
# TODO: Alias this?
|
41
|
+
def pre_boil_volume_litres
|
42
|
+
mash_out_volume_litres
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def boil_time_hours
|
48
|
+
send(:boil_time_minutes) / 60.0
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
ActiveRecord::Base.send :include, Zymurgy
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Zymurgy
|
2
|
+
def self.included(base)
|
3
|
+
base.send :extend, ClassMethods
|
4
|
+
end
|
5
|
+
|
6
|
+
# TODO: Not convinced we actually need an acts_as_brewery as yet. Maybe later.
|
7
|
+
# TODO: Provide options helper if attributes aren't as assumed.
|
8
|
+
module ClassMethods
|
9
|
+
def acts_as_brewery(options = {})
|
10
|
+
send :include, InstanceMethods
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module InstanceMethods
|
15
|
+
|
16
|
+
def add_litres_to_kettle_tax litres
|
17
|
+
kettle_tax = send(:kettle_tax_litres) + litres
|
18
|
+
send(:kettle_tax_litres=, kettle_tax)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
ActiveRecord::Base.send :include, Zymurgy
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Zymurgy
|
2
|
+
def self.included(base)
|
3
|
+
base.send :extend, ClassMethods
|
4
|
+
end
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def acts_as_fermentable(options = {})
|
8
|
+
send :include, InstanceMethods
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module InstanceMethods
|
13
|
+
def volume_gravity_points volume_litres
|
14
|
+
maximum_volume_gravity_points = (send(:points_per_kg_per_litre) / volume_litres) * send(:weight_in_kg)
|
15
|
+
|
16
|
+
return maximum_volume_gravity_points unless send(:mash)
|
17
|
+
return maximum_volume_gravity_points * send(:mash_efficiency_percentage) / 100
|
18
|
+
end
|
19
|
+
|
20
|
+
def post_boil_volume_gravity_points
|
21
|
+
volume_gravity_points(send(:post_boil_volume_litres))
|
22
|
+
end
|
23
|
+
|
24
|
+
def pre_boil_volume_gravity_points
|
25
|
+
volume_gravity_points send(:mash_out_volume_litres)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
ActiveRecord::Base.send :include, Zymurgy
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Zymurgy
|
2
|
+
def self.included(base)
|
3
|
+
base.send :extend, ClassMethods
|
4
|
+
end
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def acts_as_hop_addition(options = {})
|
8
|
+
send :include, InstanceMethods
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module InstanceMethods
|
13
|
+
|
14
|
+
# IBU = mg/l AA * time * bigness factor
|
15
|
+
def IBU
|
16
|
+
alpha_acid_mg_litre * time_factor * send(:bigness_factor)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# mg/l AA => ((AA/100) * weight_grams * 1000) / post_boil_volume
|
22
|
+
def alpha_acid_mg_litre
|
23
|
+
((send(:alpha_acid_percentage)/100.0) * send(:weight_grams) * 1000.0) / send(:post_boil_volume_litres)
|
24
|
+
end
|
25
|
+
|
26
|
+
# time => (1 - EXP((-0.04 * boil_time_minutes))) / 4.15
|
27
|
+
def time_factor
|
28
|
+
(1.0 - Math.exp((-0.04 * send(:boil_time_minutes)))) / 4.15
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
ActiveRecord::Base.send :include, Zymurgy
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Zymurgy
|
2
|
+
module Utils
|
3
|
+
|
4
|
+
def litres_2_us_gallons litres
|
5
|
+
litres / 3.78541178
|
6
|
+
end
|
7
|
+
|
8
|
+
def us_gallons_2_litres gallons
|
9
|
+
gallons * 3.78541178
|
10
|
+
end
|
11
|
+
|
12
|
+
def kilograms_2_pounds kilograms
|
13
|
+
kilograms * 2.2
|
14
|
+
end
|
15
|
+
|
16
|
+
def pounds_2_kilograms pounds
|
17
|
+
pounds / 2.2
|
18
|
+
end
|
19
|
+
|
20
|
+
def kilograms_2_ounces kilograms
|
21
|
+
kilograms / 0.0283495231
|
22
|
+
end
|
23
|
+
|
24
|
+
def ounces_2_kilograms ounces
|
25
|
+
ounces * 0.0283495231
|
26
|
+
end
|
27
|
+
|
28
|
+
def celsius_2_fahrenheit degrees_celsius
|
29
|
+
32.0 + degrees_celsius / (5.0/9.0)
|
30
|
+
end
|
31
|
+
|
32
|
+
def fahrenheit_2_celsius degrees_fahrenheit
|
33
|
+
(5.0/9.0) * (degrees_fahrenheit - 32.0)
|
34
|
+
end
|
35
|
+
|
36
|
+
def pkgl_2_ppg pkgl
|
37
|
+
litres_2_us_gallons(pounds_2_kilograms(pkgl))
|
38
|
+
end
|
39
|
+
|
40
|
+
def ppg_2_pkgl ppg
|
41
|
+
us_gallons_2_litres(kilograms_2_pounds(ppg))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Confirm test schema is loaded correctly" do
|
4
|
+
before do
|
5
|
+
load_schema
|
6
|
+
end
|
7
|
+
|
8
|
+
class Brew < ActiveRecord::Base
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should load test schema correctly" do
|
12
|
+
Brew.all.should eql []
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "Can act_as_brew_recipe" do
|
17
|
+
before do
|
18
|
+
load_schema
|
19
|
+
end
|
20
|
+
|
21
|
+
class Brew < ActiveRecord::Base
|
22
|
+
acts_as_brew_recipe
|
23
|
+
belongs_to :brewery
|
24
|
+
|
25
|
+
def evaporation_rate_litres_per_hour
|
26
|
+
self.brewery.evaporation_rate_litres_per_hour
|
27
|
+
end
|
28
|
+
|
29
|
+
def mash_efficiency_percentage
|
30
|
+
self.brewery.mash_efficiency_percentage
|
31
|
+
end
|
32
|
+
|
33
|
+
def volume_lost_to_mash_litres_per_kg
|
34
|
+
self.brewery.volume_lost_to_mash_litres_per_kg
|
35
|
+
end
|
36
|
+
|
37
|
+
def kettle_tax_litres
|
38
|
+
self.brewery.kettle_tax_litres
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class Brewery < ActiveRecord::Base
|
43
|
+
acts_as_brewery
|
44
|
+
has_many :brews
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "performing brew recipe calculations" do
|
48
|
+
before do
|
49
|
+
@brew = Brew.new()
|
50
|
+
@brew.original_gravity=(1045)
|
51
|
+
@brew.final_gravity=(1012)
|
52
|
+
@brew.fermentation_volume_litres=(25)
|
53
|
+
@brew.boil_time_minutes=(60)
|
54
|
+
|
55
|
+
@brewery = Brewery.new()
|
56
|
+
@brewery.kettle_tax_litres=(2)
|
57
|
+
@brewery.evaporation_rate_litres_per_hour=(11)
|
58
|
+
@brewery.volume_lost_to_mash_litres_per_kg=(0.82)
|
59
|
+
|
60
|
+
@brew.brewery=(@brewery)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should calculate the post boil volume" do
|
64
|
+
@brew.post_boil_volume_litres.should == 27
|
65
|
+
end
|
66
|
+
|
67
|
+
# Mashout volume = Post Boil Volume + (Boil Time Minutes / 60) * evaporation_rate_litres_per_hour
|
68
|
+
it "should calculate the Mash Out/Pre Boil volume given the weight of the total grain bill" do
|
69
|
+
@brew.mash_out_volume_litres.should == 38
|
70
|
+
@brew.pre_boil_volume_litres.should == 38
|
71
|
+
end
|
72
|
+
|
73
|
+
# Mash In volume = Mash Out volume + (volume_lost_to_mash_litres_per_kg * weight of total grain bill)
|
74
|
+
it "should calculate the Mash In volume given the weight of the total grain bill" do
|
75
|
+
@brew.mash_in_volume_litres(6.52).round_dp(2).should == 43.35
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should calculate the bigness factor used for hop utilisation calculations" do
|
79
|
+
@brew.bigness_factor.round_dp(1).should == 1.1
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should calculate the Alcohol By Volume percentage for the completed brew" do
|
83
|
+
@brew.alcohol_by_volume.round_dp(2).should == 5.05
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Confirm test schema is loaded correctly" do
|
4
|
+
before do
|
5
|
+
load_schema
|
6
|
+
end
|
7
|
+
|
8
|
+
class Brewery < ActiveRecord::Base
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should load test schema correctly" do
|
12
|
+
Brewery.all.should eql []
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "Can act_as_brewery" do
|
17
|
+
before do
|
18
|
+
load_schema
|
19
|
+
end
|
20
|
+
|
21
|
+
class Brewery < ActiveRecord::Base
|
22
|
+
acts_as_brewery
|
23
|
+
end
|
24
|
+
|
25
|
+
# Token test to prove the acts_as mechanism is working
|
26
|
+
it "can increase kettle_tax_litres" do
|
27
|
+
brewery = Brewery.new()
|
28
|
+
brewery.kettle_tax_litres=(2.0)
|
29
|
+
brewery.add_litres_to_kettle_tax(2)
|
30
|
+
brewery.kettle_tax_litres.should == 4.0
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Confirm test schema is loaded correctly" do
|
4
|
+
before do
|
5
|
+
load_schema
|
6
|
+
end
|
7
|
+
|
8
|
+
class Fermentable < ActiveRecord::Base
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should load test schema correctly" do
|
12
|
+
Fermentable.all.should eql []
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "Can act_as_fermentable" do
|
17
|
+
before do
|
18
|
+
load_schema
|
19
|
+
end
|
20
|
+
|
21
|
+
class Brew < ActiveRecord::Base
|
22
|
+
acts_as_brew_recipe
|
23
|
+
belongs_to :brewery
|
24
|
+
has_many :fermentables
|
25
|
+
|
26
|
+
def evaporation_rate_litres_per_hour
|
27
|
+
self.brewery.evaporation_rate_litres_per_hour
|
28
|
+
end
|
29
|
+
|
30
|
+
def mash_efficiency_percentage
|
31
|
+
self.brewery.mash_efficiency_percentage
|
32
|
+
end
|
33
|
+
|
34
|
+
def volume_lost_to_mash_litres_per_kg
|
35
|
+
self.brewery.volume_lost_to_mash_litres_per_kg
|
36
|
+
end
|
37
|
+
|
38
|
+
def kettle_tax_litres
|
39
|
+
self.brewery.kettle_tax_litres
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Brewery < ActiveRecord::Base
|
44
|
+
acts_as_brewery
|
45
|
+
has_many :brews
|
46
|
+
end
|
47
|
+
|
48
|
+
class Fermentable < ActiveRecord::Base
|
49
|
+
acts_as_fermentable
|
50
|
+
belongs_to :brew
|
51
|
+
|
52
|
+
def mash_out_volume_litres
|
53
|
+
self.brew.mash_out_volume_litres
|
54
|
+
end
|
55
|
+
|
56
|
+
def post_boil_volume_litres
|
57
|
+
self.brew.post_boil_volume_litres
|
58
|
+
end
|
59
|
+
|
60
|
+
def mash_efficiency_percentage
|
61
|
+
self.brew.brewery.mash_efficiency_percentage
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "performing brew fermentable calculations" do
|
66
|
+
before do
|
67
|
+
@fermentable = Fermentable.new()
|
68
|
+
@fermentable.mash=(true)
|
69
|
+
@fermentable.points_per_kg_per_litre=(300)
|
70
|
+
@fermentable.weight_in_kg=(5.24)
|
71
|
+
|
72
|
+
@brew = Brew.new()
|
73
|
+
@brew.original_gravity=(1045)
|
74
|
+
@brew.final_gravity=(1012)
|
75
|
+
@brew.fermentation_volume_litres=(25)
|
76
|
+
@brew.boil_time_minutes=(60)
|
77
|
+
|
78
|
+
@brewery = Brewery.new()
|
79
|
+
@brewery.kettle_tax_litres=(2)
|
80
|
+
@brewery.evaporation_rate_litres_per_hour=(11)
|
81
|
+
@brewery.volume_lost_to_mash_litres_per_kg=(0.82)
|
82
|
+
@brewery.mash_efficiency_percentage=(61)
|
83
|
+
|
84
|
+
@brew.brewery=(@brewery)
|
85
|
+
|
86
|
+
@fermentable.brew=(@brew)
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "for mashed fermentables, thus factoring in brewery mash efficiency" do
|
90
|
+
it "should calculate the gravity points contributed towards the post boil volume" do
|
91
|
+
@fermentable.post_boil_volume_gravity_points.round_dp(2).should == 35.52
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should calculate the gravity points contributed towards the mash out/pre boil volume" do
|
95
|
+
@fermentable.pre_boil_volume_gravity_points.round_dp(2).should == 25.23
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should calculate the gravity points contributed towards a given volume" do
|
99
|
+
@fermentable.volume_gravity_points(38).round_dp(2).should == 25.23
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "for fermentables (such as cans of goop) which aren't mashed, thus ignoring brewery mash efficiency" do
|
104
|
+
before do
|
105
|
+
@fermentable.mash=(false)
|
106
|
+
@fermentable.points_per_kg_per_litre=(300)
|
107
|
+
@fermentable.weight_in_kg=(1.7)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should calculate the gravity points contributed towards the post boil volume" do
|
111
|
+
@fermentable.post_boil_volume_gravity_points.round_dp(2).should == 18.89
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should calculate the gravity points contributed towards the pre boil volume" do
|
115
|
+
@fermentable.pre_boil_volume_gravity_points.round_dp(2).should == 13.42
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should calculate the gravity points contributed towards a given volume" do
|
119
|
+
@fermentable.volume_gravity_points(25).round_dp(2).should == 20.40
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Confirm test schema is loaded correctly" do
|
4
|
+
before do
|
5
|
+
load_schema
|
6
|
+
end
|
7
|
+
|
8
|
+
class HopAddition < ActiveRecord::Base
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should load test schema correctly" do
|
12
|
+
HopAddition.all.should eql []
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "Can act_as_hop_addition" do
|
17
|
+
before do
|
18
|
+
load_schema
|
19
|
+
end
|
20
|
+
|
21
|
+
class Brew < ActiveRecord::Base
|
22
|
+
acts_as_brew_recipe
|
23
|
+
belongs_to :brewery
|
24
|
+
has_many :fermentables
|
25
|
+
|
26
|
+
def evaporation_rate_litres_per_hour
|
27
|
+
self.brewery.evaporation_rate_litres_per_hour
|
28
|
+
end
|
29
|
+
|
30
|
+
def mash_efficiency_percentage
|
31
|
+
self.brewery.mash_efficiency_percentage
|
32
|
+
end
|
33
|
+
|
34
|
+
def volume_lost_to_mash_litres_per_kg
|
35
|
+
self.brewery.volume_lost_to_mash_litres_per_kg
|
36
|
+
end
|
37
|
+
|
38
|
+
def kettle_tax_litres
|
39
|
+
self.brewery.kettle_tax_litres
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Brewery < ActiveRecord::Base
|
44
|
+
acts_as_brewery
|
45
|
+
has_many :brews
|
46
|
+
end
|
47
|
+
|
48
|
+
class Fermentable < ActiveRecord::Base
|
49
|
+
acts_as_fermentable
|
50
|
+
belongs_to :brew
|
51
|
+
|
52
|
+
def mash_out_volume_litres
|
53
|
+
self.brew.mash_out_volume_litres
|
54
|
+
end
|
55
|
+
|
56
|
+
def post_boil_volume_litres
|
57
|
+
self.brew.post_boil_volume_litres
|
58
|
+
end
|
59
|
+
|
60
|
+
def mash_efficiency_percentage
|
61
|
+
self.brew.brewery.mash_efficiency_percentage
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class HopAddition < ActiveRecord::Base
|
66
|
+
acts_as_hop_addition
|
67
|
+
belongs_to :brew
|
68
|
+
|
69
|
+
def post_boil_volume_litres
|
70
|
+
self.brew.post_boil_volume_litres
|
71
|
+
end
|
72
|
+
|
73
|
+
def original_gravity
|
74
|
+
self.brew.original_gravity
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "performing hop addition calculations" do
|
79
|
+
before do
|
80
|
+
@fermentable = Fermentable.new()
|
81
|
+
@fermentable.mash=(true)
|
82
|
+
@fermentable.points_per_kg_per_litre=(300)
|
83
|
+
@fermentable.weight_in_kg=(5.24)
|
84
|
+
|
85
|
+
@brew = Brew.new()
|
86
|
+
@brew.original_gravity=(1045)
|
87
|
+
@brew.final_gravity=(1012)
|
88
|
+
@brew.fermentation_volume_litres=(25)
|
89
|
+
@brew.boil_time_minutes=(60)
|
90
|
+
|
91
|
+
@brewery = Brewery.new()
|
92
|
+
@brewery.kettle_tax_litres=(2)
|
93
|
+
@brewery.evaporation_rate_litres_per_hour=(11)
|
94
|
+
@brewery.volume_lost_to_mash_litres_per_kg=(0.82)
|
95
|
+
@brewery.mash_efficiency_percentage=(61)
|
96
|
+
|
97
|
+
@hop_addition = HopAddition.new()
|
98
|
+
@hop_addition.alpha_acid_percentage=(7.0)
|
99
|
+
@hop_addition.weight_grams=(30)
|
100
|
+
@hop_addition.boil_time_minutes=(45)
|
101
|
+
|
102
|
+
@brew.brewery=(@brewery)
|
103
|
+
|
104
|
+
@fermentable.brew=(@brew)
|
105
|
+
@hop_addition.brew=(@brew)
|
106
|
+
end
|
107
|
+
|
108
|
+
# mg/l AA => ((AA/100) * weight_grams * 1000) / post_boil_volume
|
109
|
+
# time => (1 - EXP((-0.04 * boil_time_minutes))) / 4.15
|
110
|
+
# IBU = mg/l AA * time * bigness factor
|
111
|
+
it "should calculate International Bitterness Units for the Hop Addition" do
|
112
|
+
@hop_addition.IBU().round_dp(2).should == 17.23
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
data/spec/database.yml
ADDED
data/spec/schema.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 0) do
|
2
|
+
|
3
|
+
create_table "breweries", :force => true do |t|
|
4
|
+
t.string "name"
|
5
|
+
t.string "head_brewer"
|
6
|
+
t.float "mash_efficiency_percentage"
|
7
|
+
t.float "evaporation_rate_litres_per_hour"
|
8
|
+
t.float "volume_lost_to_mash_litres_per_kg"
|
9
|
+
t.float "kettle_tax_litres"
|
10
|
+
t.datetime "created_at"
|
11
|
+
t.datetime "updated_at"
|
12
|
+
end
|
13
|
+
|
14
|
+
create_table "brews", :force => true do |t|
|
15
|
+
t.string "name"
|
16
|
+
t.string "brewer"
|
17
|
+
t.float "original_gravity"
|
18
|
+
t.float "final_gravity"
|
19
|
+
t.float "fermentation_volume_litres"
|
20
|
+
t.integer "boil_time_minutes"
|
21
|
+
t.integer "brewery_id"
|
22
|
+
t.datetime "created_at"
|
23
|
+
t.datetime "updated_at"
|
24
|
+
end
|
25
|
+
|
26
|
+
create_table "fermentables", :force => true do |t|
|
27
|
+
t.string "name"
|
28
|
+
t.boolean "mash"
|
29
|
+
t.float "points_per_kg_per_litre"
|
30
|
+
t.float "weight_in_kg"
|
31
|
+
t.integer "brew_id"
|
32
|
+
t.datetime "created_at"
|
33
|
+
t.datetime "updated_at"
|
34
|
+
end
|
35
|
+
|
36
|
+
create_table "hop_additions", :force => true do |t|
|
37
|
+
t.string "name"
|
38
|
+
t.float "alpha_acid_percentage"
|
39
|
+
t.float "weight_grams"
|
40
|
+
t.float "boil_time_minutes"
|
41
|
+
t.integer "brew_id"
|
42
|
+
t.datetime "created_at"
|
43
|
+
t.datetime "updated_at"
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'zymurgy'
|
6
|
+
require 'spec'
|
7
|
+
require 'spec/autorun'
|
8
|
+
|
9
|
+
require 'spec/expectations'
|
10
|
+
require 'patches/float'
|
11
|
+
|
12
|
+
Spec::Runner.configure do |config|
|
13
|
+
config.include Zymurgy::Utils
|
14
|
+
|
15
|
+
end
|
16
|
+
#require 'active_support'
|
17
|
+
require 'active_record'
|
18
|
+
|
19
|
+
|
20
|
+
def load_schema
|
21
|
+
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
22
|
+
ActiveRecord::Base.establish_connection(config['mysql'])
|
23
|
+
load(File.dirname(__FILE__) + "/schema.rb")
|
24
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
## Zymurgy is a module containing some generic zymurgical calculation methods and classes
|
4
|
+
##
|
5
|
+
|
6
|
+
describe "Zymurgy" do
|
7
|
+
describe "Utils" do
|
8
|
+
|
9
|
+
describe "Performing various metric <=> imperial calculations" do
|
10
|
+
it "should convert litres to US gallons" do
|
11
|
+
litres_2_us_gallons(26.5).round_dp(2).should == 7.00
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should convert US gallons to litres" do
|
15
|
+
us_gallons_2_litres(11).round_dp(1).should == 41.6
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should convert kilograms to pounds" do
|
19
|
+
kilograms_2_pounds(2.73).round_dp(1).should == 6.0
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should convert pounds to kilograms" do
|
23
|
+
pounds_2_kilograms(17).round_dp(2).should == 7.73
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should convert kilograms to ounces" do
|
27
|
+
kilograms_2_ounces(1).round_dp(1).should == 35.3
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should convert ounces to kilograms" do
|
31
|
+
ounces_2_kilograms(10).round_dp(2).should == 0.28
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should convert celsius to fahrenheit" do
|
35
|
+
celsius_2_fahrenheit(10).round_dp(1).should == 50.0
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should convert fahrenheit to celsius" do
|
39
|
+
fahrenheit_2_celsius(120.0).round_dp(2).should == 48.89
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should convert gravity points per kilogram per litre (pkgl) to gravity points per pound per gallon (ppg)" do
|
43
|
+
pkgl_2_ppg(291.45).round_dp(1).should == 35.0
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should convert gravity points per pound per gallon (ppg) to gravity points per kilogram per litre (pkgl)" do
|
47
|
+
ppg_2_pkgl(35.0).round_dp(2).should == 291.48
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/zymurgy.gemspec
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{zymurgy}
|
8
|
+
s.version = "0.10.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Mike Breeze"]
|
12
|
+
s.date = %q{2011-01-10}
|
13
|
+
s.description = %q{(n) The branch of chemistry that deals with fermentation processes, as in brewing.
|
14
|
+
|
15
|
+
Zymurgy is a collection of libraries to help with beer brewing calculations:
|
16
|
+
* Gravity points
|
17
|
+
* Hop utilisation
|
18
|
+
* Boil times and volumes}
|
19
|
+
s.email = %q{breezy@binningup.com}
|
20
|
+
s.extra_rdoc_files = [
|
21
|
+
"LICENSE",
|
22
|
+
"README.rdoc"
|
23
|
+
]
|
24
|
+
s.files = [
|
25
|
+
".document",
|
26
|
+
"LICENSE",
|
27
|
+
"README.rdoc",
|
28
|
+
"Rakefile",
|
29
|
+
"VERSION",
|
30
|
+
"lib/zymurgy.rb",
|
31
|
+
"lib/zymurgy/acts_as_brew_recipe.rb",
|
32
|
+
"lib/zymurgy/acts_as_brewery.rb",
|
33
|
+
"lib/zymurgy/acts_as_fermentable.rb",
|
34
|
+
"lib/zymurgy/acts_as_hop_addition.rb",
|
35
|
+
"lib/zymurgy/utils.rb",
|
36
|
+
"spec/acts_as_brew_recipe_spec.rb",
|
37
|
+
"spec/acts_as_brewery_spec.rb",
|
38
|
+
"spec/acts_as_fermentable_spec.rb",
|
39
|
+
"spec/acts_as_hop_addition_spec.rb",
|
40
|
+
"spec/database.yml",
|
41
|
+
"spec/patches/float.rb",
|
42
|
+
"spec/schema.rb",
|
43
|
+
"spec/spec_helper.rb",
|
44
|
+
"spec/zymurgy_utils_spec.rb",
|
45
|
+
"zymurgy.gemspec"
|
46
|
+
]
|
47
|
+
s.homepage = %q{http://github.com/breezy/zymurgy}
|
48
|
+
s.require_paths = ["lib"]
|
49
|
+
s.rubygems_version = %q{1.3.7}
|
50
|
+
s.summary = %q{A beer brewing gem}
|
51
|
+
s.test_files = [
|
52
|
+
"spec/acts_as_brew_recipe_spec.rb",
|
53
|
+
"spec/acts_as_brewery_spec.rb",
|
54
|
+
"spec/acts_as_fermentable_spec.rb",
|
55
|
+
"spec/acts_as_hop_addition_spec.rb",
|
56
|
+
"spec/patches/float.rb",
|
57
|
+
"spec/schema.rb",
|
58
|
+
"spec/spec_helper.rb",
|
59
|
+
"spec/zymurgy_utils_spec.rb"
|
60
|
+
]
|
61
|
+
|
62
|
+
if s.respond_to? :specification_version then
|
63
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
64
|
+
s.specification_version = 3
|
65
|
+
|
66
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
67
|
+
s.add_development_dependency(%q<rspec>, [">= 1.2.8"])
|
68
|
+
else
|
69
|
+
s.add_dependency(%q<rspec>, [">= 1.2.8"])
|
70
|
+
end
|
71
|
+
else
|
72
|
+
s.add_dependency(%q<rspec>, [">= 1.2.8"])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
metadata
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: zymurgy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 55
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 10
|
9
|
+
- 0
|
10
|
+
version: 0.10.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Mike Breeze
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-01-10 00:00:00 +11:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 15
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 2
|
33
|
+
- 8
|
34
|
+
version: 1.2.8
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id001
|
37
|
+
description: |-
|
38
|
+
(n) The branch of chemistry that deals with fermentation processes, as in brewing.
|
39
|
+
|
40
|
+
Zymurgy is a collection of libraries to help with beer brewing calculations:
|
41
|
+
* Gravity points
|
42
|
+
* Hop utilisation
|
43
|
+
* Boil times and volumes
|
44
|
+
email: breezy@binningup.com
|
45
|
+
executables: []
|
46
|
+
|
47
|
+
extensions: []
|
48
|
+
|
49
|
+
extra_rdoc_files:
|
50
|
+
- LICENSE
|
51
|
+
- README.rdoc
|
52
|
+
files:
|
53
|
+
- .document
|
54
|
+
- LICENSE
|
55
|
+
- README.rdoc
|
56
|
+
- Rakefile
|
57
|
+
- VERSION
|
58
|
+
- lib/zymurgy.rb
|
59
|
+
- lib/zymurgy/acts_as_brew_recipe.rb
|
60
|
+
- lib/zymurgy/acts_as_brewery.rb
|
61
|
+
- lib/zymurgy/acts_as_fermentable.rb
|
62
|
+
- lib/zymurgy/acts_as_hop_addition.rb
|
63
|
+
- lib/zymurgy/utils.rb
|
64
|
+
- spec/acts_as_brew_recipe_spec.rb
|
65
|
+
- spec/acts_as_brewery_spec.rb
|
66
|
+
- spec/acts_as_fermentable_spec.rb
|
67
|
+
- spec/acts_as_hop_addition_spec.rb
|
68
|
+
- spec/database.yml
|
69
|
+
- spec/patches/float.rb
|
70
|
+
- spec/schema.rb
|
71
|
+
- spec/spec_helper.rb
|
72
|
+
- spec/zymurgy_utils_spec.rb
|
73
|
+
- zymurgy.gemspec
|
74
|
+
has_rdoc: true
|
75
|
+
homepage: http://github.com/breezy/zymurgy
|
76
|
+
licenses: []
|
77
|
+
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
hash: 3
|
89
|
+
segments:
|
90
|
+
- 0
|
91
|
+
version: "0"
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
hash: 3
|
98
|
+
segments:
|
99
|
+
- 0
|
100
|
+
version: "0"
|
101
|
+
requirements: []
|
102
|
+
|
103
|
+
rubyforge_project:
|
104
|
+
rubygems_version: 1.3.7
|
105
|
+
signing_key:
|
106
|
+
specification_version: 3
|
107
|
+
summary: A beer brewing gem
|
108
|
+
test_files:
|
109
|
+
- spec/acts_as_brew_recipe_spec.rb
|
110
|
+
- spec/acts_as_brewery_spec.rb
|
111
|
+
- spec/acts_as_fermentable_spec.rb
|
112
|
+
- spec/acts_as_hop_addition_spec.rb
|
113
|
+
- spec/patches/float.rb
|
114
|
+
- spec/schema.rb
|
115
|
+
- spec/spec_helper.rb
|
116
|
+
- spec/zymurgy_utils_spec.rb
|