From 2cbdd3759e45749b4e744156dfafaa8d7a9eaf14 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 6 Jul 2013 11:00:47 -0400 Subject: [PATCH 1/5] add RubyUnits namespace to Unit --- lib/ruby-units.rb | 18 +- lib/ruby_units/array.rb | 8 +- lib/ruby_units/cache.rb | 4 +- lib/ruby_units/definition.rb | 12 +- lib/ruby_units/fixnum.rb | 4 +- lib/ruby_units/math.rb | 24 +- lib/ruby_units/namespaced.rb | 14 + lib/ruby_units/numeric.rb | 6 +- lib/ruby_units/string.rb | 10 +- lib/ruby_units/time.rb | 16 +- lib/ruby_units/unit.rb | 2780 ++++++++++--------- lib/ruby_units/unit_definitions/base.rb | 30 +- lib/ruby_units/unit_definitions/prefix.rb | 4 +- lib/ruby_units/unit_definitions/standard.rb | 536 ++-- lib/ruby_units/version.rb | 12 +- spec/ruby-units/unit_spec.rb | 4 +- 16 files changed, 1751 insertions(+), 1731 deletions(-) create mode 100644 lib/ruby_units/namespaced.rb diff --git a/lib/ruby-units.rb b/lib/ruby-units.rb index b6e8b020..820e4f30 100755 --- a/lib/ruby-units.rb +++ b/lib/ruby-units.rb @@ -1,14 +1,6 @@ + $LOAD_PATH << File.dirname(__FILE__) -require "ruby_units/version" -require "ruby_units/definition" -require "ruby_units/cache" -require 'ruby_units/array' -require 'ruby_units/date' -require 'ruby_units/time' -require 'ruby_units/math' -require 'ruby_units/numeric' -require 'ruby_units/object' -require 'ruby_units/string' -require 'ruby_units/unit' -require 'ruby_units/fixnum' -require 'ruby_units/unit_definitions' + +require 'ruby_units/namespaced' + +Unit = RubyUnits::Unit diff --git a/lib/ruby_units/array.rb b/lib/ruby_units/array.rb index a3a7ee6c..413d0ddd 100644 --- a/lib/ruby_units/array.rb +++ b/lib/ruby_units/array.rb @@ -1,11 +1,11 @@ class Array # Construct a unit from an array - # @example [1, 'mm'].to_unit => Unit("1 mm") - # @return (see Unit#initialize) + # @example [1, 'mm'].to_unit => RubyUnits::Unit("1 mm") + # @return (see RubyUnits::Unit#initialize) # @param [Object] other convert to same units as passed def to_unit(other = nil) - other ? Unit.new(self).convert_to(other) : Unit.new(self) + other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self) end alias :unit :to_unit alias :u :to_unit -end \ No newline at end of file +end diff --git a/lib/ruby_units/cache.rb b/lib/ruby_units/cache.rb index 6a65379c..6eaaccaa 100644 --- a/lib/ruby_units/cache.rb +++ b/lib/ruby_units/cache.rb @@ -1,4 +1,4 @@ -class Unit < Numeric +class RubyUnits::Unit < Numeric @@cached_units = {} class Cache @@ -17,4 +17,4 @@ def self.clear end end -end \ No newline at end of file +end diff --git a/lib/ruby_units/definition.rb b/lib/ruby_units/definition.rb index 7fd0b406..2db7df80 100644 --- a/lib/ruby_units/definition.rb +++ b/lib/ruby_units/definition.rb @@ -1,4 +1,4 @@ -class Unit < Numeric +class RubyUnits::Unit < Numeric # Handle the definition of units class Definition @@ -36,8 +36,8 @@ def initialize(_name, _definition = [], &block) @aliases ||= (_definition[0] || [_name]) @scalar ||= _definition[1] @kind ||= _definition[2] - @numerator ||= _definition[3] || Unit::UNITY_ARRAY - @denominator ||= _definition[4] || Unit::UNITY_ARRAY + @numerator ||= _definition[3] || RubyUnits::Unit::UNITY_ARRAY + @denominator ||= _definition[4] || RubyUnits::Unit::UNITY_ARRAY @display_name ||= @aliases.first end @@ -90,11 +90,11 @@ def unity? # units are base units if the scalar is one, and the unit is defined in terms of itself. # @return [Boolean] def base? - (self.denominator == Unit::UNITY_ARRAY) && - (self.numerator != Unit::UNITY_ARRAY) && + (self.denominator == RubyUnits::Unit::UNITY_ARRAY) && + (self.numerator != RubyUnits::Unit::UNITY_ARRAY) && (self.numerator.size == 1) && (self.scalar == 1) && (self.numerator.first == self.name) end end -end \ No newline at end of file +end diff --git a/lib/ruby_units/fixnum.rb b/lib/ruby_units/fixnum.rb index 3101bca9..376f36c8 100644 --- a/lib/ruby_units/fixnum.rb +++ b/lib/ruby_units/fixnum.rb @@ -8,7 +8,7 @@ class Fixnum # @return [Unit, Integer] def quo_with_units(other) case other - when Unit + when RubyUnits::Unit self * other.inverse else quo_without_units(other) @@ -19,4 +19,4 @@ def quo_with_units(other) alias / quo_with_units end # :nocov_19: -end \ No newline at end of file +end diff --git a/lib/ruby_units/math.rb b/lib/ruby_units/math.rb index 5b2bf1b5..5eea1838 100644 --- a/lib/ruby_units/math.rb +++ b/lib/ruby_units/math.rb @@ -7,7 +7,7 @@ module Math alias :unit_sqrt :sqrt # @return [Numeric] def sqrt(n) - if Unit === n + if RubyUnits::Unit === n (n**(Rational(1,2))).to_unit else unit_sqrt(n) @@ -23,7 +23,7 @@ def sqrt(n) alias :unit_cbrt :cbrt # @return [Numeric] def cbrt(n) - if Unit === n + if RubyUnits::Unit === n (n**(Rational(1,3))).to_unit else unit_cbrt(n) @@ -39,7 +39,7 @@ def cbrt(n) alias :unit_sin :sin # @return [Numeric] def sin(n) - Unit === n ? unit_sin(n.convert_to('radian').scalar) : unit_sin(n) + RubyUnits::Unit === n ? unit_sin(n.convert_to('radian').scalar) : unit_sin(n) end # @return [Numeric] module_function :unit_sin @@ -49,7 +49,7 @@ def sin(n) alias :unit_cos :cos # @return [Numeric] def cos(n) - Unit === n ? unit_cos(n.convert_to('radian').scalar) : unit_cos(n) + RubyUnits::Unit === n ? unit_cos(n.convert_to('radian').scalar) : unit_cos(n) end # @return [Numeric] module_function :unit_cos @@ -59,7 +59,7 @@ def cos(n) alias :unit_sinh :sinh # @return [Numeric] def sinh(n) - Unit === n ? unit_sinh(n.convert_to('radian').scalar) : unit_sinh(n) + RubyUnits::Unit === n ? unit_sinh(n.convert_to('radian').scalar) : unit_sinh(n) end # @return [Numeric] module_function :unit_sinh @@ -69,7 +69,7 @@ def sinh(n) alias :unit_cosh :cosh # @return [Numeric] def cosh(n) - Unit === n ? unit_cosh(n.convert_to('radian').scalar) : unit_cosh(n) + RubyUnits::Unit === n ? unit_cosh(n.convert_to('radian').scalar) : unit_cosh(n) end # @return [Numeric] module_function :unit_cosh @@ -79,7 +79,7 @@ def cosh(n) alias :unit_tan :tan # @return [Numeric] def tan(n) - Unit === n ? unit_tan(n.convert_to('radian').scalar) : unit_tan(n) + RubyUnits::Unit === n ? unit_tan(n.convert_to('radian').scalar) : unit_tan(n) end # @return [Numeric] module_function :tan @@ -89,7 +89,7 @@ def tan(n) alias :unit_tanh :tanh # @return [Numeric] def tanh(n) - Unit === n ? unit_tanh(n.convert_to('radian').scalar) : unit_tanh(n) + RubyUnits::Unit === n ? unit_tanh(n.convert_to('radian').scalar) : unit_tanh(n) end # @return [Numeric] module_function :unit_tanh @@ -100,7 +100,7 @@ def tanh(n) # Convert parameters to consistent units and perform the function # @return [Numeric] def hypot(x,y) - if Unit === x && Unit === y + if RubyUnits::Unit === x && RubyUnits::Unit === y (x**2 + y**2)**(1/2) else unit_hypot(x,y) @@ -115,9 +115,9 @@ def hypot(x,y) # @return [Numeric] def atan2(x,y) case - when (x.is_a?(Unit) && y.is_a?(Unit)) && (x !~ y) - raise ArgumentError, "Incompatible Units" - when (x.is_a?(Unit) && y.is_a?(Unit)) && (x =~ y) + when (x.is_a?(RubyUnits::Unit) && y.is_a?(RubyUnits::Unit)) && (x !~ y) + raise ArgumentError, "Incompatible RubyUnits::Units" + when (x.is_a?(RubyUnits::Unit) && y.is_a?(RubyUnits::Unit)) && (x =~ y) Math::unit_atan2(x.base_scalar, y.base_scalar) else Math::unit_atan2(x,y) diff --git a/lib/ruby_units/namespaced.rb b/lib/ruby_units/namespaced.rb new file mode 100644 index 00000000..2efc61e1 --- /dev/null +++ b/lib/ruby_units/namespaced.rb @@ -0,0 +1,14 @@ +# require this file to avoid creating an class alias from Unit to RubyUnits::Unit +require "ruby_units/version" +require "ruby_units/definition" +require "ruby_units/cache" +require 'ruby_units/array' +require 'ruby_units/date' +require 'ruby_units/time' +require 'ruby_units/math' +require 'ruby_units/numeric' +require 'ruby_units/object' +require 'ruby_units/string' +require 'ruby_units/unit' +require 'ruby_units/fixnum' +require 'ruby_units/unit_definitions' diff --git a/lib/ruby_units/numeric.rb b/lib/ruby_units/numeric.rb index 136787cd..75190b2b 100644 --- a/lib/ruby_units/numeric.rb +++ b/lib/ruby_units/numeric.rb @@ -1,9 +1,9 @@ class Numeric # make a unitless unit with a given scalar - # @return (see Unit#initialize) + # @return (see RubyUnits::Unit#initialize) def to_unit(other = nil) - other ? Unit.new(self, other) : Unit.new(self) + other ? RubyUnits::Unit.new(self, other) : RubyUnits::Unit.new(self) end alias :unit :to_unit alias :u :to_unit -end \ No newline at end of file +end diff --git a/lib/ruby_units/string.rb b/lib/ruby_units/string.rb index fd820f34..61c0edda 100644 --- a/lib/ruby_units/string.rb +++ b/lib/ruby_units/string.rb @@ -1,9 +1,9 @@ require 'time' class String # make a string into a unit - # @return (see Unit#initialize) + # @return (see RubyUnits::Unit#initialize) def to_unit(other = nil) - other ? Unit.new(self).convert_to(other) : Unit.new(self) + other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self) end alias :unit :to_unit alias :u :to_unit @@ -16,7 +16,7 @@ def to_unit(other = nil) def %(*args) return "" if self.empty? case - when args.first.is_a?(Unit) + when args.first.is_a?(RubyUnits::Unit) args.first.to_s(self) when (!defined?(Uncertain).nil? && args.first.is_a?(Uncertain)) args.first.to_s(self) @@ -27,8 +27,8 @@ def %(*args) end end - # @param (see Unit#convert_to) - # @return (see Unit#convert_to) + # @param (see RubyUnits::Unit#convert_to) + # @return (see RubyUnits::Unit#convert_to) def convert_to(other) self.unit.convert_to(other) end diff --git a/lib/ruby_units/time.rb b/lib/ruby_units/time.rb index f3100078..020c602e 100644 --- a/lib/ruby_units/time.rb +++ b/lib/ruby_units/time.rb @@ -13,21 +13,21 @@ class << self # epoch # @param [Time] arg # @param [Integer] ms - # @return [Unit, Time] + # @return [RubyUnits::Unit, Time] def self.at(arg,ms=0) case arg when Time unit_time_at(arg) - when Unit + when RubyUnits::Unit unit_time_at(arg.convert_to("s").scalar, ms) else unit_time_at(arg, ms) end end - # @return (see Unit#initialize) + # @return (see RubyUnits::Unit#initialize) def to_unit(other = nil) - other ? Unit.new(self).convert_to(other) : Unit.new(self) + other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self) end alias :unit :to_unit alias :u :to_unit @@ -39,10 +39,10 @@ def to_unit(other = nil) end alias :unit_add :+ - # @return [Unit, Time] + # @return [RubyUnits::Unit, Time] def +(other) case other - when Unit + when RubyUnits::Unit other = other.convert_to('d').round.convert_to('s') if ['y', 'decade', 'century'].include? other.units begin unit_add(other.convert_to('s').scalar) @@ -63,10 +63,10 @@ def self.in(duration) alias :unit_sub :- - # @return [Unit, Time] + # @return [RubyUnits::Unit, Time] def -(other) case other - when Unit + when RubyUnits::Unit other = other.convert_to('d').round.convert_to('s') if ['y', 'decade', 'century'].include? other.units begin unit_sub(other.convert_to('s').scalar) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 2bbac52e..200be03b 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -23,7 +23,7 @@ # # To add or override a unit definition, add a code block like this.. # @example Define a new unit -# Unit.define("foobar") do |unit| +# RubyUnits::Unit.define("foobar") do |unit| # unit.aliases = %w{foo fb foo-bar} # unit.definition = Unit("1 baz") # end @@ -32,1560 +32,1572 @@ # @todo pull caching out into its own class # @todo refactor internal representation of units # @todo method to determine best natural prefix -class Unit < Numeric - VERSION = Unit::Version::STRING - @@definitions = {} - @@PREFIX_VALUES = {} - @@PREFIX_MAP = {} - @@UNIT_MAP = {} - @@UNIT_VALUES = {} - @@UNIT_REGEX = nil - @@UNIT_MATCH_REGEX = nil - UNITY = '<1>' - UNITY_ARRAY = [UNITY] - FEET_INCH_REGEX = /(\d+)\s*(?:'|ft|feet)\s*(\d+)\s*(?:"|in|inches)/ - TIME_REGEX = /(\d+)*:(\d+)*:*(\d+)*[:,]*(\d+)*/ - LBS_OZ_REGEX = /(\d+)\s*(?:#|lbs|pounds|pound-mass)+[\s,]*(\d+)\s*(?:oz|ounces)/ - SCI_NUMBER = %r{([+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*)} - RATIONAL_NUMBER = /\(?([+-]?\d+)\/(\d+)\)?/ - COMPLEX_NUMBER = /#{SCI_NUMBER}?#{SCI_NUMBER}i\b/ - NUMBER_REGEX = /#{SCI_NUMBER}*\s*(.+)?/ - UNIT_STRING_REGEX = /#{SCI_NUMBER}*\s*([^\/]*)\/*(.+)*/ - TOP_REGEX = /([^ \*]+)(?:\^|\*\*)([\d-]+)/ - BOTTOM_REGEX = /([^* ]+)(?:\^|\*\*)(\d+)/ - UNCERTAIN_REGEX = /#{SCI_NUMBER}\s*\+\/-\s*#{SCI_NUMBER}\s(.+)/ - COMPLEX_REGEX = /#{COMPLEX_NUMBER}\s?(.+)?/ - RATIONAL_REGEX = /#{RATIONAL_NUMBER}\s?(.+)?/ - KELVIN = [''] - FAHRENHEIT = [''] - RANKINE = [''] - CELSIUS = [''] - @@TEMP_REGEX = nil - SIGNATURE_VECTOR = [ - :length, - :time, - :temperature, - :mass, - :current, - :substance, - :luminosity, - :currency, - :memory, - :angle - ] - @@KINDS = { - -312078 => :elastance, - -312058 => :resistance, - -312038 => :inductance, - -152040 => :magnetism, - -152038 => :magnetism, - -152058 => :potential, - -7997 => :specific_volume, - -79 => :snap, - -59 => :jolt, - -39 => :acceleration, - -38 => :radiation, - -20 => :frequency, - -19 => :speed, - -18 => :viscosity, - -17 => :volumetric_flow, - -1 => :wavenumber, - 0 => :unitless, - 1 => :length, - 2 => :area, - 3 => :volume, - 20 => :time, - 400 => :temperature, - 7941 => :yank, - 7942 => :power, - 7959 => :pressure, - 7962 => :energy, - 7979 => :viscosity, - 7961 => :force, - 7981 => :momentum, - 7982 => :angular_momentum, - 7997 => :density, - 7998 => :area_density, - 8000 => :mass, - 152020 => :radiation_exposure, - 159999 => :magnetism, - 160000 => :current, - 160020 => :charge, - 312058 => :resistance, - 312078 => :capacitance, - 3199980 => :activity, - 3199997 => :molar_concentration, - 3200000 => :substance, - 63999998 => :illuminance, - 64000000 => :luminous_power, - 1280000000 => :currency, - 25600000000 => :memory, - 511999999980 => :angular_velocity, - 512000000000 => :angle - } - @@cached_units = {} - @@base_unit_cache = {} - - # setup internal arrays and hashes - # @return [true] - def self.setup - self.clear_cache +module RubyUnits + class Unit < Numeric + VERSION = Unit::Version::STRING + @@definitions = {} @@PREFIX_VALUES = {} @@PREFIX_MAP = {} - @@UNIT_VALUES = {} @@UNIT_MAP = {} + @@UNIT_VALUES = {} @@UNIT_REGEX = nil @@UNIT_MATCH_REGEX = nil - @@PREFIX_REGEX = nil + UNITY = '<1>' + UNITY_ARRAY = [UNITY] + FEET_INCH_REGEX = /(\d+)\s*(?:'|ft|feet)\s*(\d+)\s*(?:"|in|inches)/ + TIME_REGEX = /(\d+)*:(\d+)*:*(\d+)*[:,]*(\d+)*/ + LBS_OZ_REGEX = /(\d+)\s*(?:#|lbs|pounds|pound-mass)+[\s,]*(\d+)\s*(?:oz|ounces)/ + SCI_NUMBER = %r{([+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*)} + RATIONAL_NUMBER = /\(?([+-]?\d+)\/(\d+)\)?/ + COMPLEX_NUMBER = /#{SCI_NUMBER}?#{SCI_NUMBER}i\b/ + NUMBER_REGEX = /#{SCI_NUMBER}*\s*(.+)?/ + UNIT_STRING_REGEX = /#{SCI_NUMBER}*\s*([^\/]*)\/*(.+)*/ + TOP_REGEX = /([^ \*]+)(?:\^|\*\*)([\d-]+)/ + BOTTOM_REGEX = /([^* ]+)(?:\^|\*\*)(\d+)/ + UNCERTAIN_REGEX = /#{SCI_NUMBER}\s*\+\/-\s*#{SCI_NUMBER}\s(.+)/ + COMPLEX_REGEX = /#{COMPLEX_NUMBER}\s?(.+)?/ + RATIONAL_REGEX = /#{RATIONAL_NUMBER}\s?(.+)?/ + KELVIN = [''] + FAHRENHEIT = [''] + RANKINE = [''] + CELSIUS = [''] + @@TEMP_REGEX = nil + SIGNATURE_VECTOR = [ + :length, + :time, + :temperature, + :mass, + :current, + :substance, + :luminosity, + :currency, + :memory, + :angle + ] + @@KINDS = { + -312078 => :elastance, + -312058 => :resistance, + -312038 => :inductance, + -152040 => :magnetism, + -152038 => :magnetism, + -152058 => :potential, + -7997 => :specific_volume, + -79 => :snap, + -59 => :jolt, + -39 => :acceleration, + -38 => :radiation, + -20 => :frequency, + -19 => :speed, + -18 => :viscosity, + -17 => :volumetric_flow, + -1 => :wavenumber, + 0 => :unitless, + 1 => :length, + 2 => :area, + 3 => :volume, + 20 => :time, + 400 => :temperature, + 7941 => :yank, + 7942 => :power, + 7959 => :pressure, + 7962 => :energy, + 7979 => :viscosity, + 7961 => :force, + 7981 => :momentum, + 7982 => :angular_momentum, + 7997 => :density, + 7998 => :area_density, + 8000 => :mass, + 152020 => :radiation_exposure, + 159999 => :magnetism, + 160000 => :current, + 160020 => :charge, + 312058 => :resistance, + 312078 => :capacitance, + 3199980 => :activity, + 3199997 => :molar_concentration, + 3200000 => :substance, + 63999998 => :illuminance, + 64000000 => :luminous_power, + 1280000000 => :currency, + 25600000000 => :memory, + 511999999980 => :angular_velocity, + 512000000000 => :angle + } + @@cached_units = {} + @@base_unit_cache = {} + + # setup internal arrays and hashes + # @return [true] + def self.setup + self.clear_cache + @@PREFIX_VALUES = {} + @@PREFIX_MAP = {} + @@UNIT_VALUES = {} + @@UNIT_MAP = {} + @@UNIT_REGEX = nil + @@UNIT_MATCH_REGEX = nil + @@PREFIX_REGEX = nil + + @@definitions.each do |name, definition| + self.use_definition(definition) + end - @@definitions.each do |name, definition| - self.use_definition(definition) + RubyUnits::Unit.new(1) + return true end - Unit.new(1) - return true - end - - # determine if a unit is already defined - # @param [String] unit - # @return [Boolean] - def self.defined?(unit) - self.definitions.values.any? {|d| d.aliases.include?(unit)} - end + # determine if a unit is already defined + # @param [String] unit + # @return [Boolean] + def self.defined?(unit) + self.definitions.values.any? { |d| d.aliases.include?(unit) } + end - # return the unit definition for a unit - # @param [String] unit - # @return [Unit::Definition, nil] - def self.definition(_unit) - unit = (_unit =~ /^<.+>$/) ? _unit : "<#{_unit}>" - return @@definitions[unit] - end + # return the unit definition for a unit + # @param [String] unit + # @return [RubyUnits::Unit::Definition, nil] + def self.definition(_unit) + unit = (_unit =~ /^<.+>$/) ? _unit : "<#{_unit}>" + return @@definitions[unit] + end - # return a list of all defined units - # @return [Array] - def self.definitions - return @@definitions - end + # return a list of all defined units + # @return [Array] + def self.definitions + return @@definitions + end - # @param [Unit::Definition|String] unit_definition - # @param [Block] block - # @return [Unit::Definition] - # @raise [ArgumentError] when passed a non-string if using the block form - # Unpack a unit definition and add it to the array of defined units - # - # @example Block form - # Unit.define('foobar') do |foobar| - # foobar.definition = Unit("1 baz") - # end - # - # @example Unit::Definition form - # unit_definition = Unit::Definition.new("foobar") {|foobar| foobar.definition = Unit("1 baz")} - # Unit.define(unit_definition) - def self.define(unit_definition, &block) - if block_given? - raise ArgumentError, "When using the block form of Unit.define, pass the name of the unit" unless unit_definition.instance_of?(String) - unit_definition = Unit::Definition.new(unit_definition, &block) - end - Unit.definitions[unit_definition.name] = unit_definition - Unit.use_definition(unit_definition) - return unit_definition - end + # @param [RubyUnits::Unit::Definition|String] unit_definition + # @param [Block] block + # @return [RubyUnits::Unit::Definition] + # @raise [ArgumentError] when passed a non-string if using the block form + # Unpack a unit definition and add it to the array of defined units + # + # @example Block form + # RubyUnits::Unit.define('foobar') do |foobar| + # foobar.definition = Unit("1 baz") + # end + # + # @example RubyUnits::Unit::Definition form + # unit_definition = RubyUnits::Unit::Definition.new("foobar") {|foobar| foobar.definition = Unit("1 baz")} + # RubyUnits::Unit.define(unit_definition) + def self.define(unit_definition, &block) + if block_given? + raise ArgumentError, "When using the block form of RubyUnits::Unit.define, pass the name of the unit" unless unit_definition.instance_of?(String) + unit_definition = RubyUnits::Unit::Definition.new(unit_definition, &block) + end + RubyUnits::Unit.definitions[unit_definition.name] = unit_definition + RubyUnits::Unit.use_definition(unit_definition) + return unit_definition + end - # @param [String] name Name of unit to redefine - # @param [Block] block - # @raise [ArgumentError] if a block is not given - # @yield [Unit::Definition] - # @return (see Unit.define) - # Get the definition for a unit and allow it to be redefined - def self.redefine!(name, &block) - raise ArgumentError, "A block is required to redefine a unit" unless block_given? - unit_definition = self.definition(name) - yield unit_definition - self.define(unit_definition) - end + # @param [String] name Name of unit to redefine + # @param [Block] block + # @raise [ArgumentError] if a block is not given + # @yield [RubyUnits::Unit::Definition] + # @return (see RubyUnits::Unit.define) + # Get the definition for a unit and allow it to be redefined + def self.redefine!(name, &block) + raise ArgumentError, "A block is required to redefine a unit" unless block_given? + unit_definition = self.definition(name) + yield unit_definition + self.define(unit_definition) + end - # @param [String] name of unit to undefine - # @return (see Unit.setup) - # Undefine a unit. Will not raise an exception for unknown units. - def self.undefine!(unit) - @@definitions.delete("<#{unit}>") - Unit.setup - end + # @param [String] name of unit to undefine + # @return (see RubyUnits::Unit.setup) + # Undefine a unit. Will not raise an exception for unknown units. + def self.undefine!(unit) + @@definitions.delete("<#{unit}>") + RubyUnits::Unit.setup + end - include Comparable + include Comparable - # @return [Numeric] - attr_accessor :scalar + # @return [Numeric] + attr_accessor :scalar - # @return [Array] - attr_accessor :numerator + # @return [Array] + attr_accessor :numerator - # @return [Array] - attr_accessor :denominator + # @return [Array] + attr_accessor :denominator - # @return [Integer] - attr_accessor :signature + # @return [Integer] + attr_accessor :signature - # @return [Numeric] - attr_accessor :base_scalar + # @return [Numeric] + attr_accessor :base_scalar - # @return [Array] - attr_accessor :base_numerator + # @return [Array] + attr_accessor :base_numerator - # @return [Array] - attr_accessor :base_denominator + # @return [Array] + attr_accessor :base_denominator - # @return [String] - attr_accessor :output + # @return [String] + attr_accessor :output - # @return [String] - attr_accessor :unit_name + # @return [String] + attr_accessor :unit_name - # needed to make complex units play nice -- otherwise not detected as a complex_generic - # @param [Class] - # @return [Boolean] - def kind_of?(klass) - self.scalar.kind_of?(klass) - end + # needed to make complex units play nice -- otherwise not detected as a complex_generic + # @param [Class] + # @return [Boolean] + def kind_of?(klass) + self.scalar.kind_of?(klass) + end - # Used to copy one unit to another - # @param [Unit] from Unit to copy definition from - # @return [Unit] - def copy(from) - @scalar = from.scalar - @numerator = from.numerator - @denominator = from.denominator - @is_base = from.is_base? - @signature = from.signature - @base_scalar = from.base_scalar - @unit_name = from.unit_name rescue nil - return self - end + # Used to copy one unit to another + # @param [Unit] from Unit to copy definition from + # @return [Unit] + def copy(from) + @scalar = from.scalar + @numerator = from.numerator + @denominator = from.denominator + @is_base = from.is_base? + @signature = from.signature + @base_scalar = from.base_scalar + @unit_name = from.unit_name rescue nil + return self + end - if RUBY_VERSION < "1.9" - # :nocov_19: + if RUBY_VERSION < "1.9" + # :nocov_19: - # a list of properties to emit to yaml - # @return [Array] - def to_yaml_properties - %w{@scalar @numerator @denominator @signature @base_scalar} - end + # a list of properties to emit to yaml + # @return [Array] + def to_yaml_properties + %w{@scalar @numerator @denominator @signature @base_scalar} + end - # basically a copy of the basic to_yaml. Needed because otherwise it ends up coercing the object to a string - # before YAML'izing it. - # @param [Hash] opts - # @return [String] - def to_yaml( opts = {} ) - YAML::quick_emit( object_id, opts ) do |out| - out.map( taguri, to_yaml_style ) do |map| - for m in to_yaml_properties do - map.add( m[1..-1], instance_variable_get( m ) ) + # basically a copy of the basic to_yaml. Needed because otherwise it ends up coercing the object to a string + # before YAML'izing it. + # @param [Hash] opts + # @return [String] + def to_yaml(opts = {}) + YAML::quick_emit(object_id, opts) do |out| + out.map(taguri, to_yaml_style) do |map| + for m in to_yaml_properties do + map.add(m[1..-1], instance_variable_get(m)) + end end end end + # :nocov_19: end - # :nocov_19: - end - # Create a new Unit object. Can be initialized using a String, a Hash, an Array, Time, DateTime - # - # @example Valid options include: - # "5.6 kg*m/s^2" - # "5.6 kg*m*s^-2" - # "5.6 kilogram*meter*second^-2" - # "2.2 kPa" - # "37 degC" - # "1" -- creates a unitless constant with value 1 - # "GPa" -- creates a unit with scalar 1 with units 'GPa' - # "6'4\""" -- recognized as 6 feet + 4 inches - # "8 lbs 8 oz" -- recognized as 8 lbs + 8 ounces - # [1, 'kg'] - # {:scalar => 1, :numerator=>'kg'} - # - # @param [Unit,String,Hash,Array,Date,Time,DateTime] options - # @return [Unit] - # @raise [ArgumentError] if absolute value of a temperature is less than absolute zero - # @raise [ArgumentError] if no unit is specified - # @raise [ArgumentError] if an invalid unit is specified - def initialize(*options) - @scalar = nil - @base_scalar = nil - @unit_name = nil - @signature = nil - @output = { } - raise ArgumentError, "Invalid Unit Format" if options[0].nil? - if options.size == 2 - # options[0] is the scalar - # options[1] is a unit string - begin - cached = @@cached_units[options[1]] * options[0] - copy(cached) - rescue - initialize("#{options[0]} #{(options[1].units rescue options[1])}") + # Create a new Unit object. Can be initialized using a String, a Hash, an Array, Time, DateTime + # + # @example Valid options include: + # "5.6 kg*m/s^2" + # "5.6 kg*m*s^-2" + # "5.6 kilogram*meter*second^-2" + # "2.2 kPa" + # "37 degC" + # "1" -- creates a unitless constant with value 1 + # "GPa" -- creates a unit with scalar 1 with units 'GPa' + # "6'4\""" -- recognized as 6 feet + 4 inches + # "8 lbs 8 oz" -- recognized as 8 lbs + 8 ounces + # [1, 'kg'] + # {:scalar => 1, :numerator=>'kg'} + # + # @param [Unit,String,Hash,Array,Date,Time,DateTime] options + # @return [Unit] + # @raise [ArgumentError] if absolute value of a temperature is less than absolute zero + # @raise [ArgumentError] if no unit is specified + # @raise [ArgumentError] if an invalid unit is specified + def initialize(*options) + @scalar = nil + @base_scalar = nil + @unit_name = nil + @signature = nil + @output = {} + raise ArgumentError, "Invalid Unit Format" if options[0].nil? + if options.size == 2 + # options[0] is the scalar + # options[1] is a unit string + begin + cached = @@cached_units[options[1]] * options[0] + copy(cached) + rescue + initialize("#{options[0]} #{(options[1].units rescue options[1])}") + end + return end - return - end - if options.size == 3 - options[1] = options[1].join if options[1].kind_of?(Array) - options[2] = options[2].join if options[2].kind_of?(Array) - begin - cached = @@cached_units["#{options[1]}/#{options[2]}"] * options[0] - copy(cached) - rescue - initialize("#{options[0]} #{options[1]}/#{options[2]}") + if options.size == 3 + options[1] = options[1].join if options[1].kind_of?(Array) + options[2] = options[2].join if options[2].kind_of?(Array) + begin + cached = @@cached_units["#{options[1]}/#{options[2]}"] * options[0] + copy(cached) + rescue + initialize("#{options[0]} #{options[1]}/#{options[2]}") + end + return end - return - end - case options[0] - when Unit - copy(options[0]) - return - when Hash - @scalar = options[0][:scalar] || 1 - @numerator = options[0][:numerator] || UNITY_ARRAY - @denominator = options[0][:denominator] || UNITY_ARRAY - @signature = options[0][:signature] - when Array - initialize(*options[0]) - return - when Numeric - @scalar = options[0] - @numerator = @denominator = UNITY_ARRAY - when Time - @scalar = options[0].to_f - @numerator = [''] - @denominator = UNITY_ARRAY - when DateTime, Date - @scalar = options[0].ajd - @numerator = [''] - @denominator = UNITY_ARRAY - when /^\s*$/ - raise ArgumentError, "No Unit Specified" - when String - parse(options[0]) - else - raise ArgumentError, "Invalid Unit Format" - end - self.update_base_scalar - raise ArgumentError, "Temperatures must not be less than absolute zero" if self.is_temperature? && self.base_scalar < 0 - unary_unit = self.units || "" - if options.first.instance_of?(String) - opt_scalar, opt_units = Unit.parse_into_numbers_and_units(options[0]) - unless @@cached_units.keys.include?(opt_units) || (opt_units =~ /(#{Unit.temp_regex})|(pounds|lbs[ ,]\d+ ounces|oz)|('\d+")|(ft|feet[ ,]\d+ in|inch|inches)|%|(#{TIME_REGEX})|i\s?(.+)?|±|\+\/-/) - @@cached_units[opt_units] = (self.scalar == 1 ? self : opt_units.unit) if opt_units && !opt_units.empty? + case options[0] + when Unit + copy(options[0]) + return + when Hash + @scalar = options[0][:scalar] || 1 + @numerator = options[0][:numerator] || UNITY_ARRAY + @denominator = options[0][:denominator] || UNITY_ARRAY + @signature = options[0][:signature] + when Array + initialize(*options[0]) + return + when Numeric + @scalar = options[0] + @numerator = @denominator = UNITY_ARRAY + when Time + @scalar = options[0].to_f + @numerator = [''] + @denominator = UNITY_ARRAY + when DateTime, Date + @scalar = options[0].ajd + @numerator = [''] + @denominator = UNITY_ARRAY + when /^\s*$/ + raise ArgumentError, "No Unit Specified" + when String + parse(options[0]) + else + raise ArgumentError, "Invalid Unit Format" end + self.update_base_scalar + raise ArgumentError, "Temperatures must not be less than absolute zero" if self.is_temperature? && self.base_scalar < 0 + unary_unit = self.units || "" + if options.first.instance_of?(String) + opt_scalar, opt_units = RubyUnits::Unit.parse_into_numbers_and_units(options[0]) + unless @@cached_units.keys.include?(opt_units) || (opt_units =~ /(#{RubyUnits::Unit.temp_regex})|(pounds|lbs[ ,]\d+ ounces|oz)|('\d+")|(ft|feet[ ,]\d+ in|inch|inches)|%|(#{TIME_REGEX})|i\s?(.+)?|±|\+\/-/) + @@cached_units[opt_units] = (self.scalar == 1 ? self : opt_units.unit) if opt_units && !opt_units.empty? + end + end + unless @@cached_units.keys.include?(unary_unit) || (unary_unit =~ /#{RubyUnits::Unit.temp_regex}/) then + @@cached_units[unary_unit] = (self.scalar == 1 ? self : unary_unit.unit) + end + [@scalar, @numerator, @denominator, @base_scalar, @signature, @is_base].each { |x| x.freeze } + return self end - unless @@cached_units.keys.include?(unary_unit) || (unary_unit =~ /#{Unit.temp_regex}/) then - @@cached_units[unary_unit] = (self.scalar == 1 ? self : unary_unit.unit) - end - [@scalar, @numerator, @denominator, @base_scalar, @signature, @is_base].each {|x| x.freeze} - return self - end - # @todo: figure out how to handle :counting units. This method should probably return :counting instead of :unitless for 'each' - # return the kind of the unit (:mass, :length, etc...) - # @return [Symbol] - def kind - return @@KINDS[self.signature] - end + # @todo: figure out how to handle :counting units. This method should probably return :counting instead of :unitless for 'each' + # return the kind of the unit (:mass, :length, etc...) + # @return [Symbol] + def kind + return @@KINDS[self.signature] + end - # @private - # @return [Hash] - def self.cached - return @@cached_units - end + # @private + # @return [Hash] + def self.cached + return @@cached_units + end - # @private - # @return [true] - def self.clear_cache - @@cached_units = {} - @@base_unit_cache = {} - Unit.new(1) - return true - end + # @private + # @return [true] + def self.clear_cache + @@cached_units = {} + @@base_unit_cache = {} + RubyUnits::Unit.new(1) + return true + end - # @private - # @return [Hash] - def self.base_unit_cache - return @@base_unit_cache - end + # @private + # @return [Hash] + def self.base_unit_cache + return @@base_unit_cache + end - # @example parse strings - # "1 minute in seconds" - # @param [String] input - # @return [Unit] - def self.parse(input) - first, second = input.scan(/(.+)\s(?:in|to|as)\s(.+)/i).first - return second.nil? ? first.unit : first.unit.convert_to(second) - end + # @example parse strings + # "1 minute in seconds" + # @param [String] input + # @return [Unit] + def self.parse(input) + first, second = input.scan(/(.+)\s(?:in|to|as)\s(.+)/i).first + return second.nil? ? first.unit : first.unit.convert_to(second) + end - # @return [Unit] - def to_unit - self - end - alias :unit :to_unit - - # Is this unit in base form? - # @return [Boolean] - def is_base? - return @is_base if defined? @is_base - @is_base = (@numerator + @denominator).compact.uniq. - map {|unit| Unit.definition(unit)}. - all? {|element| element.unity? || element.base? } - return @is_base - end - alias :base? :is_base? - - # convert to base SI units - # results of the conversion are cached so subsequent calls to this will be fast - # @return [Unit] - # @todo this is brittle as it depends on the display_name of a unit, which can be changed - def to_base - return self if self.is_base? - if @@UNIT_MAP[self.units] =~ /\A<(?:temp|deg)[CRF]>\Z/ - if RUBY_VERSION < "1.9" - # :nocov_19: - @signature = @@KINDS.index(:temperature) - # :nocov_19: - else - #:nocov: - @signature = @@KINDS.key(:temperature) - #:nocov: - end - base = case - when self.is_temperature? - self.convert_to('tempK') - when self.is_degree? - self.convert_to('degK') - end - return base + # @return [Unit] + def to_unit + self end - cached = ((@@base_unit_cache[self.units] * self.scalar) rescue nil) - return cached if cached + alias :unit :to_unit - num = [] - den = [] - q = 1 - for unit in @numerator.compact do - if @@PREFIX_VALUES[unit] - q *= @@PREFIX_VALUES[unit] - else - q *= @@UNIT_VALUES[unit][:scalar] if @@UNIT_VALUES[unit] - num << @@UNIT_VALUES[unit][:numerator] if @@UNIT_VALUES[unit] && @@UNIT_VALUES[unit][:numerator] - den << @@UNIT_VALUES[unit][:denominator] if @@UNIT_VALUES[unit] && @@UNIT_VALUES[unit][:denominator] - end + # Is this unit in base form? + # @return [Boolean] + def is_base? + return @is_base if defined? @is_base + @is_base = (@numerator + @denominator).compact.uniq. + map { |unit| RubyUnits::Unit.definition(unit) }. + all? { |element| element.unity? || element.base? } + return @is_base end - for unit in @denominator.compact do - if @@PREFIX_VALUES[unit] - q /= @@PREFIX_VALUES[unit] - else - q /= @@UNIT_VALUES[unit][:scalar] if @@UNIT_VALUES[unit] - den << @@UNIT_VALUES[unit][:numerator] if @@UNIT_VALUES[unit] && @@UNIT_VALUES[unit][:numerator] - num << @@UNIT_VALUES[unit][:denominator] if @@UNIT_VALUES[unit] && @@UNIT_VALUES[unit][:denominator] + + alias :base? :is_base? + + # convert to base SI units + # results of the conversion are cached so subsequent calls to this will be fast + # @return [Unit] + # @todo this is brittle as it depends on the display_name of a unit, which can be changed + def to_base + return self if self.is_base? + if @@UNIT_MAP[self.units] =~ /\A<(?:temp|deg)[CRF]>\Z/ + if RUBY_VERSION < "1.9" + # :nocov_19: + @signature = @@KINDS.index(:temperature) + # :nocov_19: + else + #:nocov: + @signature = @@KINDS.key(:temperature) + #:nocov: + end + base = case + when self.is_temperature? + self.convert_to('tempK') + when self.is_degree? + self.convert_to('degK') + end + return base end - end - num = num.flatten.compact - den = den.flatten.compact - num = UNITY_ARRAY if num.empty? - base= Unit.new(Unit.eliminate_terms(q,num,den)) - @@base_unit_cache[self.units]=base - return base * @scalar - end - alias :base :to_base - - # Generate human readable 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 - # - # @example - # unit.to_s(:ft) - outputs in feet and inches (e.g., 6'4") - # unit.to_s(: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 - # - # @param [Symbol] target_units - # @return [String] - def to_s(target_units=nil) - out = @output[target_units] - if out - return out - else - case target_units - when :ft - inches = self.convert_to("in").scalar.to_int - out = "#{(inches / 12).truncate}\'#{(inches % 12).round}\"" - when :lbs - ounces = self.convert_to("oz").scalar.to_int - out = "#{(ounces / 16).truncate} lbs, #{(ounces % 16).round} oz" - when String - out = case target_units - when /(%[\-+\.\w#]+)\s*(.+)*/ #format string like '%0.2f in' - begin - if $2 #unit specified, need to convert - self.convert_to($2).to_s($1) - else - "#{$1 % @scalar} #{$2 || self.units}".strip - end - rescue # parse it like a strftime format string - (DateTime.new(0) + self).strftime(target_units) - end - when /(\S+)/ #unit only 'mm' or '1/mm' - self.convert_to($1).to_s + cached = ((@@base_unit_cache[self.units] * self.scalar) rescue nil) + return cached if cached + + num = [] + den = [] + q = 1 + for unit in @numerator.compact do + if @@PREFIX_VALUES[unit] + q *= @@PREFIX_VALUES[unit] else - raise "unhandled case" + q *= @@UNIT_VALUES[unit][:scalar] if @@UNIT_VALUES[unit] + num << @@UNIT_VALUES[unit][:numerator] if @@UNIT_VALUES[unit] && @@UNIT_VALUES[unit][:numerator] + den << @@UNIT_VALUES[unit][:denominator] if @@UNIT_VALUES[unit] && @@UNIT_VALUES[unit][:denominator] end - else - out = case @scalar - when Rational - "#{@scalar} #{self.units}" + end + for unit in @denominator.compact do + if @@PREFIX_VALUES[unit] + q /= @@PREFIX_VALUES[unit] else - "#{'%g' % @scalar} #{self.units}" - end.strip + q /= @@UNIT_VALUES[unit][:scalar] if @@UNIT_VALUES[unit] + den << @@UNIT_VALUES[unit][:numerator] if @@UNIT_VALUES[unit] && @@UNIT_VALUES[unit][:numerator] + num << @@UNIT_VALUES[unit][:denominator] if @@UNIT_VALUES[unit] && @@UNIT_VALUES[unit][:denominator] + end end - @output[target_units] = out - return out + + num = num.flatten.compact + den = den.flatten.compact + num = UNITY_ARRAY if num.empty? + base = RubyUnits::Unit.new(RubyUnits::Unit.eliminate_terms(q, num, den)) + @@base_unit_cache[self.units]=base + return base * @scalar end - end - # Normally pretty prints the unit, but if you really want to see the guts of it, pass ':dump' - # @deprecated - # @return [String] - def inspect(option=nil) - return super() if option == :dump - return self.to_s - end + alias :base :to_base + + # Generate human readable 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 + # + # @example + # unit.to_s(:ft) - outputs in feet and inches (e.g., 6'4") + # unit.to_s(: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 + # + # @param [Symbol] target_units + # @return [String] + def to_s(target_units=nil) + out = @output[target_units] + if out + return out + else + case target_units + when :ft + inches = self.convert_to("in").scalar.to_int + out = "#{(inches / 12).truncate}\'#{(inches % 12).round}\"" + when :lbs + ounces = self.convert_to("oz").scalar.to_int + out = "#{(ounces / 16).truncate} lbs, #{(ounces % 16).round} oz" + when String + out = case target_units + when /(%[\-+\.\w#]+)\s*(.+)*/ #format string like '%0.2f in' + begin + if $2 #unit specified, need to convert + self.convert_to($2).to_s($1) + else + "#{$1 % @scalar} #{$2 || self.units}".strip + end + rescue # parse it like a strftime format string + (DateTime.new(0) + self).strftime(target_units) + end + when /(\S+)/ #unit only 'mm' or '1/mm' + self.convert_to($1).to_s + else + raise "unhandled case" + end + else + out = case @scalar + when Rational + "#{@scalar} #{self.units}" + else + "#{'%g' % @scalar} #{self.units}" + end.strip + end + @output[target_units] = out + return out + end + end - # true if unit is a 'temperature', false if a 'degree' or anything else - # @return [Boolean] - # @todo use unit definition to determine if it's a temperature instead of a regex - def is_temperature? - return self.is_degree? && (!(@@UNIT_MAP[self.units] =~ /temp[CFRK]/).nil?) - end - alias :temperature? :is_temperature? + # Normally pretty prints the unit, but if you really want to see the guts of it, pass ':dump' + # @deprecated + # @return [String] + def inspect(option=nil) + return super() if option == :dump + return self.to_s + end - # true if a degree unit or equivalent. - # @return [Boolean] - def is_degree? - return self.kind == :temperature - end - alias :degree? :is_degree? - - # returns the 'degree' unit associated with a temperature unit - # @example '100 tempC'.unit.temperature_scale #=> 'degC' - # @return [String] possible values: degC, degF, degR, or degK - def temperature_scale - return nil unless self.is_temperature? - return "deg#{@@UNIT_MAP[self.units][/temp([CFRK])/,1]}" - end + # true if unit is a 'temperature', false if a 'degree' or anything else + # @return [Boolean] + # @todo use unit definition to determine if it's a temperature instead of a regex + def is_temperature? + return self.is_degree? && (!(@@UNIT_MAP[self.units] =~ /temp[CFRK]/).nil?) + end - # returns true if no associated units - # false, even if the units are "unitless" like 'radians, each, etc' - # @return [Boolean] - def unitless? - return(@numerator == UNITY_ARRAY && @denominator == UNITY_ARRAY) - end + alias :temperature? :is_temperature? - # Compare two Unit objects. Throws an exception if they are not of compatible types. - # Comparisons are done based on the value of the unit in base SI units. - # @param [Object] other - # @return [-1|0|1|nil] - # @raise [NoMethodError] when other does not define <=> - # @raise [ArgumentError] when units are not compatible - def <=>(other) - case - when !self.base_scalar.respond_to?(:<=>) - raise NoMethodError, "undefined method `<=>' for #{self.base_scalar.inspect}" - when other.nil? - return self.base_scalar <=> nil - when !self.is_temperature? && other.zero? - return self.base_scalar <=> 0 - when other.instance_of?(Unit) - raise ArgumentError, "Incompatible Units (#{self.units} !~ #{other.units})" unless self =~ other - return self.base_scalar <=> other.base_scalar - else - x,y = coerce(other) - return x <=> y + # true if a degree unit or equivalent. + # @return [Boolean] + def is_degree? + return self.kind == :temperature end - end - # Compare Units for equality - # this is necessary mostly for Complex units. Complex units do not have a <=> operator - # so we define this one here so that we can properly check complex units for equality. - # Units of incompatible types are not equal, except when they are both zero and neither is a temperature - # Equality checks can be tricky since round off errors may make essentially equivalent units - # appear to be different. - # @param [Object] other - # @return [Boolean] - def ==(other) - case - when other.respond_to?(:zero?) && other.zero? - return self.zero? - when other.instance_of?(Unit) - return false unless self =~ other - return self.base_scalar == other.base_scalar - else - begin - x,y = coerce(other) - return x == y - rescue ArgumentError # return false when object cannot be coerced - return false - end + alias :degree? :is_degree? + + # returns the 'degree' unit associated with a temperature unit + # @example '100 tempC'.unit.temperature_scale #=> 'degC' + # @return [String] possible values: degC, degF, degR, or degK + def temperature_scale + return nil unless self.is_temperature? + return "deg#{@@UNIT_MAP[self.units][/temp([CFRK])/, 1]}" end - end - # check to see if units are compatible, but not the scalar part - # this check is done by comparing signatures for performance reasons - # if passed a string, it will create a unit object with the string and then do the comparison - # @example this permits a syntax like: - # unit =~ "mm" - # @note if you want to do a regexp comparison of the unit string do this ... - # unit.units =~ /regexp/ - # @param [Object] other - # @return [Boolean] - def =~(other) - case other - when Unit - self.signature == other.signature - else - begin - x,y = coerce(other) - return x =~ y - rescue ArgumentError - return false - end + # returns true if no associated units + # false, even if the units are "unitless" like 'radians, each, etc' + # @return [Boolean] + def unitless? + return(@numerator == UNITY_ARRAY && @denominator == UNITY_ARRAY) end - end - alias :compatible? :=~ - alias :compatible_with? :=~ - - # Compare two units. Returns true if quantities and units match - # @example - # Unit("100 cm") === Unit("100 cm") # => true - # Unit("100 cm") === Unit("1 m") # => false - # @param [Object] other - # @return [Boolean] - def ===(other) - case other - when Unit - (self.scalar == other.scalar) && (self.units == other.units) - else - begin - x,y = coerce(other) - return x === y - rescue ArgumentError - return false + # Compare two Unit objects. Throws an exception if they are not of compatible types. + # Comparisons are done based on the value of the unit in base SI units. + # @param [Object] other + # @return [-1|0|1|nil] + # @raise [NoMethodError] when other does not define <=> + # @raise [ArgumentError] when units are not compatible + def <=>(other) + case + when !self.base_scalar.respond_to?(:<=>) + raise NoMethodError, "undefined method `<=>' for #{self.base_scalar.inspect}" + when other.nil? + return self.base_scalar <=> nil + when !self.is_temperature? && other.zero? + return self.base_scalar <=> 0 + when other.instance_of?(Unit) + raise ArgumentError, "Incompatible Units (#{self.units} !~ #{other.units})" unless self =~ other + return self.base_scalar <=> other.base_scalar + else + x, y = coerce(other) + return x <=> y end end - end - 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 - # @param [Object] other - # @return [Unit] - # @raise [ArgumentError] when two temperatures are added - # @raise [ArgumentError] when units are not compatible - # @raise [ArgumentError] when adding a fixed time or date to a time span - def +(other) - case other - when Unit + # Compare Units for equality + # this is necessary mostly for Complex units. Complex units do not have a <=> operator + # so we define this one here so that we can properly check complex units for equality. + # Units of incompatible types are not equal, except when they are both zero and neither is a temperature + # Equality checks can be tricky since round off errors may make essentially equivalent units + # appear to be different. + # @param [Object] other + # @return [Boolean] + def ==(other) case - when self.zero? - other.dup - when self =~ other - raise ArgumentError, "Cannot add two temperatures" if ([self, other].all? {|x| x.is_temperature?}) - if [self, other].any? {|x| x.is_temperature?} - if self.is_temperature? - Unit.new(:scalar => (self.scalar + other.convert_to(self.temperature_scale).scalar), :numerator => @numerator, :denominator=>@denominator, :signature => @signature) - else - Unit.new(:scalar => (other.scalar + self.convert_to(other.temperature_scale).scalar), :numerator => other.numerator, :denominator=>other.denominator, :signature => other.signature) + when other.respond_to?(:zero?) && other.zero? + return self.zero? + when other.instance_of?(Unit) + return false unless self =~ other + return self.base_scalar == other.base_scalar + else + begin + x, y = coerce(other) + return x == y + rescue ArgumentError # return false when object cannot be coerced + return false end + end + end + + # check to see if units are compatible, but not the scalar part + # this check is done by comparing signatures for performance reasons + # if passed a string, it will create a unit object with the string and then do the comparison + # @example this permits a syntax like: + # unit =~ "mm" + # @note if you want to do a regexp comparison of the unit string do this ... + # unit.units =~ /regexp/ + # @param [Object] other + # @return [Boolean] + def =~(other) + case other + when Unit + self.signature == other.signature else - @q ||= ((@@cached_units[self.units].scalar / @@cached_units[self.units].base_scalar) rescue (self.units.unit.to_base.scalar)) - Unit.new(:scalar=>(self.base_scalar + other.base_scalar)*@q, :numerator=>@numerator, :denominator=>@denominator, :signature => @signature) - end - else - raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')" + begin + x, y = coerce(other) + return x =~ y + rescue ArgumentError + return false + end end - when Date, Time - raise ArgumentError, "Date and Time objects represent fixed points in time and cannot be added to a Unit" - else - x,y = coerce(other) - y + x end - end - # Subtract two units. Result is same units as receiver and scalar and base_scalar are updated appropriately - # @param [Numeric] other - # @return [Unit] - # @raise [ArgumentError] when subtracting a temperature from a degree - # @raise [ArgumentError] when units are not compatible - # @raise [ArgumentError] when subtracting a fixed time from a time span - def -(other) - case other - when Unit - case - when self.zero? - if other.zero? - other.dup * -1 # preserve Units class - else - -other.dup + alias :compatible? :=~ + alias :compatible_with? :=~ + + # Compare two units. Returns true if quantities and units match + # @example + # Unit("100 cm") === Unit("100 cm") # => true + # Unit("100 cm") === Unit("1 m") # => false + # @param [Object] other + # @return [Boolean] + def ===(other) + case other + when Unit + (self.scalar == other.scalar) && (self.units == other.units) + else + begin + x, y = coerce(other) + return x === y + rescue ArgumentError + return false end - when self =~ other + end + end + + 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 + # @param [Object] other + # @return [Unit] + # @raise [ArgumentError] when two temperatures are added + # @raise [ArgumentError] when units are not compatible + # @raise [ArgumentError] when adding a fixed time or date to a time span + def +(other) + case other + when Unit case - when [self, other].all? {|x| x.is_temperature?} - Unit.new(:scalar => (self.base_scalar - other.base_scalar), :numerator => KELVIN, :denominator => UNITY_ARRAY, :signature => @signature).convert_to(self.temperature_scale) - when self.is_temperature? - Unit.new(:scalar => (self.base_scalar - other.base_scalar), :numerator => [''], :denominator => UNITY_ARRAY, :signature => @signature).convert_to(self) - when other.is_temperature? - raise ArgumentError, "Cannot subtract a temperature from a differential degree unit" + when self.zero? + other.dup + when self =~ other + raise ArgumentError, "Cannot add two temperatures" if ([self, other].all? { |x| x.is_temperature? }) + if [self, other].any? { |x| x.is_temperature? } + if self.is_temperature? + RubyUnits::Unit.new(:scalar => (self.scalar + other.convert_to(self.temperature_scale).scalar), :numerator => @numerator, :denominator => @denominator, :signature => @signature) + else + RubyUnits::Unit.new(:scalar => (other.scalar + self.convert_to(other.temperature_scale).scalar), :numerator => other.numerator, :denominator => other.denominator, :signature => other.signature) + end + else + @q ||= ((@@cached_units[self.units].scalar / @@cached_units[self.units].base_scalar) rescue (self.units.unit.to_base.scalar)) + RubyUnits::Unit.new(:scalar => (self.base_scalar + other.base_scalar)*@q, :numerator => @numerator, :denominator => @denominator, :signature => @signature) + end else - @q ||= ((@@cached_units[self.units].scalar / @@cached_units[self.units].base_scalar) rescue (self.units.unit.scalar/self.units.unit.to_base.scalar)) - Unit.new(:scalar=>(self.base_scalar - other.base_scalar)*@q, :numerator=>@numerator, :denominator=>@denominator, :signature=>@signature) + raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')" end + when Date, Time + raise ArgumentError, "Date and Time objects represent fixed points in time and cannot be added to a Unit" else - raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')" - end - when Time - raise ArgumentError, "Date and Time objects represent fixed points in time and cannot be subtracted from to a Unit, which can only represent time spans" - else - x,y = coerce(other) - return y-x + x, y = coerce(other) + y + x + end end - end - # Multiply two units. - # @param [Numeric] other - # @return [Unit] - # @raise [ArgumentError] when attempting to multiply two temperatures - def *(other) - case other - when Unit - raise ArgumentError, "Cannot multiply by temperatures" if [other,self].any? {|x| x.is_temperature?} - opts = Unit.eliminate_terms(@scalar*other.scalar, @numerator + other.numerator ,@denominator + other.denominator) - opts.merge!(:signature => @signature + other.signature) - return Unit.new(opts) - when Numeric - return Unit.new(:scalar=>@scalar*other, :numerator=>@numerator, :denominator=>@denominator, :signature => @signature) - else - x,y = coerce(other) - return x * y + # Subtract two units. Result is same units as receiver and scalar and base_scalar are updated appropriately + # @param [Numeric] other + # @return [Unit] + # @raise [ArgumentError] when subtracting a temperature from a degree + # @raise [ArgumentError] when units are not compatible + # @raise [ArgumentError] when subtracting a fixed time from a time span + def -(other) + case other + when Unit + case + when self.zero? + if other.zero? + other.dup * -1 # preserve Units class + else + -other.dup + end + when self =~ other + case + when [self, other].all? { |x| x.is_temperature? } + RubyUnits::Unit.new(:scalar => (self.base_scalar - other.base_scalar), :numerator => KELVIN, :denominator => UNITY_ARRAY, :signature => @signature).convert_to(self.temperature_scale) + when self.is_temperature? + RubyUnits::Unit.new(:scalar => (self.base_scalar - other.base_scalar), :numerator => [''], :denominator => UNITY_ARRAY, :signature => @signature).convert_to(self) + when other.is_temperature? + raise ArgumentError, "Cannot subtract a temperature from a differential degree unit" + else + @q ||= ((@@cached_units[self.units].scalar / @@cached_units[self.units].base_scalar) rescue (self.units.unit.scalar/self.units.unit.to_base.scalar)) + RubyUnits::Unit.new(:scalar => (self.base_scalar - other.base_scalar)*@q, :numerator => @numerator, :denominator => @denominator, :signature => @signature) + end + else + raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')" + end + when Time + raise ArgumentError, "Date and Time objects represent fixed points in time and cannot be subtracted from to a Unit, which can only represent time spans" + else + x, y = coerce(other) + return y-x + end end - end - # Divide two units. - # Throws an exception if divisor is 0 - # @param [Numeric] other - # @return [Unit] - # @raise [ZeroDivisionError] if divisor is zero - # @raise [ArgumentError] if attempting to divide a temperature by another temperature - def /(other) - case other - when Unit - raise ZeroDivisionError if other.zero? - raise ArgumentError, "Cannot divide with temperatures" if [other,self].any? {|x| x.is_temperature?} - opts = Unit.eliminate_terms(@scalar/other.scalar, @numerator + other.denominator ,@denominator + other.numerator) - opts.merge!(:signature=> @signature - other.signature) - return Unit.new(opts) - when Numeric - raise ZeroDivisionError if other.zero? - return Unit.new(:scalar=>@scalar/other, :numerator=>@numerator, :denominator=>@denominator, :signature => @signature) - else - x,y = coerce(other) - return y / x + # Multiply two units. + # @param [Numeric] other + # @return [Unit] + # @raise [ArgumentError] when attempting to multiply two temperatures + def *(other) + case other + when Unit + raise ArgumentError, "Cannot multiply by temperatures" if [other, self].any? { |x| x.is_temperature? } + opts = RubyUnits::Unit.eliminate_terms(@scalar*other.scalar, @numerator + other.numerator, @denominator + other.denominator) + opts.merge!(:signature => @signature + other.signature) + return RubyUnits::Unit.new(opts) + when Numeric + return RubyUnits::Unit.new(:scalar => @scalar*other, :numerator => @numerator, :denominator => @denominator, :signature => @signature) + else + x, y = coerce(other) + return x * y + end end - end - # divide two units and return quotient and remainder - # when both units are in the same units we just use divmod on the raw scalars - # otherwise we use the scalar of the base unit which will be a float - # @param [Object] other - # @return [Array] - def divmod(other) - raise ArgumentError, "Incompatible Units" unless self =~ other - if self.units == other.units - return self.scalar.divmod(other.scalar) - else - return self.to_base.scalar.divmod(other.to_base.scalar) + # Divide two units. + # Throws an exception if divisor is 0 + # @param [Numeric] other + # @return [Unit] + # @raise [ZeroDivisionError] if divisor is zero + # @raise [ArgumentError] if attempting to divide a temperature by another temperature + def /(other) + case other + when Unit + raise ZeroDivisionError if other.zero? + raise ArgumentError, "Cannot divide with temperatures" if [other, self].any? { |x| x.is_temperature? } + opts = RubyUnits::Unit.eliminate_terms(@scalar/other.scalar, @numerator + other.denominator, @denominator + other.numerator) + opts.merge!(:signature => @signature - other.signature) + return RubyUnits::Unit.new(opts) + when Numeric + raise ZeroDivisionError if other.zero? + return RubyUnits::Unit.new(:scalar => @scalar/other, :numerator => @numerator, :denominator => @denominator, :signature => @signature) + else + x, y = coerce(other) + return y / x + end end - end - # perform a modulo on a unit, will raise an exception if the units are not compatible - # @param [Object] other - # @return [Integer] - def %(other) - return self.divmod(other).last - end - - # Exponentiate. Only takes integer powers. - # Note that anything raised to the power of 0 results in a Unit object with a scalar of 1, and no units. - # Throws an exception if exponent is not an integer. - # Ideally this routine should accept a float for the exponent - # It should then convert the float to a rational and raise the unit by the numerator and root it by the denominator - # but, sadly, floats can't be converted to rationals. - # - # For now, if a rational is passed in, it will be used, otherwise we are stuck with integers and certain floats < 1 - # @param [Numeric] other - # @return [Unit] - # @raise [ArgumentError] when raising a temperature to a power - # @raise [ArgumentError] when n not in the set integers from (1..9) - # @raise [ArgumentError] when attempting to raise to a complex number - # @raise [ArgumentError] when an invalid exponent is passed - def **(other) - raise ArgumentError, "Cannot raise a temperature to a power" if self.is_temperature? - if other.kind_of?(Numeric) - return self.inverse if other == -1 - return self if other == 1 - return 1 if other.zero? - end - case other - when Rational - return self.power(other.numerator).root(other.denominator) - when Integer - return self.power(other) - when Float - return self**(other.to_i) if other == other.to_i - valid = (1..9).map {|x| 1/x} - raise ArgumentError, "Not a n-th root (1..9), use 1/n" unless valid.include? other.abs - return self.root((1/other).to_int) - when Complex - raise ArgumentError, "exponentiation of complex numbers is not yet supported." - else - raise ArgumentError, "Invalid Exponent" + # divide two units and return quotient and remainder + # when both units are in the same units we just use divmod on the raw scalars + # otherwise we use the scalar of the base unit which will be a float + # @param [Object] other + # @return [Array] + def divmod(other) + raise ArgumentError, "Incompatible Units" unless self =~ other + if self.units == other.units + return self.scalar.divmod(other.scalar) + else + return self.to_base.scalar.divmod(other.to_base.scalar) + end end - end - # returns the unit raised to the n-th power - # @param [Integer] n - # @return [Unit] - # @raise [ArgumentError] when attempting to raise a temperature to a power - # @raise [ArgumentError] when n is not an integer - def power(n) - raise ArgumentError, "Cannot raise a temperature to a power" if self.is_temperature? - raise ArgumentError, "Exponent must an Integer" unless n.kind_of?(Integer) - return self.inverse if n == -1 - return 1 if n.zero? - return self if n == 1 - if n > 0 then - return (1..(n-1).to_i).inject(self) {|product, x| product * self} - else - return (1..-(n-1).to_i).inject(self) {|product, x| product / self} + # perform a modulo on a unit, will raise an exception if the units are not compatible + # @param [Object] other + # @return [Integer] + def %(other) + return self.divmod(other).last end - end - # Calculates the n-th root of a unit - # if n < 0, returns 1/unit^(1/n) - # @param [Integer] n - # @return [Unit] - # @raise [ArgumentError] when attemptint to take the root of a temperature - # @raise [ArgumentError] when n is not an integer - # @raise [ArgumentError] when n is 0 - def root(n) - raise ArgumentError, "Cannot take the root of a temperature" if self.is_temperature? - raise ArgumentError, "Exponent must an Integer" unless n.kind_of?(Integer) - raise ArgumentError, "0th root undefined" if n.zero? - return self if n == 1 - return self.root(n.abs).inverse if n < 0 - - vec = self.unit_signature_vector - vec=vec.map {|x| x % n} - raise ArgumentError, "Illegal root" unless vec.max == 0 - num = @numerator.dup - den = @denominator.dup - - for item in @numerator.uniq do - x = num.find_all {|i| i==item}.size - r = ((x/n)*(n-1)).to_int - r.times {|y| num.delete_at(num.index(item))} - end - - for item in @denominator.uniq do - x = den.find_all {|i| i==item}.size - r = ((x/n)*(n-1)).to_int - r.times {|y| den.delete_at(den.index(item))} - end - q = @scalar < 0 ? (-1)**Rational(1,n) * (@scalar.abs)**Rational(1,n) : @scalar**Rational(1,n) - return Unit.new(:scalar=>q,:numerator=>num,:denominator=>den) - end + # Exponentiate. Only takes integer powers. + # Note that anything raised to the power of 0 results in a Unit object with a scalar of 1, and no units. + # Throws an exception if exponent is not an integer. + # Ideally this routine should accept a float for the exponent + # It should then convert the float to a rational and raise the unit by the numerator and root it by the denominator + # but, sadly, floats can't be converted to rationals. + # + # For now, if a rational is passed in, it will be used, otherwise we are stuck with integers and certain floats < 1 + # @param [Numeric] other + # @return [Unit] + # @raise [ArgumentError] when raising a temperature to a power + # @raise [ArgumentError] when n not in the set integers from (1..9) + # @raise [ArgumentError] when attempting to raise to a complex number + # @raise [ArgumentError] when an invalid exponent is passed + def **(other) + raise ArgumentError, "Cannot raise a temperature to a power" if self.is_temperature? + if other.kind_of?(Numeric) + return self.inverse if other == -1 + return self if other == 1 + return 1 if other.zero? + end + case other + when Rational + return self.power(other.numerator).root(other.denominator) + when Integer + return self.power(other) + when Float + return self**(other.to_i) if other == other.to_i + valid = (1..9).map { |x| 1/x } + raise ArgumentError, "Not a n-th root (1..9), use 1/n" unless valid.include? other.abs + return self.root((1/other).to_int) + when Complex + raise ArgumentError, "exponentiation of complex numbers is not yet supported." + else + raise ArgumentError, "Invalid Exponent" + end + end - # returns inverse of Unit (1/unit) - # @return [Unit] - def inverse - return Unit("1") / self - end + # returns the unit raised to the n-th power + # @param [Integer] n + # @return [Unit] + # @raise [ArgumentError] when attempting to raise a temperature to a power + # @raise [ArgumentError] when n is not an integer + def power(n) + raise ArgumentError, "Cannot raise a temperature to a power" if self.is_temperature? + raise ArgumentError, "Exponent must an Integer" unless n.kind_of?(Integer) + return self.inverse if n == -1 + return 1 if n.zero? + return self if n == 1 + if n > 0 then + return (1..(n-1).to_i).inject(self) { |product, x| product * self } + else + return (1..-(n-1).to_i).inject(self) { |product, x| product / self } + end + end - # convert to a specified unit string or to the same units as another Unit - # - # unit.convert_to "kg" will covert to kilograms - # unit1.convert_to unit2 converts to same units as unit2 object - # - # To convert a Unit object to match another Unit object, use: - # unit1 >>= unit2 - # - # Special handling for temperature conversions is supported. If the Unit object is converted - # from one temperature unit to another, the proper temperature offsets will be used. - # Supports Kelvin, Celsius, Fahrenheit, and Rankine scales. - # - # @note If temperature is part of a compound unit, the temperature will be treated as a differential - # and the units will be scaled appropriately. - # @param [Object] other - # @return [Unit] - # @raise [ArgumentError] when attempting to convert a degree to a temperature - # @raise [ArgumentError] when target unit is unknown - # @raise [ArgumentError] when target unit is incompatible - def convert_to(other) - return self if other.nil? - return self if TrueClass === other - return self if FalseClass === other - if (Unit === other && other.is_temperature?) || (String === other && other =~ /temp[CFRK]/) - raise ArgumentError, "Receiver is not a temperature unit" unless self.degree? - start_unit = self.units - target_unit = other.units rescue other - unless @base_scalar - @base_scalar = case @@UNIT_MAP[start_unit] - when '' - @scalar + 273.15 - when '' - @scalar - when '' - (@scalar+459.67)*Rational(5,9) - when '' - @scalar*Rational(5,9) - end + # Calculates the n-th root of a unit + # if n < 0, returns 1/unit^(1/n) + # @param [Integer] n + # @return [Unit] + # @raise [ArgumentError] when attemptint to take the root of a temperature + # @raise [ArgumentError] when n is not an integer + # @raise [ArgumentError] when n is 0 + def root(n) + raise ArgumentError, "Cannot take the root of a temperature" if self.is_temperature? + raise ArgumentError, "Exponent must an Integer" unless n.kind_of?(Integer) + raise ArgumentError, "0th root undefined" if n.zero? + return self if n == 1 + return self.root(n.abs).inverse if n < 0 + + vec = self.unit_signature_vector + vec =vec.map { |x| x % n } + raise ArgumentError, "Illegal root" unless vec.max == 0 + num = @numerator.dup + den = @denominator.dup + + for item in @numerator.uniq do + x = num.find_all { |i| i==item }.size + r = ((x/n)*(n-1)).to_int + r.times { |y| num.delete_at(num.index(item)) } end - q= case @@UNIT_MAP[target_unit] - when '' - @base_scalar - 273.15 - when '' - @base_scalar - when '' - @base_scalar * Rational(9,5) - 459.67 - when '' - @base_scalar * Rational(9,5) + + for item in @denominator.uniq do + x = den.find_all { |i| i==item }.size + r = ((x/n)*(n-1)).to_int + r.times { |y| den.delete_at(den.index(item)) } end - return Unit.new("#{q} #{target_unit}") - else - case other - when Unit - return self if other.units == self.units - target = other - when String - target = Unit.new(other) + q = @scalar < 0 ? (-1)**Rational(1, n) * (@scalar.abs)**Rational(1, n) : @scalar**Rational(1, n) + return RubyUnits::Unit.new(:scalar => q, :numerator => num, :denominator => den) + end + + # returns inverse of Unit (1/unit) + # @return [Unit] + def inverse + return Unit("1") / self + end + + # convert to a specified unit string or to the same units as another Unit + # + # unit.convert_to "kg" will covert to kilograms + # unit1.convert_to unit2 converts to same units as unit2 object + # + # To convert a Unit object to match another Unit object, use: + # unit1 >>= unit2 + # + # Special handling for temperature conversions is supported. If the Unit object is converted + # from one temperature unit to another, the proper temperature offsets will be used. + # Supports Kelvin, Celsius, Fahrenheit, and Rankine scales. + # + # @note If temperature is part of a compound unit, the temperature will be treated as a differential + # and the units will be scaled appropriately. + # @param [Object] other + # @return [Unit] + # @raise [ArgumentError] when attempting to convert a degree to a temperature + # @raise [ArgumentError] when target unit is unknown + # @raise [ArgumentError] when target unit is incompatible + def convert_to(other) + return self if other.nil? + return self if TrueClass === other + return self if FalseClass === other + if (Unit === other && other.is_temperature?) || (String === other && other =~ /temp[CFRK]/) + raise ArgumentError, "Receiver is not a temperature unit" unless self.degree? + start_unit = self.units + target_unit = other.units rescue other + unless @base_scalar + @base_scalar = case @@UNIT_MAP[start_unit] + when '' + @scalar + 273.15 + when '' + @scalar + when '' + (@scalar+459.67)*Rational(5, 9) + when '' + @scalar*Rational(5, 9) + end + end + q= case @@UNIT_MAP[target_unit] + when '' + @base_scalar - 273.15 + when '' + @base_scalar + when '' + @base_scalar * Rational(9, 5) - 459.67 + when '' + @base_scalar * Rational(9, 5) + end + return RubyUnits::Unit.new("#{q} #{target_unit}") else - raise ArgumentError, "Unknown target units" + case other + when Unit + return self if other.units == self.units + target = other + when String + target = RubyUnits::Unit.new(other) + else + raise ArgumentError, "Unknown target units" + end + raise ArgumentError, "Incompatible Units" unless self =~ target + _numerator1 = @numerator.map { |x| @@PREFIX_VALUES[x] ? @@PREFIX_VALUES[x] : x }.map { |i| i.kind_of?(Numeric) ? i : @@UNIT_VALUES[i][:scalar] }.compact + _denominator1 = @denominator.map { |x| @@PREFIX_VALUES[x] ? @@PREFIX_VALUES[x] : x }.map { |i| i.kind_of?(Numeric) ? i : @@UNIT_VALUES[i][:scalar] }.compact + _numerator2 = target.numerator.map { |x| @@PREFIX_VALUES[x] ? @@PREFIX_VALUES[x] : x }.map { |x| x.kind_of?(Numeric) ? x : @@UNIT_VALUES[x][:scalar] }.compact + _denominator2 = target.denominator.map { |x| @@PREFIX_VALUES[x] ? @@PREFIX_VALUES[x] : x }.map { |x| x.kind_of?(Numeric) ? x : @@UNIT_VALUES[x][:scalar] }.compact + + q = @scalar * ((_numerator1 + _denominator2).inject(1) { |product, n| product*n }) / + ((_numerator2 + _denominator1).inject(1) { |product, n| product*n }) + return RubyUnits::Unit.new(:scalar => q, :numerator => target.numerator, :denominator => target.denominator, :signature => target.signature) end - raise ArgumentError, "Incompatible Units" unless self =~ target - _numerator1 = @numerator.map {|x| @@PREFIX_VALUES[x] ? @@PREFIX_VALUES[x] : x}.map {|i| i.kind_of?(Numeric) ? i : @@UNIT_VALUES[i][:scalar] }.compact - _denominator1 = @denominator.map {|x| @@PREFIX_VALUES[x] ? @@PREFIX_VALUES[x] : x}.map {|i| i.kind_of?(Numeric) ? i : @@UNIT_VALUES[i][:scalar] }.compact - _numerator2 = target.numerator.map {|x| @@PREFIX_VALUES[x] ? @@PREFIX_VALUES[x] : x}.map {|x| x.kind_of?(Numeric) ? x : @@UNIT_VALUES[x][:scalar] }.compact - _denominator2 = target.denominator.map {|x| @@PREFIX_VALUES[x] ? @@PREFIX_VALUES[x] : x}.map {|x| x.kind_of?(Numeric) ? x : @@UNIT_VALUES[x][:scalar] }.compact + end - q = @scalar * ( (_numerator1 + _denominator2).inject(1) {|product,n| product*n} ) / - ( (_numerator2 + _denominator1).inject(1) {|product,n| product*n} ) - return Unit.new(:scalar=>q, :numerator=>target.numerator, :denominator=>target.denominator, :signature => target.signature) + alias :>> :convert_to + alias :to :convert_to + + # converts the unit back to a float if it is unitless. Otherwise raises an exception + # @return [Float] + # @raise [RuntimeError] when not unitless + def to_f + return @scalar.to_f if self.unitless? + raise RuntimeError, "Cannot convert '#{self.to_s}' to Float unless unitless. Use Unit#scalar" end - end - alias :>> :convert_to - alias :to :convert_to - - # converts the unit back to a float if it is unitless. Otherwise raises an exception - # @return [Float] - # @raise [RuntimeError] when not unitless - def to_f - return @scalar.to_f if self.unitless? - raise RuntimeError, "Cannot convert '#{self.to_s}' to Float unless unitless. Use Unit#scalar" - end - # converts the unit back to a complex if it is unitless. Otherwise raises an exception - # @return [Complex] - # @raise [RuntimeError] when not unitless - def to_c - return Complex(@scalar) if self.unitless? - raise RuntimeError, "Cannot convert '#{self.to_s}' to Complex unless unitless. Use Unit#scalar" - end + # converts the unit back to a complex if it is unitless. Otherwise raises an exception + # @return [Complex] + # @raise [RuntimeError] when not unitless + def to_c + return Complex(@scalar) if self.unitless? + raise RuntimeError, "Cannot convert '#{self.to_s}' to Complex unless unitless. Use Unit#scalar" + end - # if unitless, returns an int, otherwise raises an error - # @return [Integer] - # @raise [RuntimeError] when not unitless - def to_i - return @scalar.to_int if self.unitless? - raise RuntimeError, "Cannot convert '#{self.to_s}' to Integer unless unitless. Use Unit#scalar" - end - alias :to_int :to_i - - # if unitless, returns a Rational, otherwise raises an error - # @return [Rational] - # @raise [RuntimeError] when not unitless - def to_r - return @scalar.to_r if self.unitless? - raise RuntimeError, "Cannot convert '#{self.to_s}' to Rational unless unitless. Use Unit#scalar" - end + # if unitless, returns an int, otherwise raises an error + # @return [Integer] + # @raise [RuntimeError] when not unitless + def to_i + return @scalar.to_int if self.unitless? + raise RuntimeError, "Cannot convert '#{self.to_s}' to Integer unless unitless. Use Unit#scalar" + end - # Returns string formatted for json - # @return [String] - def as_json(*args) - to_s - end + alias :to_int :to_i - # returns the 'unit' part of the Unit object without the scalar - # @return [String] - def units - return "" if @numerator == UNITY_ARRAY && @denominator == UNITY_ARRAY - return @unit_name unless @unit_name.nil? - output_numerator = [] - output_denominator = [] - num = @numerator.clone.compact - den = @denominator.clone.compact - - if @numerator == UNITY_ARRAY - output_numerator << "1" - else - while defn = Unit.definition(num.shift) do - if defn && defn.prefix? - output_numerator << defn.display_name + Unit.definition(num.shift).display_name - else - output_numerator << defn.display_name - end - end + # if unitless, returns a Rational, otherwise raises an error + # @return [Rational] + # @raise [RuntimeError] when not unitless + def to_r + return @scalar.to_r if self.unitless? + raise RuntimeError, "Cannot convert '#{self.to_s}' to Rational unless unitless. Use Unit#scalar" + end + + # Returns string formatted for json + # @return [String] + def as_json(*args) + to_s end - if @denominator == UNITY_ARRAY + # returns the 'unit' part of the Unit object without the scalar + # @return [String] + def units + return "" if @numerator == UNITY_ARRAY && @denominator == UNITY_ARRAY + return @unit_name unless @unit_name.nil? + output_numerator = [] output_denominator = [] - else - while defn = Unit.definition(den.shift) do - if defn && defn.prefix? - output_denominator << defn.display_name + Unit.definition(den.shift).display_name - else - output_denominator << defn.display_name + num = @numerator.clone.compact + den = @denominator.clone.compact + + if @numerator == UNITY_ARRAY + output_numerator << "1" + else + while defn = RubyUnits::Unit.definition(num.shift) do + if defn && defn.prefix? + output_numerator << defn.display_name + RubyUnits::Unit.definition(num.shift).display_name + else + output_numerator << defn.display_name + end end end - end - on = output_numerator.uniq. - map {|x| [x, output_numerator.count(x)]}. - map {|element, power| ("#{element}".strip + (power > 1 ? "^#{power}" : ''))} - od = output_denominator.uniq. - map {|x| [x, output_denominator.count(x)]}. - map {|element, power| ("#{element}".strip + (power > 1 ? "^#{power}" : ''))} - out = "#{on.join('*')}#{od.empty? ? '': '/' + od.join('*')}".strip - @unit_name = out unless self.kind == :temperature - return out - end - - # negates the scalar of the Unit - # @return [Numeric,Unit] - def -@ - return -@scalar if self.unitless? - return (self.dup * -1) - end + if @denominator == UNITY_ARRAY + output_denominator = [] + else + while defn = RubyUnits::Unit.definition(den.shift) do + if defn && defn.prefix? + output_denominator << defn.display_name + RubyUnits::Unit.definition(den.shift).display_name + else + output_denominator << defn.display_name + end + end + end - # absolute value of a unit - # @return [Numeric,Unit] - def abs - return @scalar.abs if self.unitless? - return Unit.new(@scalar.abs, @numerator, @denominator) - end + on = output_numerator.uniq. + map { |x| [x, output_numerator.count(x)] }. + map { |element, power| ("#{element}".strip + (power > 1 ? "^#{power}" : '')) } + od = output_denominator.uniq. + map { |x| [x, output_denominator.count(x)] }. + map { |element, power| ("#{element}".strip + (power > 1 ? "^#{power}" : '')) } + out = "#{on.join('*')}#{od.empty? ? '' : '/' + od.join('*')}".strip + @unit_name = out unless self.kind == :temperature + return out + end - # ceil of a unit - # @return [Numeric,Unit] - def ceil - return @scalar.ceil if self.unitless? - return Unit.new(@scalar.ceil, @numerator, @denominator) - end + # negates the scalar of the Unit + # @return [Numeric,Unit] + def -@ + return -@scalar if self.unitless? + return (self.dup * -1) + end - # @return [Numeric,Unit] - def floor - return @scalar.floor if self.unitless? - return Unit.new(@scalar.floor, @numerator, @denominator) - end + # absolute value of a unit + # @return [Numeric,Unit] + def abs + return @scalar.abs if self.unitless? + return RubyUnits::Unit.new(@scalar.abs, @numerator, @denominator) + end - if RUBY_VERSION < '1.9' + # ceil of a unit # @return [Numeric,Unit] - def round - return @scalar.round if self.unitless? - return Unit.new(@scalar.round, @numerator, @denominator) + def ceil + return @scalar.ceil if self.unitless? + return RubyUnits::Unit.new(@scalar.ceil, @numerator, @denominator) end - else + # @return [Numeric,Unit] - def round(ndigits = 0) - return @scalar.round(ndigits) if self.unitless? - return Unit.new(@scalar.round(ndigits), @numerator, @denominator) + def floor + return @scalar.floor if self.unitless? + return RubyUnits::Unit.new(@scalar.floor, @numerator, @denominator) end - end - # @return [Numeric, Unit] - def truncate - return @scalar.truncate if self.unitless? - return Unit.new(@scalar.truncate, @numerator, @denominator) - end + if RUBY_VERSION < '1.9' + # @return [Numeric,Unit] + def round + return @scalar.round if self.unitless? + return RubyUnits::Unit.new(@scalar.round, @numerator, @denominator) + end + else + # @return [Numeric,Unit] + def round(ndigits = 0) + return @scalar.round(ndigits) if self.unitless? + return RubyUnits::Unit.new(@scalar.round(ndigits), @numerator, @denominator) + end + end - # returns next unit in a range. '1 mm'.unit.succ #=> '2 mm'.unit - # only works when the scalar is an integer - # @return [Unit] - # @raise [ArgumentError] when scalar is not equal to an integer - def succ - raise ArgumentError, "Non Integer Scalar" unless @scalar == @scalar.to_i - return Unit.new(@scalar.to_i.succ, @numerator, @denominator) - end - alias :next :succ - - # returns previous unit in a range. '2 mm'.unit.pred #=> '1 mm'.unit - # only works when the scalar is an integer - # @return [Unit] - # @raise [ArgumentError] when scalar is not equal to an integer - def pred - raise ArgumentError, "Non Integer Scalar" unless @scalar == @scalar.to_i - return Unit.new(@scalar.to_i.pred, @numerator, @denominator) - end + # @return [Numeric, Unit] + def truncate + return @scalar.truncate if self.unitless? + return RubyUnits::Unit.new(@scalar.truncate, @numerator, @denominator) + end - # Tries to make a Time object from current unit. Assumes the current unit hold the duration in seconds from the epoch. - # @return [Time] - def to_time - return Time.at(self) - end - alias :time :to_time + # returns next unit in a range. '1 mm'.unit.succ #=> '2 mm'.unit + # only works when the scalar is an integer + # @return [Unit] + # @raise [ArgumentError] when scalar is not equal to an integer + def succ + raise ArgumentError, "Non Integer Scalar" unless @scalar == @scalar.to_i + return RubyUnits::Unit.new(@scalar.to_i.succ, @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 - # @return [DateTime] - def to_datetime - return DateTime.new!(self.convert_to('d').scalar) - end + alias :next :succ - # @return [Date] - def to_date - return Date.new0(self.convert_to('d').scalar) - end + # returns previous unit in a range. '2 mm'.unit.pred #=> '1 mm'.unit + # only works when the scalar is an integer + # @return [Unit] + # @raise [ArgumentError] when scalar is not equal to an integer + def pred + raise ArgumentError, "Non Integer Scalar" unless @scalar == @scalar.to_i + return RubyUnits::Unit.new(@scalar.to_i.pred, @numerator, @denominator) + end - # true if scalar is zero - # @return [Boolean] - def zero? - return self.base_scalar.zero? - end + # Tries to make a Time object from current unit. Assumes the current unit hold the duration in seconds from the epoch. + # @return [Time] + def to_time + return Time.at(self) + end - # @example '5 min'.unit.ago - # @return [Unit] - def ago - return self.before - end + alias :time :to_time - # @example '5 min'.before(time) - # @return [Unit] - def before(time_point = ::Time.now) - case time_point - when Time, Date, DateTime - return (time_point - self rescue time_point.to_datetime - self) - else - raise ArgumentError, "Must specify a Time, Date, or DateTime" + # convert a duration to a DateTime. This will work so long as the duration is the duration from the zero date + # defined by DateTime + # @return [DateTime] + def to_datetime + return DateTime.new!(self.convert_to('d').scalar) end - end - alias :before_now :before - - # @example 'min'.since(time) - # @param [Time, Date, DateTime] time_point - # @return [Unit] - # @raise [ArgumentError] when time point is not a Time, Date, or DateTime - def since(time_point) - case time_point - when Time - return (Time.now - time_point).unit('s').convert_to(self) - when DateTime, Date - return (DateTime.now - time_point).unit('d').convert_to(self) - else - raise ArgumentError, "Must specify a Time, Date, or DateTime" + + # @return [Date] + def to_date + return Date.new0(self.convert_to('d').scalar) end - end - # @example 'min'.until(time) - # @param [Time, Date, DateTime] time_point - # @return [Unit] - def until(time_point) - case time_point - when Time - return (time_point - Time.now).unit('s').convert_to(self) - when DateTime, Date - return (time_point - DateTime.now).unit('d').convert_to(self) - else - raise ArgumentError, "Must specify a Time, Date, or DateTime" + # true if scalar is zero + # @return [Boolean] + def zero? + return self.base_scalar.zero? end - end - # @example '5 min'.from(time) - # @param [Time, Date, DateTime] time_point - # @return [Time, Date, DateTime] - # @raise [ArgumentError] when passed argument is not a Time, Date, or DateTime - def from(time_point) - case time_point - when Time, DateTime, Date - return (time_point + self rescue time_point.to_datetime + self) - else - raise ArgumentError, "Must specify a Time, Date, or DateTime" + # @example '5 min'.unit.ago + # @return [Unit] + def ago + return self.before end - end - alias :after :from - alias :from_now :from - - # automatically coerce objects to units when possible - # if an object defines a 'to_unit' method, it will be coerced using that method - # @param [Object, #to_unit] - # @return [Array] - def coerce(other) - if other.respond_to? :to_unit - return [other.to_unit, self] - end - case other - when Unit - return [other, self] - else - return [Unit.new(other), self] + + # @example '5 min'.before(time) + # @return [Unit] + def before(time_point = ::Time.now) + case time_point + when Time, Date, DateTime + return (time_point - self rescue time_point.to_datetime - self) + else + raise ArgumentError, "Must specify a Time, Date, or DateTime" + end end - end - # Protected and Private Functions that should only be called from this class - protected + alias :before_now :before + + # @example 'min'.since(time) + # @param [Time, Date, DateTime] time_point + # @return [Unit] + # @raise [ArgumentError] when time point is not a Time, Date, or DateTime + def since(time_point) + case time_point + when Time + return (Time.now - time_point).unit('s').convert_to(self) + when DateTime, Date + return (DateTime.now - time_point).unit('d').convert_to(self) + else + raise ArgumentError, "Must specify a Time, Date, or DateTime" + end + end - # figure out what the scalar part of the base unit for this unit is - # @return [nil] - def update_base_scalar - if self.is_base? - @base_scalar = @scalar - @signature = unit_signature - else - base = self.to_base - @base_scalar = base.scalar - @signature = base.signature + # @example 'min'.until(time) + # @param [Time, Date, DateTime] time_point + # @return [Unit] + def until(time_point) + case time_point + when Time + return (time_point - Time.now).unit('s').convert_to(self) + when DateTime, Date + return (time_point - DateTime.now).unit('d').convert_to(self) + else + raise ArgumentError, "Must specify a Time, Date, or DateTime" + end end - end - # calculates the unit signature vector used by unit_signature - # @return [Array] - # @raise [ArgumentError] when exponent associated with a unit is > 20 or < -20 - def unit_signature_vector - return self.to_base.unit_signature_vector unless self.is_base? - vector = Array.new(SIGNATURE_VECTOR.size,0) - # it's possible to have a kind that misses the array... kinds like :counting - # are more like prefixes, so don't use them to calculate the vector - @numerator.map {|element| Unit.definition(element)}.each do |definition| - index = SIGNATURE_VECTOR.index(definition.kind) - vector[index] += 1 if index - end - @denominator.map {|element| Unit.definition(element)}.each do |definition| - index = SIGNATURE_VECTOR.index(definition.kind) - vector[index] -= 1 if index - end - raise ArgumentError, "Power out of range (-20 < net power of a unit < 20)" if vector.any? {|x| x.abs >=20} - return vector - end + # @example '5 min'.from(time) + # @param [Time, Date, DateTime] time_point + # @return [Time, Date, DateTime] + # @raise [ArgumentError] when passed argument is not a Time, Date, or DateTime + def from(time_point) + case time_point + when Time, DateTime, Date + return (time_point + self rescue time_point.to_datetime + self) + else + raise ArgumentError, "Must specify a Time, Date, or DateTime" + end + end - private + alias :after :from + alias :from_now :from - # used by #dup to duplicate a Unit - # @param [Unit] other - # @private - def initialize_copy(other) - @numerator = other.numerator.dup - @denominator = other.denominator.dup - end + # automatically coerce objects to units when possible + # if an object defines a 'to_unit' method, it will be coerced using that method + # @param [Object, #to_unit] + # @return [Array] + def coerce(other) + if other.respond_to? :to_unit + return [other.to_unit, self] + end + case other + when Unit + return [other, self] + else + return [RubyUnits::Unit.new(other), self] + end + end - # calculates the unit signature id for use in comparing compatible units and simplification - # the signature is based on a simple classification of units and is based on the following publication - # - # Novak, G.S., Jr. "Conversion of units of measurement", IEEE Transactions on Software Engineering, 21(8), Aug 1995, pp.651-661 - # @see http://doi.ieeecomputersociety.org/10.1109/32.403789 - # @return [Array] - def unit_signature - return @signature unless @signature.nil? - vector = unit_signature_vector - vector.each_with_index {|item,index| vector[index] = item * 20**index} - @signature=vector.inject(0) {|sum,n| sum+n} - return @signature - end + # Protected and Private Functions that should only be called from this class + protected - # @param [Numeric] q quantity - # @param [Array] n numerator - # @param [Array] d denominator - # @return [Hash] - def self.eliminate_terms(q, n, d) - num = n.dup - den = d.dup - - num.delete_if {|v| v == UNITY} - den.delete_if {|v| v == UNITY} - combined = Hash.new(0) - - i = 0 - loop do - break if i > num.size - if @@PREFIX_VALUES.has_key? num[i] - k = [num[i],num[i+1]] - i += 2 + # figure out what the scalar part of the base unit for this unit is + # @return [nil] + def update_base_scalar + if self.is_base? + @base_scalar = @scalar + @signature = unit_signature else - k = num[i] - i += 1 + base = self.to_base + @base_scalar = base.scalar + @signature = base.signature + end + end + + # calculates the unit signature vector used by unit_signature + # @return [Array] + # @raise [ArgumentError] when exponent associated with a unit is > 20 or < -20 + def unit_signature_vector + return self.to_base.unit_signature_vector unless self.is_base? + vector = Array.new(SIGNATURE_VECTOR.size, 0) + # it's possible to have a kind that misses the array... kinds like :counting + # are more like prefixes, so don't use them to calculate the vector + @numerator.map { |element| RubyUnits::Unit.definition(element) }.each do |definition| + index = SIGNATURE_VECTOR.index(definition.kind) + vector[index] += 1 if index end - combined[k] += 1 unless k.nil? || k == UNITY + @denominator.map { |element| RubyUnits::Unit.definition(element) }.each do |definition| + index = SIGNATURE_VECTOR.index(definition.kind) + vector[index] -= 1 if index + end + raise ArgumentError, "Power out of range (-20 < net power of a unit < 20)" if vector.any? { |x| x.abs >=20 } + return vector end - j = 0 - loop do - break if j > den.size + private + + # used by #dup to duplicate a Unit + # @param [Unit] other + # @private + def initialize_copy(other) + @numerator = other.numerator.dup + @denominator = other.denominator.dup + end + + # calculates the unit signature id for use in comparing compatible units and simplification + # the signature is based on a simple classification of units and is based on the following publication + # + # Novak, G.S., Jr. "Conversion of units of measurement", IEEE Transactions on Software Engineering, 21(8), Aug 1995, pp.651-661 + # @see http://doi.ieeecomputersociety.org/10.1109/32.403789 + # @return [Array] + def unit_signature + return @signature unless @signature.nil? + vector = unit_signature_vector + vector.each_with_index { |item, index| vector[index] = item * 20**index } + @signature=vector.inject(0) { |sum, n| sum+n } + return @signature + end + + # @param [Numeric] q quantity + # @param [Array] n numerator + # @param [Array] d denominator + # @return [Hash] + def self.eliminate_terms(q, n, d) + num = n.dup + den = d.dup + + num.delete_if { |v| v == UNITY } + den.delete_if { |v| v == UNITY } + combined = Hash.new(0) + + i = 0 + loop do + break if i > num.size + if @@PREFIX_VALUES.has_key? num[i] + k = [num[i], num[i+1]] + i += 2 + else + k = num[i] + i += 1 + end + combined[k] += 1 unless k.nil? || k == UNITY + end + + j = 0 + loop do + break if j > den.size if @@PREFIX_VALUES.has_key? den[j] - k = [den[j],den[j+1]] + k = [den[j], den[j+1]] j += 2 else k = den[j] j += 1 end - combined[k] -= 1 unless k.nil? || k == UNITY - end - - num = [] - den = [] - for key, value in combined do - case - when value > 0 - value.times {num << key} - when value < 0 - value.abs.times {den << key} + combined[k] -= 1 unless k.nil? || k == UNITY end - end - num = UNITY_ARRAY if num.empty? - den = UNITY_ARRAY if den.empty? - return {:scalar=>q, :numerator=>num.flatten.compact, :denominator=>den.flatten.compact} - end - # parse a string into a unit object. - # Typical formats like : - # "5.6 kg*m/s^2" - # "5.6 kg*m*s^-2" - # "5.6 kilogram*meter*second^-2" - # "2.2 kPa" - # "37 degC" - # "1" -- creates a unitless constant with value 1 - # "GPa" -- creates a unit with scalar 1 with units 'GPa' - # 6'4" -- recognized as 6 feet + 4 inches - # 8 lbs 8 oz -- recognized as 8 lbs + 8 ounces - # @return [nil | Unit] - # @todo This should either be a separate class or at least a class method - def parse(passed_unit_string="0") - unit_string = passed_unit_string.dup - if unit_string =~ /\$\s*(#{NUMBER_REGEX})/ - unit_string = "#{$1} USD" - end - unit_string.gsub!("\u00b0".force_encoding('utf-8'), 'deg') if RUBY_VERSION >= '1.9' && unit_string.encoding == Encoding::UTF_8 - - unit_string.gsub!(/%/,'percent') - unit_string.gsub!(/'/,'feet') - unit_string.gsub!(/"/,'inch') - unit_string.gsub!(/#/,'pound') - - #:nocov: - #:nocov_19: - if defined?(Uncertain) && unit_string =~ /(\+\/-|±)/ - value, uncertainty, unit_s = unit_string.scan(UNCERTAIN_REGEX)[0] - result = unit_s.unit * Uncertain.new(value.to_f,uncertainty.to_f) - copy(result) - return - end - #:nocov: - #:nocov_19: - - if defined?(Complex) && unit_string =~ COMPLEX_NUMBER - real, imaginary, unit_s = unit_string.scan(COMPLEX_REGEX)[0] - result = Unit(unit_s || '1') * Complex(real.to_f,imaginary.to_f) - copy(result) - return - end - - if defined?(Rational) && unit_string =~ RATIONAL_NUMBER - numerator, denominator, unit_s = unit_string.scan(RATIONAL_REGEX)[0] - result = Unit(unit_s || '1') * Rational(numerator.to_i,denominator.to_i) - copy(result) - return - end - - unit_string =~ NUMBER_REGEX - unit = @@cached_units[$2] - mult = ($1.empty? ? 1.0 : $1.to_f) rescue 1.0 - mult = mult.to_int if (mult.to_int == mult) - if unit - copy(unit) - @scalar *= mult - @base_scalar *= mult - return self - end - unit_string.gsub!(/<(#{@@UNIT_REGEX})><(#{@@UNIT_REGEX})>/, '\1*\2') - unit_string.gsub!(/[<>]/,"") - - if unit_string =~ /:/ - hours, minutes, seconds, microseconds = unit_string.scan(TIME_REGEX)[0] - raise ArgumentError, "Invalid Duration" if [hours, minutes, seconds, microseconds].all? {|x| x.nil?} - result = "#{hours || 0} h".unit + - "#{minutes || 0} minutes".unit + - "#{seconds || 0} seconds".unit + - "#{microseconds || 0} usec".unit - copy(result) - return - end - - # Special processing for unusual unit strings - # feet -- 6'5" - feet, inches = unit_string.scan(FEET_INCH_REGEX)[0] - if (feet && inches) - result = Unit.new("#{feet} ft") + Unit.new("#{inches} inches") - copy(result) - return - end - - # weight -- 8 lbs 12 oz - pounds, oz = unit_string.scan(LBS_OZ_REGEX)[0] - if (pounds && oz) - result = Unit.new("#{pounds} lbs") + Unit.new("#{oz} oz") - copy(result) - return - end - - # more than one per. I.e., "1 m/s/s" - raise( ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.count('/') > 1 - raise( ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.scan(/\s[02-9]/).size > 0 - @scalar, top, bottom = unit_string.scan(UNIT_STRING_REGEX)[0] #parse the string into parts - top.scan(TOP_REGEX).each do |item| - n = item[1].to_i - x = "#{item[0]} " - case - when n>=0 - top.gsub!(/#{item[0]}(\^|\*\*)#{n}/) {|s| x * n} - when n<0 - bottom = "#{bottom} #{x * -n}"; top.gsub!(/#{item[0]}(\^|\*\*)#{n}/,"") + num = [] + den = [] + for key, value in combined do + case + when value > 0 + value.times { num << key } + when value < 0 + value.abs.times { den << key } + end end + num = UNITY_ARRAY if num.empty? + den = UNITY_ARRAY if den.empty? + return { :scalar => q, :numerator => num.flatten.compact, :denominator => den.flatten.compact } end - bottom.gsub!(BOTTOM_REGEX) {|s| "#{$1} " * $2.to_i} if bottom - @scalar = @scalar.to_f unless @scalar.nil? || @scalar.empty? - @scalar = 1 unless @scalar.kind_of? Numeric - @scalar = @scalar.to_int if (@scalar.to_int == @scalar) - @numerator ||= UNITY_ARRAY - @denominator ||= UNITY_ARRAY - @numerator = top.scan(Unit.unit_match_regex).delete_if {|x| x.empty?}.compact if top - @denominator = bottom.scan(Unit.unit_match_regex).delete_if {|x| x.empty?}.compact if bottom + # parse a string into a unit object. + # Typical formats like : + # "5.6 kg*m/s^2" + # "5.6 kg*m*s^-2" + # "5.6 kilogram*meter*second^-2" + # "2.2 kPa" + # "37 degC" + # "1" -- creates a unitless constant with value 1 + # "GPa" -- creates a unit with scalar 1 with units 'GPa' + # 6'4" -- recognized as 6 feet + 4 inches + # 8 lbs 8 oz -- recognized as 8 lbs + 8 ounces + # @return [nil | Unit] + # @todo This should either be a separate class or at least a class method + def parse(passed_unit_string="0") + unit_string = passed_unit_string.dup + if unit_string =~ /\$\s*(#{NUMBER_REGEX})/ + unit_string = "#{$1} USD" + end + unit_string.gsub!("\u00b0".force_encoding('utf-8'), 'deg') if RUBY_VERSION >= '1.9' && unit_string.encoding == Encoding::UTF_8 + + unit_string.gsub!(/%/, 'percent') + unit_string.gsub!(/'/, 'feet') + unit_string.gsub!(/"/, 'inch') + unit_string.gsub!(/#/, 'pound') + + #:nocov: + #:nocov_19: + if defined?(Uncertain) && unit_string =~ /(\+\/-|±)/ + value, uncertainty, unit_s = unit_string.scan(UNCERTAIN_REGEX)[0] + result = unit_s.unit * Uncertain.new(value.to_f, uncertainty.to_f) + copy(result) + return + end + #:nocov: + #:nocov_19: - # eliminate all known terms from this string. This is a quick check to see if the passed unit - # contains terms that are not defined. - used = "#{top} #{bottom}".to_s.gsub(Unit.unit_match_regex,'').gsub(/[\d\*, "'_^\/\$]/,'') - raise( ArgumentError, "'#{passed_unit_string}' Unit not recognized") unless used.empty? + if defined?(Complex) && unit_string =~ COMPLEX_NUMBER + real, imaginary, unit_s = unit_string.scan(COMPLEX_REGEX)[0] + result = Unit(unit_s || '1') * Complex(real.to_f, imaginary.to_f) + copy(result) + return + end - @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?} + if defined?(Rational) && unit_string =~ RATIONAL_NUMBER + numerator, denominator, unit_s = unit_string.scan(RATIONAL_REGEX)[0] + result = Unit(unit_s || '1') * Rational(numerator.to_i, denominator.to_i) + copy(result) + return + end - @denominator = @denominator.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?} + unit_string =~ NUMBER_REGEX + unit = @@cached_units[$2] + mult = ($1.empty? ? 1.0 : $1.to_f) rescue 1.0 + mult = mult.to_int if (mult.to_int == mult) + if unit + copy(unit) + @scalar *= mult + @base_scalar *= mult + return self + end + unit_string.gsub!(/<(#{@@UNIT_REGEX})><(#{@@UNIT_REGEX})>/, '\1*\2') + unit_string.gsub!(/[<>]/, "") + + if unit_string =~ /:/ + hours, minutes, seconds, microseconds = unit_string.scan(TIME_REGEX)[0] + raise ArgumentError, "Invalid Duration" if [hours, minutes, seconds, microseconds].all? { |x| x.nil? } + result = "#{hours || 0} h".unit + + "#{minutes || 0} minutes".unit + + "#{seconds || 0} seconds".unit + + "#{microseconds || 0} usec".unit + copy(result) + return + end - @numerator = UNITY_ARRAY if @numerator.empty? - @denominator = UNITY_ARRAY if @denominator.empty? - return self - end + # Special processing for unusual unit strings + # feet -- 6'5" + feet, inches = unit_string.scan(FEET_INCH_REGEX)[0] + if (feet && inches) + result = RubyUnits::Unit.new("#{feet} ft") + RubyUnits::Unit.new("#{inches} inches") + copy(result) + return + end - # return an array of base units - # @return [Array] - def self.base_units - return @@base_units ||= @@definitions.dup.delete_if {|_, defn| !defn.base?}.keys.map {|u| Unit.new(u)} - end + # weight -- 8 lbs 12 oz + pounds, oz = unit_string.scan(LBS_OZ_REGEX)[0] + if (pounds && oz) + result = RubyUnits::Unit.new("#{pounds} lbs") + RubyUnits::Unit.new("#{oz} oz") + copy(result) + return + end - private - - # parse a string consisting of a number and a unit string - # @param [String] string - # @return [Array] consisting of [Numeric, "unit"] - # @private - def self.parse_into_numbers_and_units(string) - # scientific notation.... 123.234E22, -123.456e-10 - sci = %r{[+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*} - # rational numbers.... -1/3, 1/5, 20/100 - rational = %r{[+-]?\d+\/\d+} - # complex numbers... -1.2+3i, +1.2-3.3i - complex = %r{#{sci}{2,2}i} - anynumber = %r{(?:(#{complex}|#{rational}|#{sci})\b)?\s?([\D].*)?} - num, unit = string.scan(anynumber).first - - return [case num - when NilClass - 1 - when complex - if num.respond_to?(:to_c) - num.to_c - else - #:nocov_19: - Complex(*num.scan(/(#{sci})(#{sci})i/).flatten.map {|n| n.to_i}) - #:nocov_19: + # more than one per. I.e., "1 m/s/s" + raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.count('/') > 1 + raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.scan(/\s[02-9]/).size > 0 + @scalar, top, bottom = unit_string.scan(UNIT_STRING_REGEX)[0] #parse the string into parts + top.scan(TOP_REGEX).each do |item| + n = item[1].to_i + x = "#{item[0]} " + case + when n>=0 + top.gsub!(/#{item[0]}(\^|\*\*)#{n}/) { |s| x * n } + when n<0 + bottom = "#{bottom} #{x * -n}"; top.gsub!(/#{item[0]}(\^|\*\*)#{n}/, "") end - when rational - Rational(*num.split("/").map {|x| x.to_i}) - else - num.to_f - end, unit.to_s.strip] - end + end + bottom.gsub!(BOTTOM_REGEX) { |s| "#{$1} " * $2.to_i } if bottom + @scalar = @scalar.to_f unless @scalar.nil? || @scalar.empty? + @scalar = 1 unless @scalar.kind_of? Numeric + @scalar = @scalar.to_int if (@scalar.to_int == @scalar) + + @numerator ||= UNITY_ARRAY + @denominator ||= UNITY_ARRAY + @numerator = top.scan(RubyUnits::Unit.unit_match_regex).delete_if { |x| x.empty? }.compact if top + @denominator = bottom.scan(RubyUnits::Unit.unit_match_regex).delete_if { |x| x.empty? }.compact if bottom + + # eliminate all known terms from this string. This is a quick check to see if the passed unit + # contains terms that are not defined. + used = "#{top} #{bottom}".to_s.gsub(RubyUnits::Unit.unit_match_regex, '').gsub(/[\d\*, "'_^\/\$]/, '') + raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") unless used.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? } + + @denominator = @denominator.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? } + + @numerator = UNITY_ARRAY if @numerator.empty? + @denominator = UNITY_ARRAY if @denominator.empty? + return self + end - # return a fragment of a regex to be used for matching units or reconstruct it if hasn't been used yet. - # Unit names are reverse sorted by length so the regexp matcher will prefer longer and more specific names - # @return [String] - # @private - def self.unit_regex - @@UNIT_REGEX ||= @@UNIT_MAP.keys.sort_by {|unit_name| [unit_name.length, unit_name]}.reverse.join('|') - end + # return an array of base units + # @return [Array] + def self.base_units + return @@base_units ||= @@definitions.dup.delete_if { |_, defn| !defn.base? }.keys.map { |u| RubyUnits::Unit.new(u) } + end - # return a regex used to match units - # @return [RegExp] - # @private - def self.unit_match_regex - @@UNIT_MATCH_REGEX ||= /(#{Unit.prefix_regex})*?(#{Unit.unit_regex})\b/ - end + private + + # parse a string consisting of a number and a unit string + # @param [String] string + # @return [Array] consisting of [Numeric, "unit"] + # @private + def self.parse_into_numbers_and_units(string) + # scientific notation.... 123.234E22, -123.456e-10 + sci = %r{[+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*} + # rational numbers.... -1/3, 1/5, 20/100 + rational = %r{[+-]?\d+\/\d+} + # complex numbers... -1.2+3i, +1.2-3.3i + complex = %r{#{sci}{2,2}i} + anynumber = %r{(?:(#{complex}|#{rational}|#{sci})\b)?\s?([\D].*)?} + num, unit = string.scan(anynumber).first + + return [case num + when NilClass + 1 + when complex + if num.respond_to?(:to_c) + num.to_c + else + #:nocov_19: + Complex(*num.scan(/(#{sci})(#{sci})i/).flatten.map { |n| n.to_i }) + #:nocov_19: + end + when rational + Rational(*num.split("/").map { |x| x.to_i }) + else + num.to_f + end, unit.to_s.strip] + end - # return a regexp fragment used to match prefixes - # @return [String] - # @private - def self.prefix_regex - return @@PREFIX_REGEX ||= @@PREFIX_MAP.keys.sort_by {|prefix| [prefix.length, prefix]}.reverse.join('|') - end + # return a fragment of a regex to be used for matching units or reconstruct it if hasn't been used yet. + # Unit names are reverse sorted by length so the regexp matcher will prefer longer and more specific names + # @return [String] + # @private + def self.unit_regex + @@UNIT_REGEX ||= @@UNIT_MAP.keys.sort_by { |unit_name| [unit_name.length, unit_name] }.reverse.join('|') + end - def self.temp_regex - @@TEMP_REGEX ||= Regexp.new "(?:#{ + # return a regex used to match units + # @return [RegExp] + # @private + def self.unit_match_regex + @@UNIT_MATCH_REGEX ||= /(#{RubyUnits::Unit.prefix_regex})*?(#{RubyUnits::Unit.unit_regex})\b/ + end + + # return a regexp fragment used to match prefixes + # @return [String] + # @private + def self.prefix_regex + return @@PREFIX_REGEX ||= @@PREFIX_MAP.keys.sort_by { |prefix| [prefix.length, prefix] }.reverse.join('|') + end + + def self.temp_regex + @@TEMP_REGEX ||= Regexp.new "(?:#{ temp_units=%w(tempK tempC tempF tempR degK degC degF degR) - aliases=temp_units.map{|unit| d=Unit.definition(unit); d && d.aliases}.flatten.compact - regex_str= aliases.empty? ? '(?!x)x' : aliases.join('|') + aliases =temp_units.map { |unit| d=RubyUnits::Unit.definition(unit); d && d.aliases }.flatten.compact + regex_str = aliases.empty? ? '(?!x)x' : aliases.join('|') regex_str - })" - end + })" + end - # inject a definition into the internal array and set it up for use - # @private - def self.use_definition(definition) - @@UNIT_MATCH_REGEX = nil #invalidate the unit match regex - @@TEMP_REGEX = nil #invalidate the temp regex - if definition.prefix? - @@PREFIX_VALUES[definition.name] = definition.scalar - definition.aliases.each {|_alias| @@PREFIX_MAP[_alias] = definition.name } - @@PREFIX_REGEX = nil #invalidate the prefix regex - else - @@UNIT_VALUES[definition.name] = {} - @@UNIT_VALUES[definition.name][:scalar] = definition.scalar - @@UNIT_VALUES[definition.name][:numerator] = definition.numerator if definition.numerator - @@UNIT_VALUES[definition.name][:denominator] = definition.denominator if definition.denominator - definition.aliases.each {|_alias| @@UNIT_MAP[_alias] = definition.name} - @@UNIT_REGEX = nil #invalidate the unit regex + # inject a definition into the internal array and set it up for use + # @private + def self.use_definition(definition) + @@UNIT_MATCH_REGEX = nil #invalidate the unit match regex + @@TEMP_REGEX = nil #invalidate the temp regex + if definition.prefix? + @@PREFIX_VALUES[definition.name] = definition.scalar + definition.aliases.each { |_alias| @@PREFIX_MAP[_alias] = definition.name } + @@PREFIX_REGEX = nil #invalidate the prefix regex + else + @@UNIT_VALUES[definition.name] = {} + @@UNIT_VALUES[definition.name][:scalar] = definition.scalar + @@UNIT_VALUES[definition.name][:numerator] = definition.numerator if definition.numerator + @@UNIT_VALUES[definition.name][:denominator] = definition.denominator if definition.denominator + definition.aliases.each { |_alias| @@UNIT_MAP[_alias] = definition.name } + @@UNIT_REGEX = nil #invalidate the unit regex + end end end - end diff --git a/lib/ruby_units/unit_definitions/base.rb b/lib/ruby_units/unit_definitions/base.rb index 6795cf32..a18c67bc 100644 --- a/lib/ruby_units/unit_definitions/base.rb +++ b/lib/ruby_units/unit_definitions/base.rb @@ -1,98 +1,98 @@ # seed the cache -Unit('1') +RubyUnits::Unit('1') -Unit.define("meter") do |unit| +RubyUnits::Unit.define("meter") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{m meter meters metre metres} unit.kind = :length end -Unit.define("kilogram") do |unit| +RubyUnits::Unit.define("kilogram") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{kg kilogram kilograms} unit.kind = :mass end -Unit.define("second") do |unit| +RubyUnits::Unit.define("second") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{s sec second seconds} unit.kind = :time end -Unit.define("mole") do |unit| +RubyUnits::Unit.define("mole") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{mol mole} unit.kind = :substance end -Unit.define("ampere") do |unit| +RubyUnits::Unit.define("ampere") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{A ampere amperes amp amps} unit.kind = :current end -Unit.define("radian") do |unit| +RubyUnits::Unit.define("radian") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{rad radian radians} unit.kind = :angle end -Unit.define("kelvin") do |unit| +RubyUnits::Unit.define("kelvin") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{degK kelvin} unit.kind = :temperature end -Unit.define("tempK") do |unit| +RubyUnits::Unit.define("tempK") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{tempK} unit.kind = :temperature end -Unit.define("byte") do |unit| +RubyUnits::Unit.define("byte") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{B byte bytes} unit.kind = :memory end -Unit.define("dollar") do |unit| +RubyUnits::Unit.define("dollar") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{USD dollar} unit.kind = :currency end -Unit.define("candela") do |unit| +RubyUnits::Unit.define("candela") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{cd candela} unit.kind = :luminosity end -Unit.define("each") do |unit| +RubyUnits::Unit.define("each") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{each} unit.kind = :counting end -Unit.define("steradian") do |unit| +RubyUnits::Unit.define("steradian") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{sr steradian steradians} unit.kind = :solid_angle end -Unit.define("decibel") do |unit| +RubyUnits::Unit.define("decibel") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{dB decibel decibels} diff --git a/lib/ruby_units/unit_definitions/prefix.rb b/lib/ruby_units/unit_definitions/prefix.rb index 3b3e9da1..041ea5aa 100644 --- a/lib/ruby_units/unit_definitions/prefix.rb +++ b/lib/ruby_units/unit_definitions/prefix.rb @@ -31,10 +31,10 @@ 'zepto' => [%w{z Zepto zepto}, Rational(1,1e21)], 'yocto' => [%w{y Yocto yocto}, Rational(1,1e24)] }.each do |name, definition| - Unit.define(name) do |unit| + RubyUnits::Unit.define(name) do |unit| aliases, scalar = definition unit.aliases = aliases unit.scalar = scalar unit.kind = :prefix end -end \ No newline at end of file +end diff --git a/lib/ruby_units/unit_definitions/standard.rb b/lib/ruby_units/unit_definitions/standard.rb index a1987f4c..0a40d1f2 100644 --- a/lib/ruby_units/unit_definitions/standard.rb +++ b/lib/ruby_units/unit_definitions/standard.rb @@ -1,705 +1,705 @@ # length units -Unit.define('inch') do |inch| - inch.definition = Unit('254/10000 meter') +RubyUnits::Unit.define('inch') do |inch| + inch.definition = RubyUnits::Unit('254/10000 meter') inch.aliases = %w{in inch inches "} end -Unit.define('foot') do |foot| - foot.definition = Unit('12 inches') +RubyUnits::Unit.define('foot') do |foot| + foot.definition = RubyUnits::Unit('12 inches') foot.aliases = %w{ft foot feet '} end -Unit.define('survey-foot') do |sft| - sft.definition = Unit('1200/3937 meter') +RubyUnits::Unit.define('survey-foot') do |sft| + sft.definition = RubyUnits::Unit('1200/3937 meter') sft.aliases = %w{sft sfoot sfeet} end -Unit.define('yard') do |yard| - yard.definition = Unit('3 ft') +RubyUnits::Unit.define('yard') do |yard| + yard.definition = RubyUnits::Unit('3 ft') yard.aliases = %w{yd yard yards} end -Unit.define('mile') do |mile| - mile.definition = Unit('5280 ft') +RubyUnits::Unit.define('mile') do |mile| + mile.definition = RubyUnits::Unit('5280 ft') mile.aliases = %w{mi mile miles} end -Unit.define('naut-mile') do |naut| - naut.definition = Unit('1852 m') +RubyUnits::Unit.define('naut-mile') do |naut| + naut.definition = RubyUnits::Unit('1852 m') naut.aliases = %w{nmi M NM} end # on land -Unit.define('league') do |league| - league.definition = Unit('3 miles') +RubyUnits::Unit.define('league') do |league| + league.definition = RubyUnits::Unit('3 miles') league.aliases = %w{league leagues} end # at sea -Unit.define('naut-league') do |naut_league| - naut_league.definition = Unit('3 nmi') +RubyUnits::Unit.define('naut-league') do |naut_league| + naut_league.definition = RubyUnits::Unit('3 nmi') naut_league.aliases = %w{nleague nleagues} end -Unit.define('furlong') do |furlong| - furlong.definition = Unit('1/8 mile') +RubyUnits::Unit.define('furlong') do |furlong| + furlong.definition = RubyUnits::Unit('1/8 mile') furlong.aliases = %w{fur furlong furlongs} end -Unit.define('rod') do |rod| - rod.definition = Unit('33/2 feet') +RubyUnits::Unit.define('rod') do |rod| + rod.definition = RubyUnits::Unit('33/2 feet') rod.aliases = %w{rd rod rods} end -Unit.define('fathom') do |fathom| - fathom.definition = Unit('6 ft') +RubyUnits::Unit.define('fathom') do |fathom| + fathom.definition = RubyUnits::Unit('6 ft') fathom.aliases = %w{fathom fathoms} end -Unit.define('mil') do |mil| - mil.definition = Unit('1/1000 inch') +RubyUnits::Unit.define('mil') do |mil| + mil.definition = RubyUnits::Unit('1/1000 inch') mil.aliases = %w{mil mils} end -Unit.define('angstrom') do |ang| - ang.definition = Unit('1/10 nm') +RubyUnits::Unit.define('angstrom') do |ang| + ang.definition = RubyUnits::Unit('1/10 nm') ang.aliases = %w{ang angstrom angstroms} end # typesetting -Unit.define('point') do |point| - point.definition = Unit('1/72 ft') +RubyUnits::Unit.define('point') do |point| + point.definition = RubyUnits::Unit('1/72 ft') point.aliases = %w{point points} end -Unit.define('pica') do |pica| - pica.definition = Unit('12 point') +RubyUnits::Unit.define('pica') do |pica| + pica.definition = RubyUnits::Unit('12 point') pica.aliases = %w{P pica picas} end -Unit.define('dot') do |dot| - dot.definition = Unit('1 each') +RubyUnits::Unit.define('dot') do |dot| + dot.definition = RubyUnits::Unit('1 each') dot.aliases = %w{dot dots} dot.kind = :counting end -Unit.define('pixel') do |pixel| - pixel.definition = Unit('1 each') +RubyUnits::Unit.define('pixel') do |pixel| + pixel.definition = RubyUnits::Unit('1 each') pixel.aliases = %w{px pixel pixels} pixel.kind = :counting end -Unit.define('ppi') do |ppi| - ppi.definition = Unit('1 pixel/inch') +RubyUnits::Unit.define('ppi') do |ppi| + ppi.definition = RubyUnits::Unit('1 pixel/inch') end -Unit.define('dpi') do |dpi| - dpi.definition = Unit('1 dot/inch') +RubyUnits::Unit.define('dpi') do |dpi| + dpi.definition = RubyUnits::Unit('1 dot/inch') end # Mass -avagadro_constant = Unit('6.02214129e23 1/mol') +avagadro_constant = RubyUnits::Unit('6.02214129e23 1/mol') -Unit.define('AMU') do |amu| - amu.definition = Unit('12 kg/mol') / (12 * avagadro_constant) +RubyUnits::Unit.define('AMU') do |amu| + amu.definition = RubyUnits::Unit('12 kg/mol') / (12 * avagadro_constant) amu.aliases = %w{u AMU amu} end -Unit.define('dalton') do |dalton| - dalton.definition = Unit('1 amu') +RubyUnits::Unit.define('dalton') do |dalton| + dalton.definition = RubyUnits::Unit('1 amu') dalton.aliases = %w{Da dalton daltons} end -standard_gravitation = Unit('9.80665 m/s^2') +standard_gravitation = RubyUnits::Unit('9.80665 m/s^2') -Unit.define('metric-ton') do |mton| - mton.definition = Unit('1000 kg') +RubyUnits::Unit.define('metric-ton') do |mton| + mton.definition = RubyUnits::Unit('1000 kg') mton.aliases = %w{tonne} end # defined as a rational number to preserve accuracy and minimize round-off errors during # calculations -Unit.define('pound') do |pound| - pound.definition = Unit(Rational(45359237,1e8), 'kg') +RubyUnits::Unit.define('pound') do |pound| + pound.definition = RubyUnits::Unit(Rational(45359237,1e8), 'kg') pound.aliases = %w{lbs lb lbm pound-mass pound pounds #} end -Unit.define('ounce') do |ounce| - ounce.definition = Unit('1/16 lbs') +RubyUnits::Unit.define('ounce') do |ounce| + ounce.definition = RubyUnits::Unit('1/16 lbs') ounce.aliases = %w{oz ounce ounces} end -Unit.define('gram') do |gram| - gram.definition = Unit('1/1000 kg') +RubyUnits::Unit.define('gram') do |gram| + gram.definition = RubyUnits::Unit('1/1000 kg') gram.aliases = %w{g gram grams gramme grammes} end -Unit.define('short-ton') do |ton| - ton.definition = Unit('2000 lbs') +RubyUnits::Unit.define('short-ton') do |ton| + ton.definition = RubyUnits::Unit('2000 lbs') ton.aliases = %w{ton tn} end -Unit.define('carat') do |carat| - carat.definition = Unit('1/5000 kg') +RubyUnits::Unit.define('carat') do |carat| + carat.definition = RubyUnits::Unit('1/5000 kg') carat.aliases = %w{ct carat carats} end # time -Unit.define('minute') do |min| - min.definition = Unit('60 seconds') +RubyUnits::Unit.define('minute') do |min| + min.definition = RubyUnits::Unit('60 seconds') min.aliases = %w{min minute minutes} end -Unit.define('hour') do |hour| - hour.definition = Unit('60 minutes') +RubyUnits::Unit.define('hour') do |hour| + hour.definition = RubyUnits::Unit('60 minutes') hour.aliases = %w{h hr hrs hour hours} end -Unit.define('day') do |day| - day.definition = Unit('24 hours') +RubyUnits::Unit.define('day') do |day| + day.definition = RubyUnits::Unit('24 hours') day.aliases = %w{d day days} end -Unit.define('week') do |week| - week.definition = Unit('7 days') +RubyUnits::Unit.define('week') do |week| + week.definition = RubyUnits::Unit('7 days') week.aliases = %w{wk week weeks} end -Unit.define('fortnight') do |fortnight| - fortnight.definition = Unit('2 weeks') +RubyUnits::Unit.define('fortnight') do |fortnight| + fortnight.definition = RubyUnits::Unit('2 weeks') fortnight.aliases = %w{fortnight fortnights} end -Unit.define('year') do |year| - year.definition = Unit('31556926 seconds') # works out to 365.24219907407405 days +RubyUnits::Unit.define('year') do |year| + year.definition = RubyUnits::Unit('31556926 seconds') # works out to 365.24219907407405 days year.aliases = %w{y yr year years annum} end -Unit.define('decade') do |decade| - decade.definition = Unit('10 years') +RubyUnits::Unit.define('decade') do |decade| + decade.definition = RubyUnits::Unit('10 years') decade.aliases = %w{decade decades} end -Unit.define('century') do |century| - century.definition = Unit('100 years') +RubyUnits::Unit.define('century') do |century| + century.definition = RubyUnits::Unit('100 years') century.aliases = %w{century centuries} end # area -Unit.define('hectare') do |hectare| - hectare.definition = Unit('10000 m^2') +RubyUnits::Unit.define('hectare') do |hectare| + hectare.definition = RubyUnits::Unit('10000 m^2') end -Unit.define('acre') do |acre| - acre.definition = Unit('1 mi')**2 / 640 +RubyUnits::Unit.define('acre') do |acre| + acre.definition = RubyUnits::Unit('1 mi')**2 / 640 acre.aliases = %w{acre acres} end -Unit.define('sqft') do |sqft| - sqft.definition = Unit('1 ft^2') +RubyUnits::Unit.define('sqft') do |sqft| + sqft.definition = RubyUnits::Unit('1 ft^2') end -Unit.define('sqin') do |sqin| - sqin.definition = Unit('1 in^2') +RubyUnits::Unit.define('sqin') do |sqin| + sqin.definition = RubyUnits::Unit('1 in^2') end # volume -Unit.define('liter') do |liter| - liter.definition = Unit('1/1000 m^3') +RubyUnits::Unit.define('liter') do |liter| + liter.definition = RubyUnits::Unit('1/1000 m^3') liter.aliases = %w{l L liter liters litre litres} end -Unit.define('gallon') do |gallon| - gallon.definition = Unit('231 in^3') +RubyUnits::Unit.define('gallon') do |gallon| + gallon.definition = RubyUnits::Unit('231 in^3') gallon.aliases = %w{gal gallon gallons} end -Unit.define('quart') do |quart| - quart.definition = Unit('1/4 gal') +RubyUnits::Unit.define('quart') do |quart| + quart.definition = RubyUnits::Unit('1/4 gal') quart.aliases = %w{qt quart quarts} end -Unit.define('pint') do |pint| - pint.definition = Unit('1/8 gal') +RubyUnits::Unit.define('pint') do |pint| + pint.definition = RubyUnits::Unit('1/8 gal') pint.aliases = %w{pt pint pints} end -Unit.define('cup') do |cup| - cup.definition = Unit('1/16 gal') +RubyUnits::Unit.define('cup') do |cup| + cup.definition = RubyUnits::Unit('1/16 gal') cup.aliases = %w{cu cup cups} end -Unit.define('fluid-ounce') do |floz| - floz.definition = Unit('1/128 gal') +RubyUnits::Unit.define('fluid-ounce') do |floz| + floz.definition = RubyUnits::Unit('1/128 gal') floz.aliases = %w{floz fluid-ounce fluid-ounces} end -Unit.define('tablespoon') do |tbsp| - tbsp.definition = Unit('1/2 floz') +RubyUnits::Unit.define('tablespoon') do |tbsp| + tbsp.definition = RubyUnits::Unit('1/2 floz') tbsp.aliases = %w{tbs tbsp tablespoon tablespoons} end -Unit.define('teaspoon') do |tsp| - tsp.definition = Unit('1/3 tablespoon') +RubyUnits::Unit.define('teaspoon') do |tsp| + tsp.definition = RubyUnits::Unit('1/3 tablespoon') tsp.aliases = %w{tsp teaspoon teaspoons} end # volumetric flow -Unit.define('cfm') do |cfm| - cfm.definition = Unit('1 ft^3/minute') +RubyUnits::Unit.define('cfm') do |cfm| + cfm.definition = RubyUnits::Unit('1 ft^3/minute') cfm.aliases = %w{cfm CFM CFPM} end # speed -Unit.define('kph') do |kph| - kph.definition = Unit('1 kilometer/hour') +RubyUnits::Unit.define('kph') do |kph| + kph.definition = RubyUnits::Unit('1 kilometer/hour') end -Unit.define('mph') do |mph| - mph.definition = Unit('1 mile/hour') +RubyUnits::Unit.define('mph') do |mph| + mph.definition = RubyUnits::Unit('1 mile/hour') end -Unit.define('fps') do |fps| - fps.definition = Unit('1 foot/second') +RubyUnits::Unit.define('fps') do |fps| + fps.definition = RubyUnits::Unit('1 foot/second') end -Unit.define('knot') do |knot| - knot.definition = Unit('1 nmi/hour') +RubyUnits::Unit.define('knot') do |knot| + knot.definition = RubyUnits::Unit('1 nmi/hour') knot.aliases = %w{kt kn kts knot knots} end -Unit.define('gee') do |gee| +RubyUnits::Unit.define('gee') do |gee| # approximated as a rational number to minimize round-off errors - gee.definition = Unit(Rational(196133,20000), 'm/s^2') # equivalent to 9.80665 m/s^2 + gee.definition = RubyUnits::Unit(Rational(196133,20000), 'm/s^2') # equivalent to 9.80665 m/s^2 gee.aliases = %w{gee standard-gravitation} end # temperature differences -Unit.define('newton') do |newton| - newton.definition = Unit('1 kg*m/s^2') +RubyUnits::Unit.define('newton') do |newton| + newton.definition = RubyUnits::Unit('1 kg*m/s^2') newton.aliases = %w{N newton newtons} end -Unit.define('dyne') do |dyne| - dyne.definition = Unit('1/100000 N') +RubyUnits::Unit.define('dyne') do |dyne| + dyne.definition = RubyUnits::Unit('1/100000 N') dyne.aliases = %w{dyn dyne} end -Unit.define('pound-force') do |lbf| - lbf.definition = Unit('1 lb') * Unit('1 gee') +RubyUnits::Unit.define('pound-force') do |lbf| + lbf.definition = RubyUnits::Unit('1 lb') * RubyUnits::Unit('1 gee') lbf.aliases = %w{lbf pound-force} end -Unit.define('poundal') do |poundal| - poundal.definition = Unit('1 lb') * Unit('1 ft/s^2') +RubyUnits::Unit.define('poundal') do |poundal| + poundal.definition = RubyUnits::Unit('1 lb') * RubyUnits::Unit('1 ft/s^2') poundal.aliases = %w{pdl poundal poundals} end temp_convert_factor = Rational(2501999792983609,4503599627370496) # approximates 1/1.8 -Unit.define('celsius') do |celsius| - celsius.definition = Unit('1 degK') +RubyUnits::Unit.define('celsius') do |celsius| + celsius.definition = RubyUnits::Unit('1 degK') celsius.aliases = %w{degC celsius centigrade} end -Unit.define('fahrenheit') do |fahrenheit| - fahrenheit.definition = Unit(temp_convert_factor, 'degK') +RubyUnits::Unit.define('fahrenheit') do |fahrenheit| + fahrenheit.definition = RubyUnits::Unit(temp_convert_factor, 'degK') fahrenheit.aliases = %w{degF fahrenheit} end -Unit.define('rankine') do |rankine| - rankine.definition = Unit('1 degF') +RubyUnits::Unit.define('rankine') do |rankine| + rankine.definition = RubyUnits::Unit('1 degF') rankine.aliases = %w{degR rankine} end -Unit.define('tempC') do |tempC| - tempC.definition = Unit('1 tempK') +RubyUnits::Unit.define('tempC') do |tempC| + tempC.definition = RubyUnits::Unit('1 tempK') end -Unit.define('tempF') do |tempF| - tempF.definition = Unit(temp_convert_factor, 'tempK') +RubyUnits::Unit.define('tempF') do |tempF| + tempF.definition = RubyUnits::Unit(temp_convert_factor, 'tempK') end -Unit.define('tempR') do |tempR| - tempR.definition = Unit('1 tempF') +RubyUnits::Unit.define('tempR') do |tempR| + tempR.definition = RubyUnits::Unit('1 tempF') end # astronomy -speed_of_light = Unit('299792458 m/s') +speed_of_light = RubyUnits::Unit('299792458 m/s') -Unit.define('light-second') do |ls| - ls.definition = Unit('1 s') * speed_of_light +RubyUnits::Unit.define('light-second') do |ls| + ls.definition = RubyUnits::Unit('1 s') * speed_of_light ls.aliases = %w{ls lsec light-second} end -Unit.define('light-minute') do |lmin| - lmin.definition = Unit('1 min') * speed_of_light +RubyUnits::Unit.define('light-minute') do |lmin| + lmin.definition = RubyUnits::Unit('1 min') * speed_of_light lmin.aliases = %w{lmin light-minute} end -Unit.define('light-year') do |ly| - ly.definition = Unit('1 y') * speed_of_light +RubyUnits::Unit.define('light-year') do |ly| + ly.definition = RubyUnits::Unit('1 y') * speed_of_light ly.aliases = %w{ly light-year} end -Unit.define('parsec') do |parsec| - parsec.definition = Unit('3.26163626 ly') +RubyUnits::Unit.define('parsec') do |parsec| + parsec.definition = RubyUnits::Unit('3.26163626 ly') parsec.aliases = %w{pc parsec parsecs} end # once was '149597900000 m' but there appears to be a more accurate estimate according to wikipedia # see http://en.wikipedia.org/wiki/Astronomical_unit -Unit.define('AU') do |au| - au.definition = Unit('149597870700 m') +RubyUnits::Unit.define('AU') do |au| + au.definition = RubyUnits::Unit('149597870700 m') au.aliases = %w{AU astronomical-unit} end -Unit.define('redshift') do |red| - red.definition = Unit('1.302773e26 m') +RubyUnits::Unit.define('redshift') do |red| + red.definition = RubyUnits::Unit('1.302773e26 m') red.aliases = %w{z red-shift} end # mass -Unit.define('slug') do |slug| - slug.definition = Unit('1 lbf*s^2/ft') +RubyUnits::Unit.define('slug') do |slug| + slug.definition = RubyUnits::Unit('1 lbf*s^2/ft') slug.aliases = %w{slug slugs} end # pressure -Unit.define('pascal') do |pascal| - pascal.definition = Unit('1 kg/m*s^2') +RubyUnits::Unit.define('pascal') do |pascal| + pascal.definition = RubyUnits::Unit('1 kg/m*s^2') pascal.aliases = %w{Pa pascal pascals} end -Unit.define('bar') do |bar| - bar.definition = Unit('100 kPa') +RubyUnits::Unit.define('bar') do |bar| + bar.definition = RubyUnits::Unit('100 kPa') bar.aliases = %w{bar bars} end -Unit.define('atm') do |atm| - atm.definition = Unit('101325 Pa') +RubyUnits::Unit.define('atm') do |atm| + atm.definition = RubyUnits::Unit('101325 Pa') atm.aliases = %w{atm ATM atmosphere atmospheres} end -Unit.define('mmHg') do |mmhg| - density_of_mercury = Unit('7653360911758079/562949953421312 g/cm^3') # 13.5951 g/cm^3 at 0 tempC - mmhg.definition = Unit('1 mm') * Unit('1 gee') * density_of_mercury +RubyUnits::Unit.define('mmHg') do |mmhg| + density_of_mercury = RubyUnits::Unit('7653360911758079/562949953421312 g/cm^3') # 13.5951 g/cm^3 at 0 tempC + mmhg.definition = RubyUnits::Unit('1 mm') * RubyUnits::Unit('1 gee') * density_of_mercury end -Unit.define('inHg') do |inhg| - density_of_mercury = Unit('7653360911758079/562949953421312 g/cm^3') # 13.5951 g/cm^3 at 0 tempC - inhg.definition = Unit('1 in') * Unit('1 gee') * density_of_mercury +RubyUnits::Unit.define('inHg') do |inhg| + density_of_mercury = RubyUnits::Unit('7653360911758079/562949953421312 g/cm^3') # 13.5951 g/cm^3 at 0 tempC + inhg.definition = RubyUnits::Unit('1 in') * RubyUnits::Unit('1 gee') * density_of_mercury end -Unit.define('torr') do |torr| - torr.definition = Unit('1/760 atm') +RubyUnits::Unit.define('torr') do |torr| + torr.definition = RubyUnits::Unit('1/760 atm') torr.aliases = %w{Torr torr} end -Unit.define('psi') do |psi| - psi.definition = Unit('1 lbf/in^2') +RubyUnits::Unit.define('psi') do |psi| + psi.definition = RubyUnits::Unit('1 lbf/in^2') end -Unit.define('cmh2o') do |cmh2o| - density_of_water = Unit('1 g/cm^3') # at 4 tempC - cmh2o.definition = Unit('1 cm') * Unit('1 gee') * density_of_water +RubyUnits::Unit.define('cmh2o') do |cmh2o| + density_of_water = RubyUnits::Unit('1 g/cm^3') # at 4 tempC + cmh2o.definition = RubyUnits::Unit('1 cm') * RubyUnits::Unit('1 gee') * density_of_water cmh2o.aliases = %w{cmH2O cmh2o cmAq} end -Unit.define('inh2o') do |inh2o| - density_of_water = Unit('1 g/cm^3') # at 4 tempC - inh2o.definition = Unit('1 in') * Unit('1 gee') * density_of_water +RubyUnits::Unit.define('inh2o') do |inh2o| + density_of_water = RubyUnits::Unit('1 g/cm^3') # at 4 tempC + inh2o.definition = RubyUnits::Unit('1 in') * RubyUnits::Unit('1 gee') * density_of_water inh2o.aliases = %w{inH2O inh2o inAq} end #viscosity -Unit.define('poise') do |poise| - poise.definition = Unit('dPa*s') +RubyUnits::Unit.define('poise') do |poise| + poise.definition = RubyUnits::Unit('dPa*s') poise.aliases = %w{P poise} end -Unit.define('stokes') do |stokes| - stokes.definition = Unit('1 cm^2/s') +RubyUnits::Unit.define('stokes') do |stokes| + stokes.definition = RubyUnits::Unit('1 cm^2/s') stokes.aliases = %w{St stokes} end # #energy -Unit.define('joule') do |joule| - joule.definition = Unit('1 N*m') +RubyUnits::Unit.define('joule') do |joule| + joule.definition = RubyUnits::Unit('1 N*m') joule.aliases = %w{J joule joules} end -Unit.define('erg') do |erg| - erg.definition = Unit('1 g*cm^2/s^2') +RubyUnits::Unit.define('erg') do |erg| + erg.definition = RubyUnits::Unit('1 g*cm^2/s^2') erg.aliases = %w{erg ergs} end #power -Unit.define('watt') do |watt| - watt.definition = Unit('1 N*m/s') +RubyUnits::Unit.define('watt') do |watt| + watt.definition = RubyUnits::Unit('1 N*m/s') watt.aliases = %w{W Watt watt watts} end -Unit.define('horsepower') do |hp| - hp.definition = Unit('33000 ft*lbf/min') +RubyUnits::Unit.define('horsepower') do |hp| + hp.definition = RubyUnits::Unit('33000 ft*lbf/min') hp.aliases = %w{hp horsepower} end # energy -Unit.define('btu') do |btu| - btu.definition = Unit('2320092679909671/2199023255552 J') # 1055.056 J --- ISO standard +RubyUnits::Unit.define('btu') do |btu| + btu.definition = RubyUnits::Unit('2320092679909671/2199023255552 J') # 1055.056 J --- ISO standard btu.aliases = %w{Btu btu Btus btus} end -Unit.define('therm') do |therm| - therm.definition = Unit('100 kBtu') +RubyUnits::Unit.define('therm') do |therm| + therm.definition = RubyUnits::Unit('100 kBtu') therm.aliases = %w{thm therm therms Therm} end # "small" calorie -Unit.define('calorie') do |calorie| - calorie.definition = Unit('4.184 J') +RubyUnits::Unit.define('calorie') do |calorie| + calorie.definition = RubyUnits::Unit('4.184 J') calorie.aliases = %w{cal calorie calories} end # "big" calorie -Unit.define('Calorie') do |calorie| - calorie.definition = Unit('1 kcal') +RubyUnits::Unit.define('Calorie') do |calorie| + calorie.definition = RubyUnits::Unit('1 kcal') calorie.aliases = %w{Cal Calorie Calories} end -Unit.define('molar') do |molar| - molar.definition = Unit('1 mole/l') +RubyUnits::Unit.define('molar') do |molar| + molar.definition = RubyUnits::Unit('1 mole/l') molar.aliases = %w{M molar} end # potential -Unit.define('volt') do |volt| - volt.definition = Unit('1 W/A') +RubyUnits::Unit.define('volt') do |volt| + volt.definition = RubyUnits::Unit('1 W/A') volt.aliases = %w{V volt volts} end # capacitance -Unit.define('farad') do |farad| - farad.definition = Unit('1 A*s/V') +RubyUnits::Unit.define('farad') do |farad| + farad.definition = RubyUnits::Unit('1 A*s/V') farad.aliases = %w{F farad farads} end # charge -Unit.define('coulomb') do |coulomb| - coulomb.definition = Unit('1 A*s') +RubyUnits::Unit.define('coulomb') do |coulomb| + coulomb.definition = RubyUnits::Unit('1 A*s') coulomb.aliases = %w{C coulomb coulombs} end # conductance -Unit.define('siemens') do |siemens| - siemens.definition = Unit('1 A/V') +RubyUnits::Unit.define('siemens') do |siemens| + siemens.definition = RubyUnits::Unit('1 A/V') siemens.aliases = %w{S siemens} end # inductance -Unit.define('henry') do |henry| - henry.definition = Unit('1 J/A^2') +RubyUnits::Unit.define('henry') do |henry| + henry.definition = RubyUnits::Unit('1 J/A^2') henry.aliases = %w{H henry henries} end # resistance -Unit.define('ohm') do |ohm| - ohm.definition = Unit('1 V/A') +RubyUnits::Unit.define('ohm') do |ohm| + ohm.definition = RubyUnits::Unit('1 V/A') ohm.aliases = %w{Ohm ohm ohms} end # magnetism -Unit.define('weber') do |weber| - weber.definition = Unit('1 V*s') +RubyUnits::Unit.define('weber') do |weber| + weber.definition = RubyUnits::Unit('1 V*s') weber.aliases = %w{Wb weber webers} end -Unit.define('tesla') do |tesla| - tesla.definition = Unit('1 V*s/m^2') +RubyUnits::Unit.define('tesla') do |tesla| + tesla.definition = RubyUnits::Unit('1 V*s/m^2') tesla.aliases = %w{T tesla teslas} end -Unit.define('gauss') do |gauss| - gauss.definition = Unit('100 microT') +RubyUnits::Unit.define('gauss') do |gauss| + gauss.definition = RubyUnits::Unit('100 microT') gauss.aliases = %w{G gauss} end -Unit.define('maxwell') do |maxwell| - maxwell.definition = Unit('1 gauss*cm^2') +RubyUnits::Unit.define('maxwell') do |maxwell| + maxwell.definition = RubyUnits::Unit('1 gauss*cm^2') maxwell.aliases = %w{Mx maxwell maxwells} end -Unit.define('oersted') do |oersted| - oersted.definition = Unit(250.0/Math::PI, 'A/m') +RubyUnits::Unit.define('oersted') do |oersted| + oersted.definition = RubyUnits::Unit(250.0/Math::PI, 'A/m') oersted.aliases = %w{Oe oersted oersteds} end #activity -Unit.define('katal') do |katal| - katal.definition = Unit('1 mole/sec') +RubyUnits::Unit.define('katal') do |katal| + katal.definition = RubyUnits::Unit('1 mole/sec') katal.aliases = %w{kat katal} end -Unit.define('unit') do |unit| - unit.definition = Unit('1/60 microkatal') - unit.aliases = %w{U enzUnit} +RubyUnits::Unit.define('unit') do |unit| + unit.definition = RubyUnits::Unit('1/60 microkatal') + unit.aliases = %w{U enzRubyUnits::Unit} end #frequency -Unit.define('hertz') do |hz| - hz.definition = Unit('1 1/s') +RubyUnits::Unit.define('hertz') do |hz| + hz.definition = RubyUnits::Unit('1 1/s') hz.aliases = %w{Hz hertz} end #angle -Unit.define('degree') do |deg| - deg.definition = Unit(Math::PI / 180.0, 'radian') +RubyUnits::Unit.define('degree') do |deg| + deg.definition = RubyUnits::Unit(Math::PI / 180.0, 'radian') deg.aliases = %w{deg degree degrees} end -Unit.define('grad') do |grad| - grad.definition = Unit(Math::PI / 200.0, 'radian') +RubyUnits::Unit.define('grad') do |grad| + grad.definition = RubyUnits::Unit(Math::PI / 200.0, 'radian') grad.aliases = %w{grad gradian grads} end #rotation -Unit.define('rotation') do |rotation| - rotation.definition = Unit(2.0*Math::PI, 'radian') +RubyUnits::Unit.define('rotation') do |rotation| + rotation.definition = RubyUnits::Unit(2.0*Math::PI, 'radian') end -Unit.define('rpm') do |rpm| - rpm.definition = Unit('1 rotation/min') +RubyUnits::Unit.define('rpm') do |rpm| + rpm.definition = RubyUnits::Unit('1 rotation/min') end #memory -Unit.define('bit') do |bit| - bit.definition = Unit('1/8 byte') +RubyUnits::Unit.define('bit') do |bit| + bit.definition = RubyUnits::Unit('1/8 byte') bit.aliases = %w{b bit} end #currency -Unit.define('cents') do |cents| - cents.definition = Unit('1/100 dollar') +RubyUnits::Unit.define('cents') do |cents| + cents.definition = RubyUnits::Unit('1/100 dollar') end #luminosity -Unit.define('lumen') do |lumen| - lumen.definition = Unit('1 cd*steradian') +RubyUnits::Unit.define('lumen') do |lumen| + lumen.definition = RubyUnits::Unit('1 cd*steradian') lumen.aliases = %w{lm lumen} end -Unit.define('lux') do |lux| - lux.definition = Unit('1 lumen/m^2') +RubyUnits::Unit.define('lux') do |lux| + lux.definition = RubyUnits::Unit('1 lumen/m^2') end #radiation -Unit.define('gray') do |gray| - gray.definition = Unit('1 J/kg') +RubyUnits::Unit.define('gray') do |gray| + gray.definition = RubyUnits::Unit('1 J/kg') gray.aliases = %w{Gy gray grays} end -Unit.define('roentgen') do |roentgen| - roentgen.definition = Unit('2.58e-4 C/kg') +RubyUnits::Unit.define('roentgen') do |roentgen| + roentgen.definition = RubyUnits::Unit('2.58e-4 C/kg') roentgen.aliases = %w{R roentgen} end -Unit.define('sievert') do |sievert| - sievert.definition = Unit('1 J/kg') +RubyUnits::Unit.define('sievert') do |sievert| + sievert.definition = RubyUnits::Unit('1 J/kg') sievert.aliases = %w{Sv sievert sieverts} end -Unit.define('becquerel') do |becquerel| - becquerel.definition = Unit('1 1/s') +RubyUnits::Unit.define('becquerel') do |becquerel| + becquerel.definition = RubyUnits::Unit('1 1/s') becquerel.aliases = %w{Bq becquerel becquerels} end -Unit.define('curie') do |curie| - curie.definition = Unit('37 GBq') +RubyUnits::Unit.define('curie') do |curie| + curie.definition = RubyUnits::Unit('37 GBq') curie.aliases = %w{Ci curie curies} end -Unit.define('count') do |count| - count.definition = Unit('1 each') +RubyUnits::Unit.define('count') do |count| + count.definition = RubyUnits::Unit('1 each') count.kind = :counting end # rate -Unit.define('cpm') do |cpm| - cpm.definition = Unit('1 count/min') +RubyUnits::Unit.define('cpm') do |cpm| + cpm.definition = RubyUnits::Unit('1 count/min') end -Unit.define('dpm') do |dpm| - dpm.definition = Unit('1 count/min') +RubyUnits::Unit.define('dpm') do |dpm| + dpm.definition = RubyUnits::Unit('1 count/min') end -Unit.define('bpm') do |bpm| - bpm.definition = Unit('1 count/min') +RubyUnits::Unit.define('bpm') do |bpm| + bpm.definition = RubyUnits::Unit('1 count/min') end # misc -Unit.define('dozen') do |dozen| - dozen.definition = Unit('12 each') +RubyUnits::Unit.define('dozen') do |dozen| + dozen.definition = RubyUnits::Unit('12 each') dozen.aliases = %w{doz dz dozen} dozen.kind = :counting end -Unit.define('gross') do |gross| - gross.definition = Unit('12 dozen') +RubyUnits::Unit.define('gross') do |gross| + gross.definition = RubyUnits::Unit('12 dozen') gross.aliases = %w{gr gross} gross.kind = :counting end -Unit.define('cell') do |cell| - cell.definition = Unit('1 each') +RubyUnits::Unit.define('cell') do |cell| + cell.definition = RubyUnits::Unit('1 each') cell.aliases = %w{cells cell} cell.kind = :counting end -Unit.define('base-pair') do |bp| - bp.definition = Unit('1 each') +RubyUnits::Unit.define('base-pair') do |bp| + bp.definition = RubyUnits::Unit('1 each') bp.aliases = %w{bp base-pair} bp.kind = :counting end -Unit.define('nucleotide') do |nt| - nt.definition = Unit('1 each') +RubyUnits::Unit.define('nucleotide') do |nt| + nt.definition = RubyUnits::Unit('1 each') nt.aliases = %w{nt} nt.kind = :counting end -Unit.define('molecule') do |molecule| - molecule.definition = Unit('1 each') +RubyUnits::Unit.define('molecule') do |molecule| + molecule.definition = RubyUnits::Unit('1 each') molecule.aliases = %w{molecule molecules} molecule.kind = :counting end -Unit.define('percent') do |percent| - percent.definition = Unit('1/100') +RubyUnits::Unit.define('percent') do |percent| + percent.definition = RubyUnits::Unit('1/100') percent.aliases = %w{% percent} end -Unit.define('ppm') do |ppm| - ppm.definition = Unit(1) / 1_000_000 +RubyUnits::Unit.define('ppm') do |ppm| + ppm.definition = RubyUnits::Unit(1) / 1_000_000 end -Unit.define('ppb') do |ppb| - ppb.definition = Unit(1) / 1_000_000_000 +RubyUnits::Unit.define('ppb') do |ppb| + ppb.definition = RubyUnits::Unit(1) / 1_000_000_000 end diff --git a/lib/ruby_units/version.rb b/lib/ruby_units/version.rb index 1d6dee39..059e2ca3 100644 --- a/lib/ruby_units/version.rb +++ b/lib/ruby_units/version.rb @@ -1,6 +1,8 @@ -class Unit < Numeric - # Pull the version number from the VERSION file - module Version - STRING = File.read(File.dirname(__FILE__) + "/../../VERSION") +module RubyUnits + class Unit < Numeric + # Pull the version number from the VERSION file + module Version + STRING = File.read(File.dirname(__FILE__) + "/../../VERSION") + end end -end \ No newline at end of file +end diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index 408d7698..e0501b0c 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -603,7 +603,7 @@ describe '#to_yaml' do subject { Unit('1 mm') } - its(:to_yaml) {should =~ /--- !ruby\/object:Unit/ } + its(:to_yaml) {should =~ /--- !ruby\/object:RubyUnits::Unit/ } end describe "#definition" do @@ -834,7 +834,7 @@ specify { Unit("2 m").should > Unit("1 ft")} specify { Unit("70 tempF").should > Unit("10 degC")} specify { Unit("1 m").should > 0 } - specify { expect { Unit("1 m").should_not > nil}.to raise_error(ArgumentError, /comparison of Unit with (nil failed|NilClass)/) } + specify { expect { Unit("1 m").should_not > nil}.to raise_error(ArgumentError, /comparison of RubyUnits::Unit with (nil failed|NilClass)/) } end context "incompatible units cannot be compared" do From 5aacc00b09eb7f2ef9e18110ff01df915824a21e Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 6 Jul 2013 11:59:09 -0400 Subject: [PATCH 2/5] Don't load 'Unit()' helper if only loading namespaced code. Add travis config for 2.0.0 --- .travis.yml | 3 +- README.md | 6 +- lib/ruby-units | 1 + lib/ruby-units.rb | 7 +- lib/ruby_units/namespaced.rb | 30 ++- lib/ruby_units/time.rb | 1 + lib/ruby_units/unit.rb | 16 +- lib/ruby_units/unit_definitions.rb | 6 +- lib/ruby_units/unit_definitions/base.rb | 2 +- lib/ruby_units/unit_definitions/standard.rb | 274 ++++++++++---------- 10 files changed, 176 insertions(+), 170 deletions(-) create mode 120000 lib/ruby-units diff --git a/.travis.yml b/.travis.yml index 4b6f75d1..07bf44b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: ruby rvm: - 1.9.3 - jruby-19mode # JRuby in 1.9 mode + - 2.0.0 jdk: - openjdk6 - openjdk7 @@ -9,4 +10,4 @@ matrix: exclude: - rvm: 1.9.3 jdk: openjdk7 -script: bundle exec rake --trace \ No newline at end of file +script: bundle exec rake --trace diff --git a/README.md b/README.md index 7d61e19f..45e2d86a 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,7 @@ [![Build Status](https://secure.travis-ci.org/olbrich/ruby-units.png)](http://travis-ci.org/olbrich/ruby-units) -Kevin C. Olbrich, Ph.D. - -[Sciwerks.com](http://www.sciwerks.com) +Kevin C. Olbrich, Ph.D. Project page: [http://github.com/olbrich/ruby-units](http://github.com/olbrich/ruby-units) @@ -36,7 +34,7 @@ This package may be installed using: `gem install ruby-units` 2. use SI notation when possible 3. avoid using spaces in unit names -## Unit compatability: +## Unit compatibility: Many methods require that the units of two operands are compatible. Compatible units are those that can be easily converted into each other, such as 'meters' and 'feet'. unit1 =~ unit2 #=> true if units are compatible diff --git a/lib/ruby-units b/lib/ruby-units new file mode 120000 index 00000000..661dac0c --- /dev/null +++ b/lib/ruby-units @@ -0,0 +1 @@ +./ruby_units \ No newline at end of file diff --git a/lib/ruby-units.rb b/lib/ruby-units.rb index 820e4f30..36b5cb09 100755 --- a/lib/ruby-units.rb +++ b/lib/ruby-units.rb @@ -1,6 +1,9 @@ - $LOAD_PATH << File.dirname(__FILE__) -require 'ruby_units/namespaced' +require_relative 'ruby_units/namespaced' + +# only include the Unit('unit') helper if we aren't fully namespaced +require_relative 'ruby_units/object' + Unit = RubyUnits::Unit diff --git a/lib/ruby_units/namespaced.rb b/lib/ruby_units/namespaced.rb index 2efc61e1..229fdd00 100644 --- a/lib/ruby_units/namespaced.rb +++ b/lib/ruby_units/namespaced.rb @@ -1,14 +1,16 @@ -# require this file to avoid creating an class alias from Unit to RubyUnits::Unit -require "ruby_units/version" -require "ruby_units/definition" -require "ruby_units/cache" -require 'ruby_units/array' -require 'ruby_units/date' -require 'ruby_units/time' -require 'ruby_units/math' -require 'ruby_units/numeric' -require 'ruby_units/object' -require 'ruby_units/string' -require 'ruby_units/unit' -require 'ruby_units/fixnum' -require 'ruby_units/unit_definitions' + +$LOAD_PATH << File.dirname(__FILE__) + +# require_relative this file to avoid creating an class alias from Unit to RubyUnits::Unit +require_relative 'version' +require_relative 'definition' +require_relative 'cache' +require_relative 'array' +require_relative 'date' +require_relative 'time' +require_relative 'math' +require_relative 'numeric' +require_relative 'string' +require_relative 'unit' +require_relative 'fixnum' +require_relative 'unit_definitions' diff --git a/lib/ruby_units/time.rb b/lib/ruby_units/time.rb index 020c602e..78488546 100644 --- a/lib/ruby_units/time.rb +++ b/lib/ruby_units/time.rb @@ -1,3 +1,4 @@ +require 'time' # # Time math is handled slightly differently. The difference is considered to be an exact duration if # the subtracted value is in hours, minutes, or seconds. It is rounded to the nearest day if the offset diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 200be03b..694735e7 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -25,7 +25,7 @@ # @example Define a new unit # RubyUnits::Unit.define("foobar") do |unit| # unit.aliases = %w{foo fb foo-bar} -# unit.definition = Unit("1 baz") +# unit.definition = RubyUnits::Unit.new("1 baz") # end # # @todo fix class variables so they conform to standard naming conventions and refactor away as many of them as possible @@ -177,11 +177,11 @@ def self.definitions # # @example Block form # RubyUnits::Unit.define('foobar') do |foobar| - # foobar.definition = Unit("1 baz") + # foobar.definition = RubyUnits::Unit.new("1 baz") # end # # @example RubyUnits::Unit::Definition form - # unit_definition = RubyUnits::Unit::Definition.new("foobar") {|foobar| foobar.definition = Unit("1 baz")} + # unit_definition = RubyUnits::Unit::Definition.new("foobar") {|foobar| foobar.definition = RubyUnits::Unit.new("1 baz")} # RubyUnits::Unit.define(unit_definition) def self.define(unit_definition, &block) if block_given? @@ -674,8 +674,8 @@ def =~(other) # Compare two units. Returns true if quantities and units match # @example - # Unit("100 cm") === Unit("100 cm") # => true - # Unit("100 cm") === Unit("1 m") # => false + # RubyUnits::Unit.new("100 cm") === RubyUnits::Unit.new("100 cm") # => true + # RubyUnits::Unit.new("100 cm") === RubyUnits::Unit.new("1 m") # => false # @param [Object] other # @return [Boolean] def ===(other) @@ -928,7 +928,7 @@ def root(n) # returns inverse of Unit (1/unit) # @return [Unit] def inverse - return Unit("1") / self + return RubyUnits::Unit.new("1") / self end # convert to a specified unit string or to the same units as another Unit @@ -1415,14 +1415,14 @@ def parse(passed_unit_string="0") if defined?(Complex) && unit_string =~ COMPLEX_NUMBER real, imaginary, unit_s = unit_string.scan(COMPLEX_REGEX)[0] - result = Unit(unit_s || '1') * Complex(real.to_f, imaginary.to_f) + result = RubyUnits::Unit.new(unit_s || '1') * Complex(real.to_f, imaginary.to_f) copy(result) return end if defined?(Rational) && unit_string =~ RATIONAL_NUMBER numerator, denominator, unit_s = unit_string.scan(RATIONAL_REGEX)[0] - result = Unit(unit_s || '1') * Rational(numerator.to_i, denominator.to_i) + result = RubyUnits::Unit.new(unit_s || '1') * Rational(numerator.to_i, denominator.to_i) copy(result) return end diff --git a/lib/ruby_units/unit_definitions.rb b/lib/ruby_units/unit_definitions.rb index 4f6b0ea6..0aa0331f 100644 --- a/lib/ruby_units/unit_definitions.rb +++ b/lib/ruby_units/unit_definitions.rb @@ -1,3 +1,3 @@ -require 'ruby_units/unit_definitions/prefix' -require 'ruby_units/unit_definitions/base' -require 'ruby_units/unit_definitions/standard' +require_relative 'unit_definitions/prefix' +require_relative 'unit_definitions/base' +require_relative 'unit_definitions/standard' diff --git a/lib/ruby_units/unit_definitions/base.rb b/lib/ruby_units/unit_definitions/base.rb index a18c67bc..952cc238 100644 --- a/lib/ruby_units/unit_definitions/base.rb +++ b/lib/ruby_units/unit_definitions/base.rb @@ -1,5 +1,5 @@ # seed the cache -RubyUnits::Unit('1') +RubyUnits::Unit.new('1') RubyUnits::Unit.define("meter") do |unit| unit.scalar = 1 diff --git a/lib/ruby_units/unit_definitions/standard.rb b/lib/ruby_units/unit_definitions/standard.rb index 0a40d1f2..17ec11bd 100644 --- a/lib/ruby_units/unit_definitions/standard.rb +++ b/lib/ruby_units/unit_definitions/standard.rb @@ -1,705 +1,705 @@ # length units RubyUnits::Unit.define('inch') do |inch| - inch.definition = RubyUnits::Unit('254/10000 meter') + inch.definition = RubyUnits::Unit.new('254/10000 meter') inch.aliases = %w{in inch inches "} end RubyUnits::Unit.define('foot') do |foot| - foot.definition = RubyUnits::Unit('12 inches') + foot.definition = RubyUnits::Unit.new('12 inches') foot.aliases = %w{ft foot feet '} end RubyUnits::Unit.define('survey-foot') do |sft| - sft.definition = RubyUnits::Unit('1200/3937 meter') + sft.definition = RubyUnits::Unit.new('1200/3937 meter') sft.aliases = %w{sft sfoot sfeet} end RubyUnits::Unit.define('yard') do |yard| - yard.definition = RubyUnits::Unit('3 ft') + yard.definition = RubyUnits::Unit.new('3 ft') yard.aliases = %w{yd yard yards} end RubyUnits::Unit.define('mile') do |mile| - mile.definition = RubyUnits::Unit('5280 ft') + mile.definition = RubyUnits::Unit.new('5280 ft') mile.aliases = %w{mi mile miles} end RubyUnits::Unit.define('naut-mile') do |naut| - naut.definition = RubyUnits::Unit('1852 m') + naut.definition = RubyUnits::Unit.new('1852 m') naut.aliases = %w{nmi M NM} end # on land RubyUnits::Unit.define('league') do |league| - league.definition = RubyUnits::Unit('3 miles') + league.definition = RubyUnits::Unit.new('3 miles') league.aliases = %w{league leagues} end # at sea RubyUnits::Unit.define('naut-league') do |naut_league| - naut_league.definition = RubyUnits::Unit('3 nmi') + naut_league.definition = RubyUnits::Unit.new('3 nmi') naut_league.aliases = %w{nleague nleagues} end RubyUnits::Unit.define('furlong') do |furlong| - furlong.definition = RubyUnits::Unit('1/8 mile') + furlong.definition = RubyUnits::Unit.new('1/8 mile') furlong.aliases = %w{fur furlong furlongs} end RubyUnits::Unit.define('rod') do |rod| - rod.definition = RubyUnits::Unit('33/2 feet') + rod.definition = RubyUnits::Unit.new('33/2 feet') rod.aliases = %w{rd rod rods} end RubyUnits::Unit.define('fathom') do |fathom| - fathom.definition = RubyUnits::Unit('6 ft') + fathom.definition = RubyUnits::Unit.new('6 ft') fathom.aliases = %w{fathom fathoms} end RubyUnits::Unit.define('mil') do |mil| - mil.definition = RubyUnits::Unit('1/1000 inch') + mil.definition = RubyUnits::Unit.new('1/1000 inch') mil.aliases = %w{mil mils} end RubyUnits::Unit.define('angstrom') do |ang| - ang.definition = RubyUnits::Unit('1/10 nm') + ang.definition = RubyUnits::Unit.new('1/10 nm') ang.aliases = %w{ang angstrom angstroms} end # typesetting RubyUnits::Unit.define('point') do |point| - point.definition = RubyUnits::Unit('1/72 ft') + point.definition = RubyUnits::Unit.new('1/72 ft') point.aliases = %w{point points} end RubyUnits::Unit.define('pica') do |pica| - pica.definition = RubyUnits::Unit('12 point') + pica.definition = RubyUnits::Unit.new('12 point') pica.aliases = %w{P pica picas} end RubyUnits::Unit.define('dot') do |dot| - dot.definition = RubyUnits::Unit('1 each') + dot.definition = RubyUnits::Unit.new('1 each') dot.aliases = %w{dot dots} dot.kind = :counting end RubyUnits::Unit.define('pixel') do |pixel| - pixel.definition = RubyUnits::Unit('1 each') + pixel.definition = RubyUnits::Unit.new('1 each') pixel.aliases = %w{px pixel pixels} pixel.kind = :counting end RubyUnits::Unit.define('ppi') do |ppi| - ppi.definition = RubyUnits::Unit('1 pixel/inch') + ppi.definition = RubyUnits::Unit.new('1 pixel/inch') end RubyUnits::Unit.define('dpi') do |dpi| - dpi.definition = RubyUnits::Unit('1 dot/inch') + dpi.definition = RubyUnits::Unit.new('1 dot/inch') end # Mass -avagadro_constant = RubyUnits::Unit('6.02214129e23 1/mol') +avagadro_constant = RubyUnits::Unit.new('6.02214129e23 1/mol') RubyUnits::Unit.define('AMU') do |amu| - amu.definition = RubyUnits::Unit('12 kg/mol') / (12 * avagadro_constant) + amu.definition = RubyUnits::Unit.new('12 kg/mol') / (12 * avagadro_constant) amu.aliases = %w{u AMU amu} end RubyUnits::Unit.define('dalton') do |dalton| - dalton.definition = RubyUnits::Unit('1 amu') + dalton.definition = RubyUnits::Unit.new('1 amu') dalton.aliases = %w{Da dalton daltons} end -standard_gravitation = RubyUnits::Unit('9.80665 m/s^2') +standard_gravitation = RubyUnits::Unit.new('9.80665 m/s^2') RubyUnits::Unit.define('metric-ton') do |mton| - mton.definition = RubyUnits::Unit('1000 kg') + mton.definition = RubyUnits::Unit.new('1000 kg') mton.aliases = %w{tonne} end # defined as a rational number to preserve accuracy and minimize round-off errors during # calculations RubyUnits::Unit.define('pound') do |pound| - pound.definition = RubyUnits::Unit(Rational(45359237,1e8), 'kg') + pound.definition = RubyUnits::Unit.new(Rational(45359237,1e8), 'kg') pound.aliases = %w{lbs lb lbm pound-mass pound pounds #} end RubyUnits::Unit.define('ounce') do |ounce| - ounce.definition = RubyUnits::Unit('1/16 lbs') + ounce.definition = RubyUnits::Unit.new('1/16 lbs') ounce.aliases = %w{oz ounce ounces} end RubyUnits::Unit.define('gram') do |gram| - gram.definition = RubyUnits::Unit('1/1000 kg') + gram.definition = RubyUnits::Unit.new('1/1000 kg') gram.aliases = %w{g gram grams gramme grammes} end RubyUnits::Unit.define('short-ton') do |ton| - ton.definition = RubyUnits::Unit('2000 lbs') + ton.definition = RubyUnits::Unit.new('2000 lbs') ton.aliases = %w{ton tn} end RubyUnits::Unit.define('carat') do |carat| - carat.definition = RubyUnits::Unit('1/5000 kg') + carat.definition = RubyUnits::Unit.new('1/5000 kg') carat.aliases = %w{ct carat carats} end # time RubyUnits::Unit.define('minute') do |min| - min.definition = RubyUnits::Unit('60 seconds') + min.definition = RubyUnits::Unit.new('60 seconds') min.aliases = %w{min minute minutes} end RubyUnits::Unit.define('hour') do |hour| - hour.definition = RubyUnits::Unit('60 minutes') + hour.definition = RubyUnits::Unit.new('60 minutes') hour.aliases = %w{h hr hrs hour hours} end RubyUnits::Unit.define('day') do |day| - day.definition = RubyUnits::Unit('24 hours') + day.definition = RubyUnits::Unit.new('24 hours') day.aliases = %w{d day days} end RubyUnits::Unit.define('week') do |week| - week.definition = RubyUnits::Unit('7 days') + week.definition = RubyUnits::Unit.new('7 days') week.aliases = %w{wk week weeks} end RubyUnits::Unit.define('fortnight') do |fortnight| - fortnight.definition = RubyUnits::Unit('2 weeks') + fortnight.definition = RubyUnits::Unit.new('2 weeks') fortnight.aliases = %w{fortnight fortnights} end RubyUnits::Unit.define('year') do |year| - year.definition = RubyUnits::Unit('31556926 seconds') # works out to 365.24219907407405 days + year.definition = RubyUnits::Unit.new('31556926 seconds') # works out to 365.24219907407405 days year.aliases = %w{y yr year years annum} end RubyUnits::Unit.define('decade') do |decade| - decade.definition = RubyUnits::Unit('10 years') + decade.definition = RubyUnits::Unit.new('10 years') decade.aliases = %w{decade decades} end RubyUnits::Unit.define('century') do |century| - century.definition = RubyUnits::Unit('100 years') + century.definition = RubyUnits::Unit.new('100 years') century.aliases = %w{century centuries} end # area RubyUnits::Unit.define('hectare') do |hectare| - hectare.definition = RubyUnits::Unit('10000 m^2') + hectare.definition = RubyUnits::Unit.new('10000 m^2') end RubyUnits::Unit.define('acre') do |acre| - acre.definition = RubyUnits::Unit('1 mi')**2 / 640 + acre.definition = RubyUnits::Unit.new('1 mi')**2 / 640 acre.aliases = %w{acre acres} end RubyUnits::Unit.define('sqft') do |sqft| - sqft.definition = RubyUnits::Unit('1 ft^2') + sqft.definition = RubyUnits::Unit.new('1 ft^2') end RubyUnits::Unit.define('sqin') do |sqin| - sqin.definition = RubyUnits::Unit('1 in^2') + sqin.definition = RubyUnits::Unit.new('1 in^2') end # volume RubyUnits::Unit.define('liter') do |liter| - liter.definition = RubyUnits::Unit('1/1000 m^3') + liter.definition = RubyUnits::Unit.new('1/1000 m^3') liter.aliases = %w{l L liter liters litre litres} end RubyUnits::Unit.define('gallon') do |gallon| - gallon.definition = RubyUnits::Unit('231 in^3') + gallon.definition = RubyUnits::Unit.new('231 in^3') gallon.aliases = %w{gal gallon gallons} end RubyUnits::Unit.define('quart') do |quart| - quart.definition = RubyUnits::Unit('1/4 gal') + quart.definition = RubyUnits::Unit.new('1/4 gal') quart.aliases = %w{qt quart quarts} end RubyUnits::Unit.define('pint') do |pint| - pint.definition = RubyUnits::Unit('1/8 gal') + pint.definition = RubyUnits::Unit.new('1/8 gal') pint.aliases = %w{pt pint pints} end RubyUnits::Unit.define('cup') do |cup| - cup.definition = RubyUnits::Unit('1/16 gal') + cup.definition = RubyUnits::Unit.new('1/16 gal') cup.aliases = %w{cu cup cups} end RubyUnits::Unit.define('fluid-ounce') do |floz| - floz.definition = RubyUnits::Unit('1/128 gal') + floz.definition = RubyUnits::Unit.new('1/128 gal') floz.aliases = %w{floz fluid-ounce fluid-ounces} end RubyUnits::Unit.define('tablespoon') do |tbsp| - tbsp.definition = RubyUnits::Unit('1/2 floz') + tbsp.definition = RubyUnits::Unit.new('1/2 floz') tbsp.aliases = %w{tbs tbsp tablespoon tablespoons} end RubyUnits::Unit.define('teaspoon') do |tsp| - tsp.definition = RubyUnits::Unit('1/3 tablespoon') + tsp.definition = RubyUnits::Unit.new('1/3 tablespoon') tsp.aliases = %w{tsp teaspoon teaspoons} end # volumetric flow RubyUnits::Unit.define('cfm') do |cfm| - cfm.definition = RubyUnits::Unit('1 ft^3/minute') + cfm.definition = RubyUnits::Unit.new('1 ft^3/minute') cfm.aliases = %w{cfm CFM CFPM} end # speed RubyUnits::Unit.define('kph') do |kph| - kph.definition = RubyUnits::Unit('1 kilometer/hour') + kph.definition = RubyUnits::Unit.new('1 kilometer/hour') end RubyUnits::Unit.define('mph') do |mph| - mph.definition = RubyUnits::Unit('1 mile/hour') + mph.definition = RubyUnits::Unit.new('1 mile/hour') end RubyUnits::Unit.define('fps') do |fps| - fps.definition = RubyUnits::Unit('1 foot/second') + fps.definition = RubyUnits::Unit.new('1 foot/second') end RubyUnits::Unit.define('knot') do |knot| - knot.definition = RubyUnits::Unit('1 nmi/hour') + knot.definition = RubyUnits::Unit.new('1 nmi/hour') knot.aliases = %w{kt kn kts knot knots} end RubyUnits::Unit.define('gee') do |gee| # approximated as a rational number to minimize round-off errors - gee.definition = RubyUnits::Unit(Rational(196133,20000), 'm/s^2') # equivalent to 9.80665 m/s^2 + gee.definition = RubyUnits::Unit.new(Rational(196133,20000), 'm/s^2') # equivalent to 9.80665 m/s^2 gee.aliases = %w{gee standard-gravitation} end # temperature differences RubyUnits::Unit.define('newton') do |newton| - newton.definition = RubyUnits::Unit('1 kg*m/s^2') + newton.definition = RubyUnits::Unit.new('1 kg*m/s^2') newton.aliases = %w{N newton newtons} end RubyUnits::Unit.define('dyne') do |dyne| - dyne.definition = RubyUnits::Unit('1/100000 N') + dyne.definition = RubyUnits::Unit.new('1/100000 N') dyne.aliases = %w{dyn dyne} end RubyUnits::Unit.define('pound-force') do |lbf| - lbf.definition = RubyUnits::Unit('1 lb') * RubyUnits::Unit('1 gee') + lbf.definition = RubyUnits::Unit.new('1 lb') * RubyUnits::Unit.new('1 gee') lbf.aliases = %w{lbf pound-force} end RubyUnits::Unit.define('poundal') do |poundal| - poundal.definition = RubyUnits::Unit('1 lb') * RubyUnits::Unit('1 ft/s^2') + poundal.definition = RubyUnits::Unit.new('1 lb') * RubyUnits::Unit.new('1 ft/s^2') poundal.aliases = %w{pdl poundal poundals} end temp_convert_factor = Rational(2501999792983609,4503599627370496) # approximates 1/1.8 RubyUnits::Unit.define('celsius') do |celsius| - celsius.definition = RubyUnits::Unit('1 degK') + celsius.definition = RubyUnits::Unit.new('1 degK') celsius.aliases = %w{degC celsius centigrade} end RubyUnits::Unit.define('fahrenheit') do |fahrenheit| - fahrenheit.definition = RubyUnits::Unit(temp_convert_factor, 'degK') + fahrenheit.definition = RubyUnits::Unit.new(temp_convert_factor, 'degK') fahrenheit.aliases = %w{degF fahrenheit} end RubyUnits::Unit.define('rankine') do |rankine| - rankine.definition = RubyUnits::Unit('1 degF') + rankine.definition = RubyUnits::Unit.new('1 degF') rankine.aliases = %w{degR rankine} end RubyUnits::Unit.define('tempC') do |tempC| - tempC.definition = RubyUnits::Unit('1 tempK') + tempC.definition = RubyUnits::Unit.new('1 tempK') end RubyUnits::Unit.define('tempF') do |tempF| - tempF.definition = RubyUnits::Unit(temp_convert_factor, 'tempK') + tempF.definition = RubyUnits::Unit.new(temp_convert_factor, 'tempK') end RubyUnits::Unit.define('tempR') do |tempR| - tempR.definition = RubyUnits::Unit('1 tempF') + tempR.definition = RubyUnits::Unit.new('1 tempF') end # astronomy -speed_of_light = RubyUnits::Unit('299792458 m/s') +speed_of_light = RubyUnits::Unit.new('299792458 m/s') RubyUnits::Unit.define('light-second') do |ls| - ls.definition = RubyUnits::Unit('1 s') * speed_of_light + ls.definition = RubyUnits::Unit.new('1 s') * speed_of_light ls.aliases = %w{ls lsec light-second} end RubyUnits::Unit.define('light-minute') do |lmin| - lmin.definition = RubyUnits::Unit('1 min') * speed_of_light + lmin.definition = RubyUnits::Unit.new('1 min') * speed_of_light lmin.aliases = %w{lmin light-minute} end RubyUnits::Unit.define('light-year') do |ly| - ly.definition = RubyUnits::Unit('1 y') * speed_of_light + ly.definition = RubyUnits::Unit.new('1 y') * speed_of_light ly.aliases = %w{ly light-year} end RubyUnits::Unit.define('parsec') do |parsec| - parsec.definition = RubyUnits::Unit('3.26163626 ly') + parsec.definition = RubyUnits::Unit.new('3.26163626 ly') parsec.aliases = %w{pc parsec parsecs} end # once was '149597900000 m' but there appears to be a more accurate estimate according to wikipedia # see http://en.wikipedia.org/wiki/Astronomical_unit RubyUnits::Unit.define('AU') do |au| - au.definition = RubyUnits::Unit('149597870700 m') + au.definition = RubyUnits::Unit.new('149597870700 m') au.aliases = %w{AU astronomical-unit} end RubyUnits::Unit.define('redshift') do |red| - red.definition = RubyUnits::Unit('1.302773e26 m') + red.definition = RubyUnits::Unit.new('1.302773e26 m') red.aliases = %w{z red-shift} end # mass RubyUnits::Unit.define('slug') do |slug| - slug.definition = RubyUnits::Unit('1 lbf*s^2/ft') + slug.definition = RubyUnits::Unit.new('1 lbf*s^2/ft') slug.aliases = %w{slug slugs} end # pressure RubyUnits::Unit.define('pascal') do |pascal| - pascal.definition = RubyUnits::Unit('1 kg/m*s^2') + pascal.definition = RubyUnits::Unit.new('1 kg/m*s^2') pascal.aliases = %w{Pa pascal pascals} end RubyUnits::Unit.define('bar') do |bar| - bar.definition = RubyUnits::Unit('100 kPa') + bar.definition = RubyUnits::Unit.new('100 kPa') bar.aliases = %w{bar bars} end RubyUnits::Unit.define('atm') do |atm| - atm.definition = RubyUnits::Unit('101325 Pa') + atm.definition = RubyUnits::Unit.new('101325 Pa') atm.aliases = %w{atm ATM atmosphere atmospheres} end RubyUnits::Unit.define('mmHg') do |mmhg| - density_of_mercury = RubyUnits::Unit('7653360911758079/562949953421312 g/cm^3') # 13.5951 g/cm^3 at 0 tempC - mmhg.definition = RubyUnits::Unit('1 mm') * RubyUnits::Unit('1 gee') * density_of_mercury + density_of_mercury = RubyUnits::Unit.new('7653360911758079/562949953421312 g/cm^3') # 13.5951 g/cm^3 at 0 tempC + mmhg.definition = RubyUnits::Unit.new('1 mm') * RubyUnits::Unit.new('1 gee') * density_of_mercury end RubyUnits::Unit.define('inHg') do |inhg| - density_of_mercury = RubyUnits::Unit('7653360911758079/562949953421312 g/cm^3') # 13.5951 g/cm^3 at 0 tempC - inhg.definition = RubyUnits::Unit('1 in') * RubyUnits::Unit('1 gee') * density_of_mercury + density_of_mercury = RubyUnits::Unit.new('7653360911758079/562949953421312 g/cm^3') # 13.5951 g/cm^3 at 0 tempC + inhg.definition = RubyUnits::Unit.new('1 in') * RubyUnits::Unit.new('1 gee') * density_of_mercury end RubyUnits::Unit.define('torr') do |torr| - torr.definition = RubyUnits::Unit('1/760 atm') + torr.definition = RubyUnits::Unit.new('1/760 atm') torr.aliases = %w{Torr torr} end RubyUnits::Unit.define('psi') do |psi| - psi.definition = RubyUnits::Unit('1 lbf/in^2') + psi.definition = RubyUnits::Unit.new('1 lbf/in^2') end RubyUnits::Unit.define('cmh2o') do |cmh2o| - density_of_water = RubyUnits::Unit('1 g/cm^3') # at 4 tempC - cmh2o.definition = RubyUnits::Unit('1 cm') * RubyUnits::Unit('1 gee') * density_of_water + density_of_water = RubyUnits::Unit.new('1 g/cm^3') # at 4 tempC + cmh2o.definition = RubyUnits::Unit.new('1 cm') * RubyUnits::Unit.new('1 gee') * density_of_water cmh2o.aliases = %w{cmH2O cmh2o cmAq} end RubyUnits::Unit.define('inh2o') do |inh2o| - density_of_water = RubyUnits::Unit('1 g/cm^3') # at 4 tempC - inh2o.definition = RubyUnits::Unit('1 in') * RubyUnits::Unit('1 gee') * density_of_water + density_of_water = RubyUnits::Unit.new('1 g/cm^3') # at 4 tempC + inh2o.definition = RubyUnits::Unit.new('1 in') * RubyUnits::Unit.new('1 gee') * density_of_water inh2o.aliases = %w{inH2O inh2o inAq} end #viscosity RubyUnits::Unit.define('poise') do |poise| - poise.definition = RubyUnits::Unit('dPa*s') + poise.definition = RubyUnits::Unit.new('dPa*s') poise.aliases = %w{P poise} end RubyUnits::Unit.define('stokes') do |stokes| - stokes.definition = RubyUnits::Unit('1 cm^2/s') + stokes.definition = RubyUnits::Unit.new('1 cm^2/s') stokes.aliases = %w{St stokes} end # #energy RubyUnits::Unit.define('joule') do |joule| - joule.definition = RubyUnits::Unit('1 N*m') + joule.definition = RubyUnits::Unit.new('1 N*m') joule.aliases = %w{J joule joules} end RubyUnits::Unit.define('erg') do |erg| - erg.definition = RubyUnits::Unit('1 g*cm^2/s^2') + erg.definition = RubyUnits::Unit.new('1 g*cm^2/s^2') erg.aliases = %w{erg ergs} end #power RubyUnits::Unit.define('watt') do |watt| - watt.definition = RubyUnits::Unit('1 N*m/s') + watt.definition = RubyUnits::Unit.new('1 N*m/s') watt.aliases = %w{W Watt watt watts} end RubyUnits::Unit.define('horsepower') do |hp| - hp.definition = RubyUnits::Unit('33000 ft*lbf/min') + hp.definition = RubyUnits::Unit.new('33000 ft*lbf/min') hp.aliases = %w{hp horsepower} end # energy RubyUnits::Unit.define('btu') do |btu| - btu.definition = RubyUnits::Unit('2320092679909671/2199023255552 J') # 1055.056 J --- ISO standard + btu.definition = RubyUnits::Unit.new('2320092679909671/2199023255552 J') # 1055.056 J --- ISO standard btu.aliases = %w{Btu btu Btus btus} end RubyUnits::Unit.define('therm') do |therm| - therm.definition = RubyUnits::Unit('100 kBtu') + therm.definition = RubyUnits::Unit.new('100 kBtu') therm.aliases = %w{thm therm therms Therm} end # "small" calorie RubyUnits::Unit.define('calorie') do |calorie| - calorie.definition = RubyUnits::Unit('4.184 J') + calorie.definition = RubyUnits::Unit.new('4.184 J') calorie.aliases = %w{cal calorie calories} end # "big" calorie RubyUnits::Unit.define('Calorie') do |calorie| - calorie.definition = RubyUnits::Unit('1 kcal') + calorie.definition = RubyUnits::Unit.new('1 kcal') calorie.aliases = %w{Cal Calorie Calories} end RubyUnits::Unit.define('molar') do |molar| - molar.definition = RubyUnits::Unit('1 mole/l') + molar.definition = RubyUnits::Unit.new('1 mole/l') molar.aliases = %w{M molar} end # potential RubyUnits::Unit.define('volt') do |volt| - volt.definition = RubyUnits::Unit('1 W/A') + volt.definition = RubyUnits::Unit.new('1 W/A') volt.aliases = %w{V volt volts} end # capacitance RubyUnits::Unit.define('farad') do |farad| - farad.definition = RubyUnits::Unit('1 A*s/V') + farad.definition = RubyUnits::Unit.new('1 A*s/V') farad.aliases = %w{F farad farads} end # charge RubyUnits::Unit.define('coulomb') do |coulomb| - coulomb.definition = RubyUnits::Unit('1 A*s') + coulomb.definition = RubyUnits::Unit.new('1 A*s') coulomb.aliases = %w{C coulomb coulombs} end # conductance RubyUnits::Unit.define('siemens') do |siemens| - siemens.definition = RubyUnits::Unit('1 A/V') + siemens.definition = RubyUnits::Unit.new('1 A/V') siemens.aliases = %w{S siemens} end # inductance RubyUnits::Unit.define('henry') do |henry| - henry.definition = RubyUnits::Unit('1 J/A^2') + henry.definition = RubyUnits::Unit.new('1 J/A^2') henry.aliases = %w{H henry henries} end # resistance RubyUnits::Unit.define('ohm') do |ohm| - ohm.definition = RubyUnits::Unit('1 V/A') + ohm.definition = RubyUnits::Unit.new('1 V/A') ohm.aliases = %w{Ohm ohm ohms} end # magnetism RubyUnits::Unit.define('weber') do |weber| - weber.definition = RubyUnits::Unit('1 V*s') + weber.definition = RubyUnits::Unit.new('1 V*s') weber.aliases = %w{Wb weber webers} end RubyUnits::Unit.define('tesla') do |tesla| - tesla.definition = RubyUnits::Unit('1 V*s/m^2') + tesla.definition = RubyUnits::Unit.new('1 V*s/m^2') tesla.aliases = %w{T tesla teslas} end RubyUnits::Unit.define('gauss') do |gauss| - gauss.definition = RubyUnits::Unit('100 microT') + gauss.definition = RubyUnits::Unit.new('100 microT') gauss.aliases = %w{G gauss} end RubyUnits::Unit.define('maxwell') do |maxwell| - maxwell.definition = RubyUnits::Unit('1 gauss*cm^2') + maxwell.definition = RubyUnits::Unit.new('1 gauss*cm^2') maxwell.aliases = %w{Mx maxwell maxwells} end RubyUnits::Unit.define('oersted') do |oersted| - oersted.definition = RubyUnits::Unit(250.0/Math::PI, 'A/m') + oersted.definition = RubyUnits::Unit.new(250.0/Math::PI, 'A/m') oersted.aliases = %w{Oe oersted oersteds} end #activity RubyUnits::Unit.define('katal') do |katal| - katal.definition = RubyUnits::Unit('1 mole/sec') + katal.definition = RubyUnits::Unit.new('1 mole/sec') katal.aliases = %w{kat katal} end RubyUnits::Unit.define('unit') do |unit| - unit.definition = RubyUnits::Unit('1/60 microkatal') + unit.definition = RubyUnits::Unit.new('1/60 microkatal') unit.aliases = %w{U enzRubyUnits::Unit} end #frequency RubyUnits::Unit.define('hertz') do |hz| - hz.definition = RubyUnits::Unit('1 1/s') + hz.definition = RubyUnits::Unit.new('1 1/s') hz.aliases = %w{Hz hertz} end #angle RubyUnits::Unit.define('degree') do |deg| - deg.definition = RubyUnits::Unit(Math::PI / 180.0, 'radian') + deg.definition = RubyUnits::Unit.new(Math::PI / 180.0, 'radian') deg.aliases = %w{deg degree degrees} end RubyUnits::Unit.define('grad') do |grad| - grad.definition = RubyUnits::Unit(Math::PI / 200.0, 'radian') + grad.definition = RubyUnits::Unit.new(Math::PI / 200.0, 'radian') grad.aliases = %w{grad gradian grads} end #rotation RubyUnits::Unit.define('rotation') do |rotation| - rotation.definition = RubyUnits::Unit(2.0*Math::PI, 'radian') + rotation.definition = RubyUnits::Unit.new(2.0*Math::PI, 'radian') end RubyUnits::Unit.define('rpm') do |rpm| - rpm.definition = RubyUnits::Unit('1 rotation/min') + rpm.definition = RubyUnits::Unit.new('1 rotation/min') end #memory RubyUnits::Unit.define('bit') do |bit| - bit.definition = RubyUnits::Unit('1/8 byte') + bit.definition = RubyUnits::Unit.new('1/8 byte') bit.aliases = %w{b bit} end #currency RubyUnits::Unit.define('cents') do |cents| - cents.definition = RubyUnits::Unit('1/100 dollar') + cents.definition = RubyUnits::Unit.new('1/100 dollar') end #luminosity RubyUnits::Unit.define('lumen') do |lumen| - lumen.definition = RubyUnits::Unit('1 cd*steradian') + lumen.definition = RubyUnits::Unit.new('1 cd*steradian') lumen.aliases = %w{lm lumen} end RubyUnits::Unit.define('lux') do |lux| - lux.definition = RubyUnits::Unit('1 lumen/m^2') + lux.definition = RubyUnits::Unit.new('1 lumen/m^2') end #radiation RubyUnits::Unit.define('gray') do |gray| - gray.definition = RubyUnits::Unit('1 J/kg') + gray.definition = RubyUnits::Unit.new('1 J/kg') gray.aliases = %w{Gy gray grays} end RubyUnits::Unit.define('roentgen') do |roentgen| - roentgen.definition = RubyUnits::Unit('2.58e-4 C/kg') + roentgen.definition = RubyUnits::Unit.new('2.58e-4 C/kg') roentgen.aliases = %w{R roentgen} end RubyUnits::Unit.define('sievert') do |sievert| - sievert.definition = RubyUnits::Unit('1 J/kg') + sievert.definition = RubyUnits::Unit.new('1 J/kg') sievert.aliases = %w{Sv sievert sieverts} end RubyUnits::Unit.define('becquerel') do |becquerel| - becquerel.definition = RubyUnits::Unit('1 1/s') + becquerel.definition = RubyUnits::Unit.new('1 1/s') becquerel.aliases = %w{Bq becquerel becquerels} end RubyUnits::Unit.define('curie') do |curie| - curie.definition = RubyUnits::Unit('37 GBq') + curie.definition = RubyUnits::Unit.new('37 GBq') curie.aliases = %w{Ci curie curies} end RubyUnits::Unit.define('count') do |count| - count.definition = RubyUnits::Unit('1 each') + count.definition = RubyUnits::Unit.new('1 each') count.kind = :counting end # rate RubyUnits::Unit.define('cpm') do |cpm| - cpm.definition = RubyUnits::Unit('1 count/min') + cpm.definition = RubyUnits::Unit.new('1 count/min') end RubyUnits::Unit.define('dpm') do |dpm| - dpm.definition = RubyUnits::Unit('1 count/min') + dpm.definition = RubyUnits::Unit.new('1 count/min') end RubyUnits::Unit.define('bpm') do |bpm| - bpm.definition = RubyUnits::Unit('1 count/min') + bpm.definition = RubyUnits::Unit.new('1 count/min') end # misc RubyUnits::Unit.define('dozen') do |dozen| - dozen.definition = RubyUnits::Unit('12 each') + dozen.definition = RubyUnits::Unit.new('12 each') dozen.aliases = %w{doz dz dozen} dozen.kind = :counting end RubyUnits::Unit.define('gross') do |gross| - gross.definition = RubyUnits::Unit('12 dozen') + gross.definition = RubyUnits::Unit.new('12 dozen') gross.aliases = %w{gr gross} gross.kind = :counting end RubyUnits::Unit.define('cell') do |cell| - cell.definition = RubyUnits::Unit('1 each') + cell.definition = RubyUnits::Unit.new('1 each') cell.aliases = %w{cells cell} cell.kind = :counting end RubyUnits::Unit.define('base-pair') do |bp| - bp.definition = RubyUnits::Unit('1 each') + bp.definition = RubyUnits::Unit.new('1 each') bp.aliases = %w{bp base-pair} bp.kind = :counting end RubyUnits::Unit.define('nucleotide') do |nt| - nt.definition = RubyUnits::Unit('1 each') + nt.definition = RubyUnits::Unit.new('1 each') nt.aliases = %w{nt} nt.kind = :counting end RubyUnits::Unit.define('molecule') do |molecule| - molecule.definition = RubyUnits::Unit('1 each') + molecule.definition = RubyUnits::Unit.new('1 each') molecule.aliases = %w{molecule molecules} molecule.kind = :counting end RubyUnits::Unit.define('percent') do |percent| - percent.definition = RubyUnits::Unit('1/100') + percent.definition = RubyUnits::Unit.new('1/100') percent.aliases = %w{% percent} end RubyUnits::Unit.define('ppm') do |ppm| - ppm.definition = RubyUnits::Unit(1) / 1_000_000 + ppm.definition = RubyUnits::Unit.new(1) / 1_000_000 end RubyUnits::Unit.define('ppb') do |ppb| - ppb.definition = RubyUnits::Unit(1) / 1_000_000_000 + ppb.definition = RubyUnits::Unit.new(1) / 1_000_000_000 end From f89f5b4aeadace6b4320621f81a84b9ee286eb5c Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 6 Jul 2013 12:10:22 -0400 Subject: [PATCH 3/5] Version bump to 1.4.4 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 3c80e4f0..e1df5de7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.3 \ No newline at end of file +1.4.4 \ No newline at end of file From 031eb8e1701ba994432e970fbf5724fc52ced389 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 6 Jul 2013 12:15:31 -0400 Subject: [PATCH 4/5] update readme with information about namespaced classes and how to use them. See #60 --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 45e2d86a..51405b8a 100644 --- a/README.md +++ b/README.md @@ -168,4 +168,17 @@ This is useful for changing display names, adding aliases, etc. Unit.redefine!("cup") do |cup| cup.display_name = "cup" end - + + +### Namespaced Class + +Sometimes the default class 'Unit' may conflict with other gems or applications. Internally ruby-units defines itself using the RubyUnits namespace. +The actual class of a unit is the RubyUnits::Unit. For simplicity and backwards compatiblity, the '::Unit' class is defined as an alias to '::RubyUnits::Unit'. + +To load ruby-units without this alias... + + require 'ruby-units/namespaced' + +When using bundler... + + gem 'ruby-units', require: 'namespaced' From 26eb120b47ecb5b69b184866a7b0a146de97c8e3 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 6 Jul 2013 12:17:14 -0400 Subject: [PATCH 5/5] add another caveat about the Unit helper --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 51405b8a..198438f9 100644 --- a/README.md +++ b/README.md @@ -182,3 +182,5 @@ To load ruby-units without this alias... When using bundler... gem 'ruby-units', require: 'namespaced' + +Note: when using the namespaced version, the Unit('unit string') helper will not be defined.