diff --git a/lib/beerxml/hop.rb b/lib/beerxml/hop.rb index 385b43c..98d2de5 100644 --- a/lib/beerxml/hop.rb +++ b/lib/beerxml/hop.rb @@ -21,11 +21,11 @@ class Beerxml::Hop < Beerxml::Model property :id, Serial belongs_to :recipe, :required => false - def tinseth(post_boil_og, batch_size) # batch size is gallons for now + def tinseth(post_boil_og, batch_size) # batch size is gallons or Unit bigness = 1.65 * 0.000125**(post_boil_og - 1) boil_factor = (1 - 2.72 ** (-0.04 * time.in_minutes.to_f)) / 4.15 utilization = bigness * boil_factor - ibus = utilization * (aau * 0.01 * 7490) / batch_size + ibus = utilization * (aau * 0.01 * 7490) / U(batch_size, 'gallons').to_f ibus.round end alias_method :ibus, :tinseth diff --git a/lib/beerxml/recipe.rb b/lib/beerxml/recipe.rb index e344ccc..ccb6b14 100644 --- a/lib/beerxml/recipe.rb +++ b/lib/beerxml/recipe.rb @@ -45,4 +45,9 @@ class Beerxml::Recipe < Beerxml::Model # these are not used in the xml property :id, Serial + + def tinseth + hops.inject(0) { |v, h| v + h.tinseth(og, batch_size) }.round + end + alias_method :ibus, :tinseth end diff --git a/lib/beerxml/unit.rb b/lib/beerxml/unit.rb index 7e41453..cd4b333 100644 --- a/lib/beerxml/unit.rb +++ b/lib/beerxml/unit.rb @@ -1,6 +1,7 @@ +module Beerxml # Unit system with conversions between units of the same type. Very much # a work in progress. -class Beerxml::Unit +class Unit attr_reader :type, :unit Units = {} @@ -22,6 +23,7 @@ def in!(new_unit, *args) @unit = new_unit self end + alias_method :to!, :in! alias_method :unit=, :in! def base_unit @@ -33,7 +35,13 @@ def to_f end def initialize(amount, unit = nil) - if !unit + if amount.is_a?(Unit) + if unit + amount = amount.to(unit).to_f + else + amount, unit = amount.to_f, amount.unit + end + elsif !unit amount, unit = amount.to_s.split(/\s+/, 2) end unit = unit.to_s @@ -117,6 +125,7 @@ def self.included(k) module Volume def self.included(k) k.add_type('volume', 'liters', 'l', 'liter') + k.add('volume', 0.26417, 'gallons', 'gallon') end end include Volume @@ -138,6 +147,7 @@ def self.included(k) end include Temperature end +end def U(*a) Beerxml::Unit.new(*a) diff --git a/spec/parsing_spec.rb b/spec/parsing_spec.rb index 8c8cd4f..39707ab 100644 --- a/spec/parsing_spec.rb +++ b/spec/parsing_spec.rb @@ -1,16 +1,6 @@ require "#{File.dirname(__FILE__)}/spec_helper" describe "beerxml.com examples" do - def filename(example) - "examples/beerxml.com/#{example}.xml" - end - def read_file(example) - File.read(filename(example)) - end - def read_xml(example) - Nokogiri::XML(read_file(example)) - end - it "should parse the first recipe and its hops" do recipe = Beerxml::Recipe.new.from_xml(read_xml("recipes").root.children[1]) diff --git a/spec/recipes_spec.rb b/spec/recipes_spec.rb new file mode 100644 index 0000000..ea6c7cc --- /dev/null +++ b/spec/recipes_spec.rb @@ -0,0 +1,9 @@ +require "#{File.dirname(__FILE__)}/spec_helper" + +describe Beerxml::Recipe do + it "should calculate IBUs using the tinseth method" do + recipe = Beerxml::Recipe.new.from_xml(read_xml("recipes").root.children[1]) + recipe.should be_valid + recipe.ibus.should == 44 + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0a6e037..b35c1fc 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -3,4 +3,13 @@ require 'rspec' RSpec.configure do |c| + def filename(example) + "examples/beerxml.com/#{example}.xml" + end + def read_file(example) + File.read(filename(example)) + end + def read_xml(example) + Nokogiri::XML(read_file(example)) + end end diff --git a/spec/units_spec.rb b/spec/units_spec.rb index 39e7606..6309945 100644 --- a/spec/units_spec.rb +++ b/spec/units_spec.rb @@ -41,6 +41,17 @@ def near?(rhs, prec = 0.01) w.should == U('53.97 oz') end + it "should allow constructing from another compatible Unit object" do + w = U(53.97, 'oz') + w2 = U(w) # defaults to oz, same units as copying object + w3 = U(w, 'kg') + w.should == w2 + w.should == w3 + w2.should == w3 + w2.should == 53.97 + w3.should == 1.53 + end + describe "equality" do it "should compare between units" do w = U(3.5, 'kg')