diff --git a/lib/quantity.rb b/lib/quantity.rb index 2b416da..3fbfabf 100644 --- a/lib/quantity.rb +++ b/lib/quantity.rb @@ -73,12 +73,12 @@ def initialize(value, unit = nil ) @reference_value = value[:reference_value] || (value[:value] * @unit.value) @value = @unit.value_for(@reference_value) #dimension.reference.convert_proc(@unit).call(@reference_value) #@value = @unit.convert_proc(@unit).call(@reference_value) - when Numeric + when Numeric, String @unit = Unit.for(unit) if @unit.nil? @unit = Unit.from_string_form(unit) end - @value = value + @value = value.is_a?(Numeric) ? value : value.to_f @reference_value = value * @unit.value end end @@ -133,10 +133,10 @@ def coerce(other) def +(other) if (other.is_a?(Numeric)) Quantity.new(@value + other, @unit) - elsif(other.is_a?(Quantity) && @unit.dimension == other.unit.dimension) + elsif compatible_with?(other) Quantity.new({:unit => @unit,:reference_value => @reference_value + other.reference_value}) else - raise ArgumentError,"Cannot add #{self} to #{other}" + raise ArgumentError,"Cannot add #{self} (#{@unit.dimension}) to #{other} (#{other.class}" + (other.is_a?(Quantity) ? "-#{other.unit.dimension})" : ')') end end @@ -147,10 +147,10 @@ def +(other) def -(other) if (other.is_a?(Numeric)) Quantity.new(@value - other, @unit) - elsif(other.is_a?(Quantity) && @unit.dimension == other.unit.dimension) + elsif compatible_with?(other) Quantity.new({:unit => @unit,:reference_value => @reference_value - other.reference_value}) else - raise ArgumentError, "Cannot subtract #{other} from #{self}" + raise ArgumentError, "Cannot subtract #{other} (#{other.class}) from #{self} (#{@unit.dimension})" end end @@ -161,7 +161,7 @@ def -(other) def <=>(other) if (other.is_a?(Numeric)) @value <=> other - elsif(other.is_a?(Quantity) && measures == other.measures) + elsif compatible_with?(other) @reference_value <=> other.reference_value else nil @@ -279,6 +279,11 @@ def to_f @value.to_f end + def compatible_with?(other) + return false if unit.nil? + other.respond_to?(:unit) && unit.compatible_with?(other.unit) + end + # Round this value to the nearest integer # @return [Quantity] def round diff --git a/lib/quantity/dimension.rb b/lib/quantity/dimension.rb index 325c20b..d7d64fc 100644 --- a/lib/quantity/dimension.rb +++ b/lib/quantity/dimension.rb @@ -178,6 +178,12 @@ def <=>(other) end end + + def compatible_with?(other) + self === other || (other.respond_to?(:name) && name == other.name) + end + + # Returns a developer-friendly representation of this value. # # The string will be of the format `#`, diff --git a/lib/quantity/unit.rb b/lib/quantity/unit.rb index 0f060c6..7994f3a 100644 --- a/lib/quantity/unit.rb +++ b/lib/quantity/unit.rb @@ -294,7 +294,7 @@ def calculate_value @dimension.numerators.each do | component | component.power.times do # we might have a unit for a compound dimension, such as liters for length^3. - value *= @units[Quantity::Dimension.for(component.dimension)].value + value *= @units[Quantity::Dimension.for(component.dimension)].value if @units[Quantity::Dimension.for(component.dimension)] end end @dimension.denominators.each do | component | @@ -305,6 +305,12 @@ def calculate_value @value = value end + + def compatible_with?(other) + other.respond_to?(:dimension) && dimension.compatible_with?(other.dimension) + end + + # A vaguely human-readable form for this unit # @return [String] def string_form