lib/stick/units/base.rb in stick-1.3.1 vs lib/stick/units/base.rb in stick-1.3.2

- old
+ new

@@ -67,38 +67,37 @@ # K C F R D N R R # # http://en.wikipedia.org/wiki/Conversion_of_units #++ -module Stick module Units def method_missing(m, *args, &blk) if args.length == 1 - args[0] = (::Stick::Units::Converter.converter(args[0]) rescue nil) if not args[0].is_a? ::Stick::Units::Converter - return ::Stick::Units::Unit.new({m => 1}, args[0]) if args[0] && args[0].registered?(m) - elsif (::Stick::Units::Converter.current.registered?(m) rescue false) + args[0] = (::Units::Converter.converter(args[0]) rescue nil) if not args[0].is_a? ::Units::Converter + return ::Units::Unit.new({m => 1}, args[0]) if args[0] && args[0].registered?(m) + elsif (::Units::Converter.current.registered?(m) rescue false) raise ::ArgumentError, "Wrong number of arguments" if args.length != 0 - return ::Stick::Units::Unit.new({m => 1}, ::Stick::Units::Converter.current) + return ::Units::Unit.new({m => 1}, ::Units::Converter.current) end ::Exception.with_clean_backtrace("method_missing") { super } end def const_missing(c) - if (::Stick::Units::Converter.current.registered?(c) rescue false) - return ::Stick::Units::Unit.new({c => 1}, ::Stick::Units::Converter.current) + if (::Units::Converter.current.registered?(c) rescue false) + return ::Units::Unit.new({c => 1}, ::Units::Converter.current) else ::Exception.with_clean_backtrace("const_missing") { super } end end def self.append_features(m) - m.send(:extend, ::Stick::Units) + m.send(:extend, ::Units) super end # Executes the block with the current Converter changed to # the given Converter. This allows to temporarily change the @@ -115,11 +114,11 @@ # puts 1.cwt.to(lb) # => 100.0 lb # } # # See also Converter.current. def with_unit_converter(name, &blk) # :yields: - ::Stick::Units::Converter.with_converter(name, &blk) + ::Units::Converter.with_converter(name, &blk) end module_function :with_unit_converter class Regexps @@ -136,11 +135,11 @@ class BaseUnit attr_reader :name, :converter - def initialize(name, converter = ::Stick::Units::Converter.current) + def initialize(name, converter = ::Units::Converter.current) name = name.to_sym raise ::ArgumentError, "unit #{name.to_s.dump} not registered with #{converter}" if not converter.registered? name @name = name @converter = converter end @@ -148,21 +147,21 @@ def conversion @converter.send(:conversions, @name) end def ==(other) - other.is_a?(::Stick::Units::BaseUnit) && other.name == @name && other.converter == @converter + other.is_a?(::Units::BaseUnit) && other.name == @name && other.converter == @converter end alias eql? == def hash @name.hash ^ @converter.hash end def to_s - if ::Stick::Units::Converter.current.includes?(converter) + if ::Units::Converter.current.includes?(converter) @name.to_s else "#{@converter}:#{@name}" end end @@ -170,17 +169,17 @@ alias inspect to_s end # This class represents a Unit. A Unit uses a given Converter with - # a number of registered Stick in which it can be expressed. - # A Unit is the product of the powers of other Stick. In principle, these + # a number of registered units in which it can be expressed. + # A Unit is the product of the powers of other units. In principle, these # need not be integer powers, but this may cause problems with rounding. # The following code for example returns +false+: # Unit.new(:m => 0.1) * Unit.new(:m => 0.2) == Unit.new(:m => 0.3) # - # Stick can be multiplied, divided, and raised to a given power. + # Units can be multiplied, divided, and raised to a given power. # As an extra, 1 can be divided by a Unit. # # Examples: # # Unit.new(:mi => 1, :s => -1) ** 2 # => mi**2/s**2 @@ -201,17 +200,17 @@ # Unit.new(:m => 1, :s => -1, Converter.converter(:uk)) # => m/s # Unit.new(:mi => 1, :s => -2) # => mi/s**2 # # See also Converter, Converter.converter def initialize(units = {}, converter = nil) - conv = proc { converter ||= ::Stick::Units::Converter.current } + conv = proc { converter ||= ::Units::Converter.current } if units.is_a? ::String @units = decode_string(units, conv) else @units = {} units.each_pair do |k, v| - k = conv[].base_unit(k.to_sym) if not k.is_a? ::Stick::Units::BaseUnit + k = conv[].base_unit(k.to_sym) if not k.is_a? ::Units::BaseUnit @units[k] = v end end normalize_units end @@ -220,11 +219,11 @@ def **(p) result = {} @units.each_pair do |u, e| result[u] = e * p end - ::Stick::Units::Unit.new(result) + ::Units::Unit.new(result) end # Multiplies with the given Unit. def *(other) do_op(:*, :+, other) @@ -239,22 +238,22 @@ def unitless? @units.empty? end def coerce(other) # :nodoc: - return [::Stick::Units::Unit.new({}), self] if other == 1 - ::Stick::Units::Converter.coerce_units(self, other) + return [::Units::Unit.new({}), self] if other == 1 + ::Units::Converter.coerce_units(self, other) end def simplify - ::Stick::Units::Converter.simplify_unit(self) + ::Units::Converter.simplify_unit(self) end # Returns +true+ iff the two units are equals, <i>i.e.,</i> iff they have # the same exponent for all units, and they both use the same Converter. def ==(other) - other.is_a?(::Stick::Units::Unit) && other.units == units + other.is_a?(::Units::Unit) && other.units == units end alias eql? == def hash @@ -263,11 +262,11 @@ # Returns +true+ iff this Unit is compatible with the given # Unit. This is less strict than equality because for example hours are # compatible with seconds ("we can add them"), but hours are not seconds. def compatible_with?(other) - conv1, conv2 = ::Stick::Units::Converter.coerce_units(self, other) + conv1, conv2 = ::Units::Converter.coerce_units(self, other) conv1.units == conv2.units end # Returns a human readable string representation. def to_s @@ -287,25 +286,25 @@ alias inspect to_s def method_missing(m, *args, &blk) if args.length == 1 - args[0] = (::Stick::Units::Converter.converter(args[0]) rescue nil) if not args[0].is_a? ::Stick::Units::Converter - return self * ::Stick::Units::Unit.new({m => 1}, args[0]) if args[0] && args[0].registered?(m) - elsif (::Stick::Units::Converter.current.registered?(m) rescue false) + args[0] = (::Units::Converter.converter(args[0]) rescue nil) if not args[0].is_a? ::Units::Converter + return self * ::Units::Unit.new({m => 1}, args[0]) if args[0] && args[0].registered?(m) + elsif (::Units::Converter.current.registered?(m) rescue false) raise ::ArgumentError, "Wrong number of arguments" if args.length != 0 - return self * ::Stick::Units::Unit.new({m => 1}, ::Stick::Units::Converter.current) + return self * ::Units::Unit.new({m => 1}, ::Units::Converter.current) end ::Exception.with_clean_backtrace("method_missing") { super } end private def decode_string(s, converter) - if ::Stick::Units::Regexps::TOTAL_UNIT_REGEXP =~ s + if ::Units::Regexps::TOTAL_UNIT_REGEXP =~ s numerator, denominator = $1, $2 units = {} decode_multiplicative_string(numerator, 1, converter, units) if numerator decode_multiplicative_string(denominator, -1, converter, units) if denominator units @@ -315,13 +314,13 @@ raise ::ArgumentError, "Illegal unit string #{s.dump}" end end def decode_multiplicative_string(s, multiplier, converter, result) - s.scan(::Stick::Units::Regexps::SINGLE_UNIT_REGEXP) do |conv, unit, exp| + s.scan(::Units::Regexps::SINGLE_UNIT_REGEXP) do |conv, unit, exp| if unit - conv = ::Stick::Units::Converter.converter(conv) + conv = ::Units::Converter.converter(conv) else conv, unit = converter[], conv end exp ||= '1' unit = conv.base_unit(unit) @@ -335,17 +334,17 @@ end end def do_op(op, dual_op, other) other = other.to_unit - raise TypeError, "cannot convert to Unit" unless ::Stick::Units::Unit === other + raise TypeError, "cannot convert to Unit" unless ::Units::Unit === other result = @units.dup other.units.each_pair do |u, e| result[u] = 0 if not result[u] result[u] = result[u].send(dual_op, e) end - ::Stick::Units::Unit.new(result) + ::Units::Unit.new(result) end end # This class represents a Value with a numeric value and a Unit. @@ -412,26 +411,26 @@ end %w{ * / }.each do |op| eval %{ def #{op}(other) - ::Stick::Units::Value.new(*do_multiplicative_op(:#{op}, other)) + ::Units::Value.new(*do_multiplicative_op(:#{op}, other)) end } end %w{ + - modulo remainder % }.each do |op| eval %{ def #{op}(other) - ::Stick::Units::Value.new(*do_additive_op(:#{op}, other)) + ::Units::Value.new(*do_additive_op(:#{op}, other)) end } end def divmod(other) (q, r), unit = *do_additive_op(:divmod, other) - [q, ::Stick::Units::Value.new(r, unit)] + [q, ::Units::Value.new(r, unit)] end def div(other) do_additive_op(:div, other)[0] end @@ -443,11 +442,11 @@ def +@ # :nodoc: self end def **(other) # :nodoc: - ::Stick::Units::Value.new(@value ** other, @unit ** other) + ::Units::Value.new(@value ** other, @unit ** other) end def <=>(other) # :nodoc: if other == 0 @value <=> 0 @@ -465,11 +464,11 @@ end %w{ abs ceil floor next round succ truncate }.each do |op| eval %{ def #{op} - ::Stick::Units::Value.new(@value.#{op}, @unit) + ::Units::Value.new(@value.#{op}, @unit) end } end %w{ finite? infinite? integer? nan? nonzero? zero? }.each do |op| @@ -485,20 +484,20 @@ # and the given Unit are the same. It obviously fails if the # Units are not compatible (can't add apples and oranges). def to(to_unit, converter = nil) raise ArgumentError, "Wrong number of arguments" if converter && !(::String === to_unit) to_unit = to_unit.to_unit(converter) - raise TypeError, "cannot convert to Unit" unless ::Stick::Units::Unit === to_unit + raise TypeError, "cannot convert to Unit" unless ::Units::Unit === to_unit conv1, conv2 = unit.coerce(to_unit) raise TypeError, "incompatible units for operation" if conv1.units != conv2.units mult = conv1.multiplier / conv2.multiplier - ::Stick::Units::Value.new(value * mult, to_unit) + ::Units::Value.new(value * mult, to_unit) end def coerce(other) # :nodoc: if ::Numeric === other - [::Stick::Units::Value.new!(other, ::Stick::Units::Unit.new), self] + [::Units::Value.new!(other, ::Units::Unit.new), self] else super end end @@ -509,33 +508,33 @@ # Returns a float if this Value is unitless, and raises an # exception otherwise. def to_f val = simplify - if ::Stick::Units::Value === val + if ::Units::Value === val raise TypeError, "Cannot convert to float" else val.to_f end end # Returns an int if this Value is unitless, and raises an # exception otherwise. def to_i val = simplify - if ::Stick::Units::Value === val + if ::Units::Value === val raise TypeError, "Cannot convert to integer" else val.to_i end end # Returns an int if this Value is unitless, and raises an # exception otherwise. def to_int val = simplify - if ::Stick::Units::Value === val + if ::Units::Value === val raise TypeError, "Cannot convert to integer" else val.to_int end end @@ -545,11 +544,11 @@ def simplify mul, new_unit = *@unit.simplify if new_unit.unitless? @value * mul else - ::Stick::Units::Value.new(@value * mul, new_unit) + ::Units::Value.new(@value * mul, new_unit) end end # Returns +self+. def to_value(converter = nil) @@ -558,37 +557,37 @@ alias inspect to_s def method_missing(m, *args, &blk) if args.length == 1 - args[0] = (::Stick::Units::Converter.converter(args[0]) rescue nil) if not args[0].is_a? ::Stick::Units::Converter - return self * ::Stick::Units::Value.new(1, ::Stick::Units::Unit.new({m => 1}, args[0])) if args[0] && args[0].registered?(m) - elsif (::Stick::Units::Converter.current.registered?(m) rescue false) + args[0] = (::Units::Converter.converter(args[0]) rescue nil) if not args[0].is_a? ::Units::Converter + return self * ::Units::Value.new(1, ::Units::Unit.new({m => 1}, args[0])) if args[0] && args[0].registered?(m) + elsif (::Units::Converter.current.registered?(m) rescue false) raise ::ArgumentError, "Wrong number of arguments" if args.length != 0 - return self * ::Stick::Units::Value.new(1, ::Stick::Units::Unit.new({m => 1}, ::Stick::Units::Converter.current)) + return self * ::Units::Value.new(1, ::Units::Unit.new({m => 1}, ::Units::Converter.current)) end ::Exception.with_clean_backtrace("method_missing") { super } end private def self.decode_string(s, converter) - if m = ::Stick::Units::Regexps::VALUE_REGEXP.match(s) + if m = ::Units::Regexps::VALUE_REGEXP.match(s) value = m[2].empty? ? Integer(m[1]) : Float(m[1]) - unit = ::Stick::Units::Unit.new(m[3], converter) + unit = ::Units::Unit.new(m[3], converter) [value, unit] else raise ::ArgumentError, "Illegal value string #{s.dump}" end end def do_additive_op(op, other) other = other.to_value - raise TypeError, "cannot convert to Value" unless ::Stick::Units::Value === other - if other.is_a? ::Stick::Units::Value + raise TypeError, "cannot convert to Value" unless ::Units::Value === other + if other.is_a? ::Units::Value conv1, conv2 = unit.coerce(other.unit) raise TypeError, "incompatible units for #{op}" if conv1.units != conv2.units mult = conv2.multiplier / conv1.multiplier if mult > 1 [value.send(op, other.value * mult), unit] @@ -601,22 +600,22 @@ end end def do_multiplicative_op(op, other) case other - when ::Stick::Units::Value + when ::Units::Value [value.send(op, other.value), unit.send(op, other.unit)] - when ::Stick::Units::Unit + when ::Units::Unit [value, unit.send(op, other)] when ::Numeric [value.send(op, other), unit] else - # TODO: How to make this work for Stick as well? + # TODO: How to make this work for Units as well? # Problem : how check whether to_value failed without # masking all exceptions? other = other.to_value - raise TypeError, "cannot convert to Value" unless ::Stick::Units::Value === other + raise TypeError, "cannot convert to Value" unless ::Units::Value === other do_multiplicative_op(op, other) end end end @@ -671,20 +670,20 @@ end # Included the given converter in the receiver, unless it # was already included. def include(conv) - conv = ::Stick::Units::Converter.converter(conv) if not conv.is_a?(::Stick::Units::Converter) + conv = ::Units::Converter.converter(conv) if not conv.is_a?(::Units::Converter) raise "Circular include" if conv.includes?(self) @included << conv if not includes? conv self end # Returns whether the given converter was included in the # receiver. def includes?(conv) - conv = ::Stick::Units::Converter.converter(conv) if not conv.is_a?(::Stick::Units::Converter) + conv = ::Units::Converter.converter(conv) if not conv.is_a?(::Units::Converter) return true if conv == self @included.each do |c| return true if conv == c || c.includes?(conv) end false @@ -712,11 +711,11 @@ end # Returns the base unit with this name def base_unit(name) if conv = registered?(name) - return ::Stick::Units::BaseUnit.new(name, conv) + return ::Units::BaseUnit.new(name, conv) end raise "unit #{name.to_s.dump} not registered with #{self}" end # Returns the list of registered unit names as symbols. @@ -726,11 +725,11 @@ # def method_missing(m, *args, &blk) if registered?(m) raise ::ArgumentError, "Wrong number of arguments" if args.length != 0 - return ::Stick::Units::Unit.new({m => 1}, self) + return ::Units::Unit.new({m => 1}, self) end ::Exception.with_clean_backtrace("method_missing") { super } end @@ -792,16 +791,16 @@ unit_sym = unit.to_sym prefixes.each_pair do |pre,info| abbrev = info[:abbrev] multiplier = info[:multiplier] || 1 power = info[:power] || 1 - register_unit(pre + unit, :equals => {:unit => ::Stick::Units::Unit.new({unit_sym => power}, self), :multiplier => multiplier}) + register_unit(pre + unit, :equals => {:unit => ::Units::Unit.new({unit_sym => power}, self), :multiplier => multiplier}) aliases.each do |a| - register_unit(pre + a, :equals => {:unit => ::Stick::Units::Unit.new({unit_sym => power}, self), :multiplier => multiplier}) + register_unit(pre + a, :equals => {:unit => ::Units::Unit.new({unit_sym => power}, self), :multiplier => multiplier}) end abbrevs.each do |a| - register_unit(abbrev + a, :equals => {:unit => ::Stick::Units::Unit.new({unit_sym => power}, self), :multiplier => multiplier}) + register_unit(abbrev + a, :equals => {:unit => ::Units::Unit.new({unit_sym => power}, self), :multiplier => multiplier}) end end end def extract_data(unit, data, conv) @@ -818,21 +817,21 @@ if not data.is_a? ::String return {:unit => data[:unit] || data['unit'], :multiplier => data[:multiplier] || data['multiplier']} end if /^\s*1\s*\// =~ data - {:unit => ::Stick::Units::Unit.new(data, self)} - elsif m = /^\s*#{::Stick::Units::Regexps::NUMBER_REGEXP}(?:\s+(\S.*)$|\s*$)/.match(data) - unit = m[3] ? ::Stick::Units::Unit.new(m[3], self) : ::Stick::Units::Unit.new({}, self) + {:unit => ::Units::Unit.new(data, self)} + elsif m = /^\s*#{::Units::Regexps::NUMBER_REGEXP}(?:\s+(\S.*)$|\s*$)/.match(data) + unit = m[3] ? ::Units::Unit.new(m[3], self) : ::Units::Unit.new({}, self) if m[1] multiplier = m[2].empty? ? Integer(m[1]) : Float(m[1]) {:unit => unit, :multiplier => multiplier} else {:unit => unit} end else - {:unit => ::Stick::Units::Unit.new(data, self)} + {:unit => ::Units::Unit.new(data, self)} end end # Checks whether the unit with the given name is registered. # The name can be a symbol or a string. @@ -845,35 +844,37 @@ @conversions[unit] #|| (unit == :'--base-currency--' ? :none : nil) end class << self + THREAD_REFERENCE = 'Units::converter'.to_sym + private :new # Returns the current Converter in the current Thread. # The default converter is the one returned by <code>converter(:default)</code>. - # See also Stick::Units#with_converter and Converter.converter. + # See also Units#with_converter and Converter.converter. def current - Thread.current[:'Stick::Units::converter'] ||= converter(:default) + Thread.current[THREAD_REFERENCE] ||= converter(:default) end def with_converter(conv) # :nodoc: - conv = converter(conv) if not conv.is_a? ::Stick::Units::Converter - raise ::ArgumentError, "Converter expected" if not conv.is_a? ::Stick::Units::Converter + conv = converter(conv) if not conv.is_a? ::Units::Converter + raise ::ArgumentError, "Converter expected" if not conv.is_a? ::Units::Converter begin - old_conv = Thread.current[:'Stick::Units::converter'] + old_conv = Thread.current[THREAD_REFERENCE] if old_conv new_conv = Converter.send(:new, nil) new_conv.include(old_conv) new_conv.include(conv) else new_conv = conv end - Thread.current[:'Stick::Units::converter'] = new_conv + Thread.current[THREAD_REFERENCE] = new_conv yield ensure - Thread.current[:'Stick::Units::converter'] = old_conv + Thread.current[THREAD_REFERENCE] = old_conv end end # Returns the converter with the given name. # This name can be a Symbol or a String. @@ -917,11 +918,11 @@ base_units = {} other_units = {} units.each_pair do |u, e| (u.conversion != :none ? other_units : base_units)[u] = e end - result = Conversion.new(::Stick::Units::Unit.new(base_units, self), multiplier) + result = Conversion.new(::Units::Unit.new(base_units, self), multiplier) other_units.each_pair do |u, e| result *= (u.conversion ** e) end result end @@ -942,40 +943,39 @@ SYSTEMDIR = File.dirname(__FILE__) CONFIGDIR = File.join(SYSTEMDIR, 'data') end end -end class Numeric # def method_missing(m, *args, &blk) if args.length == 1 - args[0] = (::Stick::Units::Converter.converter(args[0]) rescue nil) if not args[0].is_a? ::Stick::Units::Converter - return ::Stick::Units::Value.new(self, ::Stick::Units::Unit.new({m => 1}, args[0])) if args[0] && args[0].registered?(m) - elsif ::Stick::Units::Converter.current.registered?(m) + args[0] = (::Units::Converter.converter(args[0]) rescue nil) if not args[0].is_a? ::Units::Converter + return ::Units::Value.new(self, ::Units::Unit.new({m => 1}, args[0])) if args[0] && args[0].registered?(m) + elsif ::Units::Converter.current.registered?(m) raise ::ArgumentError, "Wrong number of arguments" if args.length != 0 - return ::Stick::Units::Value.new(self, ::Stick::Units::Unit.new({m => 1}, ::Stick::Units::Converter.current)) + return ::Units::Value.new(self, ::Units::Unit.new({m => 1}, ::Units::Converter.current)) end ::Exception.with_clean_backtrace("method_missing") { super } end # def to_value(unit) - ::Stick::Units::Value.new(self, unit) + ::Units::Value.new(self, unit) end end class String # def to_unit(converter = nil) - ::Stick::Units::Unit.new(self, converter) + ::Units::Unit.new(self, converter) end # def to_value(converter = nil) - ::Stick::Units::Value.new(self, converter) + ::Units::Value.new(self, converter) end end