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 :-