lib/ruby-units.rb in ruby-units-0.3.7 vs lib/ruby-units.rb in ruby-units-0.3.8

- old
+ new

@@ -1,10 +1,10 @@ require 'mathn' require 'rational' require 'date' require 'parsedate' -# = Ruby Units 0.3.7 +# = Ruby Units 0.3.8 # # Copyright 2006 by Kevin C. Olbrich, Ph.D. # # See http://rubyforge.org/ruby-units/ # @@ -38,11 +38,11 @@ # end # Unit.setup class Unit < Numeric require 'units' # pre-generate hashes from unit definitions for performance. - VERSION = '0.3.7' + VERSION = '0.3.8' @@USER_DEFINITIONS = {} @@PREFIX_VALUES = {} @@PREFIX_MAP = {} @@UNIT_MAP = {} @@UNIT_VALUES = {} @@ -638,13 +638,11 @@ end end alias :>> :to alias :convert_to :to - # Eliminates terms in the passed numerator and denominator. Expands out prefixes and applies them to the - # scalar. Returns a hash that can be used to initialize a new Unit object. - # converts the unit back to a float if it is unitless + # converts the unit back to a float if it is unitless. Otherwise raises an exception def to_f return @scalar.to_f if self.unitless? raise RuntimeError, "Can't convert to float unless unitless. Use Unit#scalar" end @@ -706,17 +704,17 @@ def floor return @scalar.floor if self.unitless? Unit.new(@scalar.floor, @numerator, @denominator) end - # if unitless, returns an int + # if unitless, returns an int, otherwise raises an error def to_int return @scalar.to_int if self.unitless? raise RuntimeError, 'Cannot convert to Integer, use Unit#scalar' end - # Tries to make a Time object from current unit + # Tries to make a Time object from current unit. Assumes the current unit hold the duration in seconds from the epoch. def to_time Time.at(self) end alias :time :to_time alias :to_i :to_int @@ -724,10 +722,12 @@ def truncate return @scalar.truncate if self.unitless? Unit.new(@scalar.truncate, @numerator, @denominator) end + # convert a duration to a DateTime. This will work so long as the duration is the duration from the zero date + # defined by DateTime def to_datetime DateTime.new(self.to('d').scalar) end def round @@ -790,18 +790,25 @@ time_point + self rescue time_point.to_datetime + self end end alias :after :from alias :from_now :from - + + # returns next unit in a range. '1 mm'.unit.succ #=> '2 mm'.unit + # only works when the scalar is an integer def succ raise ArgumentError, "Non Integer Scalar" unless @scalar == @scalar.to_i q = @scalar.to_i.succ Unit.new(q, @numerator, @denominator) end + # automatically coerce objects to units when possible + # if an object defines a 'to_unit' method, it will be coerced using that method def coerce(other) + if other.respond_to? :to_unit + return [other.to_unit, self] + end case other when Unit : [other, self] else [Unit.new(other), self] end @@ -1015,10 +1022,10 @@ @denominator ||= UNITY_ARRAY @numerator = top.scan(@@UNIT_MATCH_REGEX).delete_if {|x| x.empty?}.compact if top @denominator = bottom.scan(@@UNIT_MATCH_REGEX).delete_if {|x| x.empty?}.compact if bottom us = "#{(top || '' + bottom || '')}".to_s.gsub(@@UNIT_MATCH_REGEX,'').gsub(/[\d\*, "'_^\/\$]/,'') - raise( ArgumentError, "'#{passed_unit_string}' Unit not recognized ('#{us}' left '#{top =~ @@UNIT_MATCH_REGEX}')") unless us.empty? + raise( ArgumentError, "'#{passed_unit_string}' Unit not recognized") unless us.empty? @numerator = @numerator.map do |item| @@PREFIX_MAP[item[0]] ? [@@PREFIX_MAP[item[0]], @@UNIT_MAP[item[1]]] : [@@UNIT_MAP[item[1]]] end.flatten.compact.delete_if {|x| x.empty?}