lib/ruby-units.rb in ruby-units-0.3.2 vs lib/ruby-units.rb in ruby-units-0.3.3

- old
+ new

@@ -1,10 +1,10 @@ require 'mathn' require 'rational' require 'date' require 'parsedate' -# = Ruby Units 0.3.1 +# = Ruby Units 0.3.3 # # 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.0' + VERSION = '0.3.3' @@USER_DEFINITIONS = {} @@PREFIX_VALUES = {} @@PREFIX_MAP = {} @@UNIT_MAP = {} @@UNIT_VALUES = {} @@ -127,12 +127,11 @@ end @@OUTPUT_MAP[key]=value[0][0] end @@PREFIX_REGEX = @@PREFIX_MAP.keys.sort_by {|prefix| prefix.length}.reverse.join('|') @@UNIT_REGEX = @@UNIT_MAP.keys.sort_by {|unit| unit.length}.reverse.join('|') - @@UNIT_MATCH_REGEX = /(#{@@PREFIX_REGEX})*?(#{@@UNIT_REGEX})\b/ - + @@UNIT_MATCH_REGEX = /(#{@@PREFIX_REGEX})*?(#{@@UNIT_REGEX})\b/ end include Comparable attr_accessor :scalar, :numerator, :denominator, :signature, :base_scalar, :base_numerator, :base_denominator, :output, :unit_name @@ -212,10 +211,14 @@ @numerator = @denominator = UNITY_ARRAY when Time: @scalar = options[0].to_f @numerator = ['<second>'] @denominator = UNITY_ARRAY + when DateTime: + @scalar = options[0].ajd + @numerator = ['<day>'] + @denominator = UNITY_ARRAY else raise ArgumentError, "Invalid Unit Format" end self.update_base_scalar self.replace_temperature @@ -263,11 +266,12 @@ return @is_base=false unless x == UNITY || (@@BASE_UNITS.include?((x))) end return @is_base = true end - #convert to base SI units + # convert to base SI units + # results of the conversion are cached so subsequent calls to this will be fast def to_base return self if self.is_base? cached = @@base_unit_cache[self.units] * self.scalar rescue nil return cached if cached @@ -300,15 +304,21 @@ @@base_unit_cache[self.units]=base return base * @scalar end # Generate human readable output. - # If the name of a unit is passed, the scalar will first be converted to the target unit before output. + # If the name of a unit is passed, the unit will first be converted to the target unit before output. # some named conversions are available # # :ft - outputs in feet and inches (e.g., 6'4") # :lbs - outputs in pounds and ounces (e.g, 8 lbs, 8 oz) + # + # You can also pass a standard format string (i.e., '%0.2f') + # or a strftime format string. + # + # output is cached so subsequent calls for the same format will be fast + # def to_s(target_units=nil) out = @output[target_units] rescue nil if out return out else @@ -332,10 +342,11 @@ @output = {target_units => out} return out end end + # Normally pretty prints the unit, but if you really want to see the guts of it, pass ':dump' def inspect(option=nil) return super() if option == :dump self.to_s end @@ -393,15 +404,16 @@ alias :same? :=== alias :same_as? :=== # Add two units together. Result is same units as receiver and scalar and base_scalar are updated appropriately # throws an exception if the units are not compatible. + # It is possible to add Time objects to units of time def +(other) if Unit === other if self =~ other then - q = self.zero? ? 1 : (self.scalar / self.base_scalar) - Unit.new(:scalar=>(self.base_scalar + other.base_scalar)*q, :numerator=>@numerator, :denominator=>@denominator, :signature => @signature) + @q ||= @@cached_units[self.units].scalar / @@cached_units[self.units].base_scalar + Unit.new(:scalar=>(self.base_scalar + other.base_scalar)*@q, :numerator=>@numerator, :denominator=>@denominator, :signature => @signature) else raise ArgumentError, "Incompatible Units" end elsif Time === other other + self @@ -414,12 +426,12 @@ # Subtract two units. Result is same units as receiver and scalar and base_scalar are updated appropriately # throws an exception if the units are not compatible. def -(other) if Unit === other if self =~ other then - q = self.zero? ? 1 : (self.scalar / self.base_scalar) - Unit.new(:scalar=>(self.base_scalar - other.base_scalar)*q, :numerator=>@numerator, :denominator=>@denominator, :signature=>@signature) + @q ||= @@cached_units[self.units].scalar / @@cached_units[self.units].base_scalar + Unit.new(:scalar=>(self.base_scalar - other.base_scalar)*@q, :numerator=>@numerator, :denominator=>@denominator, :signature=>@signature) else raise ArgumentError, "Incompatible Units" end elsif Time === other other - self @@ -697,10 +709,14 @@ Time.at(self) end alias :time :to_time alias :to_i :to_int alias :truncate :to_int + + def to_datetime + DateTime.new(self.to('d').scalar) + end def round Unit.new(@scalar.round, @numerator, @denominator) end @@ -986,11 +1002,11 @@ # Allow date objects to do offsets by a time unit # Date.today + U"1 week" => gives today+1 week class Date alias :unit_date_add :+ - def +unit + def +(unit) case unit when Unit: unit = unit.to('d').round if ['y', 'decade', 'century'].include? unit.units unit_date_add(unit.to('day').scalar) when Time: unit_date_add(unit.to_datetime) @@ -998,21 +1014,26 @@ unit_date_add(unit) end end alias :unit_date_sub :- - def -unit + def -(unit) case unit when Unit: unit = unit.to('d').round if ['y', 'decade', 'century'].include? unit.units unit_date_sub(unit.to('day').scalar) when Time: unit_date_sub(unit.to_datetime) else unit_date_sub(unit) end end + def to_unit(other = nil) + other ? Unit.new(self).to(other) : Unit.new(self) + end + alias :unit :to_unit + def to_time Time.local(*ParseDate.parsedate(self.to_s)) end alias :units_datetime_inspect :inspect @@ -1070,11 +1091,10 @@ end end #needed for compatibility with Rails, which defines a String.from method if self.public_instance_methods.include? 'from' - puts 'rails' alias :old_from :from end def from(time_point = ::Time.now) return old_from(time_point) if Integer === time_point @@ -1160,12 +1180,12 @@ else unit_time_at(*args) end end - def to_unit(other = "s") - other ? Unit.new("#{self.to_f} s").to(other) : Unit.new("#{self.to_f} s") + def to_unit(other = nil) + other ? Unit.new(self).to(other) : Unit.new(self) end alias :unit :to_unit alias :u :to_unit alias :unit_add :+ @@ -1184,9 +1204,10 @@ else unit_add(other) end end + # usage: Time.in '5 min' def self.in(duration) Time.now + duration.to_unit end alias :unit_sub :-