This class represents a Unit. A Unit uses a given Converter with a number of registered Units in which it can be expressed. A Unit is the product of the powers of other Units. In principle, these need not be integer powers, but this may cause problems with rounding. The following code for example returns false:
Unit.new(:m => 0.1) * Unit.new(:m => 0.2) == Unit.new(:m => 0.3)
Units can be multiplied and divided, or raised to a given power. This can only be done when both units use the same Converter. As an extra, 1 can be divided by a Unit.
Examples:
Unit.new(:mi => 1, :s => -1) ** 2 # => mi**2/s**2 Unit.new(:mi => 1, :s => -1) * Unit.new(:s => 1, :usd => -1) # => mi/usd Unit.new(:mi => 1, :s => -1, Converter.converter(:uk)) * Unit.new(:s => 1, :usd => -1, Converter.converter(:us)) # => TypeError 1 / Unit.new(:mi => 1, :s => -1) # => s/mi
[R] | converter | |
[R] | units |
Creates a new (composite) Unit. It is passed a hash of the form {:unit => exponent}, and the Converter to use.
Examples:
Unit.new(:m => 1, :s => -1, Converter.converter(:uk)) # => m/s Unit.new(:mi => 1, :s => -2) # => mi/s**2
See also Converter, Converter.converter
[ show source ]
# File lib/facets/more/units.rb, line 121 def initialize(units = {}, converter = Units::Converter.current) @units, @converter = {}, converter units.each_pair { |k, v| @units[k.to_sym] = v } check_units end
Multiplies with the given Unit.
[ show source ]
# File lib/facets/more/units.rb, line 137 def *(other) do_op(:*, :+, other) end
Raises to the given power.
[ show source ]
# File lib/facets/more/units.rb, line 128 def **(p) result = {} @units.each_pair do |u, e| result[u] = e * p end Units::Unit.new(result, @converter) end
Divides by the given Unit.
[ show source ]
# File lib/facets/more/units.rb, line 142 def /(other) do_op(:/, :-, other) end
Returns true iff the two Units are equals, i.e., iff they have the same exponent for all units, and they both use the same Converter.
[ show source ]
# File lib/facets/more/units.rb, line 159 def ==(other) other.is_a?(Units::Unit) && other.units == units && other.converter == converter end
Returns true iff this Unit is compatible with the given Unit. This is less strict than equality because for example hours are compatible with seconds ("we can add them"), but hours are not seconds.
[ show source ]
# File lib/facets/more/units.rb, line 166 def compatible_with?(other) return false if converter != other.converter conv1, conv2 = converter.coerce_units(self, other) conv1.units == conv2.units end
Alias for to_s
[ show source ]
# File lib/facets/more/units.rb, line 184 def method_missing(m, *args, &blk) if converter.registered?(m) raise ArgumentError, "Wrong number of arguments" if args.length != 0 return Units::Unit.new({m => 1}, converter) * self end super end
Returns a human readable string representation.
[ show source ]
# File lib/facets/more/units.rb, line 173 def to_s numerator = "" denominator = "" @units.each_pair do |u, e| (e > 0 ? numerator : denominator) << " #{u.to_s}#{"**#{e.abs}" if e.abs != 1}" end "#{numerator.lstrip}#{"/" + denominator.lstrip if not denominator.empty?}" end
Returns true iff this Unit has all exponents equal to 0.
[ show source ]
# File lib/facets/more/units.rb, line 147 def unitless? @units.empty? end
[ show source ]
# File lib/facets/more/units.rb, line 194 def check_units @units.keys.each do |unit| raise ArgumentError, "unit #{unit.to_s.dump} not registered" if not @converter.registered? unit @units.delete(unit) if @units[unit] == 0 end end
[ show source ]
# File lib/facets/more/units.rb, line 201 def do_op(op, dual_op, other) raise TypeError, "incompatible converters for #{op}" if converter != other.converter result = @units.dup other.units.each_pair do |u, e| result[u] = 0 if not result[u] result[u] = result[u].send(dual_op, e) end Units::Unit.new(result, @converter) end