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?}