require 'units/units' require 'eymiha_math' require 'approximately_equals' # Numerics are extended to allow them to be united with units. # # Part of this extension is in the added dynamism of the class. During # unit definition, if an unencountered unit is referenced, the use is held # until more information is loaded into the system and the unknown unit has # been resolved. During use, unencountered units are raised. class Numeric alias :method_missing_before_units :method_missing def method_missing(method,*args) # :nodoc: if Units.defining? reference = Units.make_forward_reference(method,Units.defining?) begin value = Units.convert self, method Units.release_forward_reference reference value rescue MissingUnitsException Units.hold_forward_reference rescue UnitsException => exception units_problem("definition",exception,method,args) rescue Exception => exception method_missing_before_units(method,args) end else begin ps = method.to_s.split '_per_' case ps.size when 1 then unite method when 2 then unite(ps[0])/(1.unite(ps[1])) else raise UnitsException('invalid per method') end rescue UnitsException => exception units_problem("usage",exception,method,args) rescue Exception method_missing_before_units(method,*args) end end end # Returns a NumericWithUnits whose numeric value is the value of the # instance, and whose unit is determined from the provided unit and power in # the context of a given measure: # * as a String or Symbol equal to the singular, plural or abbreviated name of a unit, # * as a UnitsHash, # * as the unit part of a NumericWithUnits, # * as an Array of any of the above. def unite(unit=nil,power=1,measure=nil) if !unit self else if (unit.kind_of? Array) units = UnitsHash.new unit.each {|u| units.merge! 1.unite(u)} unit = units elsif (unit.kind_of? String)||(unit.kind_of? Symbol) s = unit.to_s as = s.split('_and_') if as.size == 1 units = Units.lookup(as[0]) case units.size when 1 then unit = units[0] when 0 then as = as[0].split('_') units_problem("usage", AmbiguousUnitsException.new(unit), :unit=,unit) if as.size == 0 unit = unite(as,power,measure).unit else units_problem("usage", AmbiguousUnitsException.new(unit), :unit=,unit) end else unit = unite(as,power,measure).unit end elsif unit.kind_of? NumericWithUnits unit = unit.unit end NumericWithUnits.new(self,unit,power) end end end