class Unit

Constants

VERSION

Attributes

default_system[RW]
normalized[R]
system[R]
unit[R]
value[R]

Public Class Methods

method_name_to_unit(name) click to toggle source
# File lib/unit/dsl.rb, line 14
def self.method_name_to_unit(name)
  name.to_s.sub(/^per_/, '1/').gsub('_per_', '/').gsub('_', ' ')
end
new(value, unit, system) click to toggle source
# File lib/unit/class.rb, line 6
def initialize(value, unit, system)
  @system = system
  @value = value
  @unit = unit.dup
  @normalized = nil
  reduce!
end

Private Class Methods

numeric_to_unit(object, system = nil) click to toggle source
# File lib/unit/class.rb, line 305
def numeric_to_unit(object, system = nil)
  system ||= Unit.default_system
  case object
  when Unit
    raise IncompatibleUnitError, "Unit system of #{object.inspect} is incompatible with #{system.name}" if object.system != system
    object
  when Numeric
    Unit.new(object, [], system)
  else
    raise TypeError, "#{object.class} can't be coerced into Unit"
  end
end
power_unit(unit, pow) click to toggle source
# File lib/unit/class.rb, line 301
def power_unit(unit, pow)
  unit.map {|factor, name, exp| [factor, name, exp * pow] }
end
to_unit(object, system = nil) click to toggle source
# File lib/unit/class.rb, line 318
def to_unit(object, system = nil)
  system ||= Unit.default_system
  case object
  when String, Symbol
    unit = system.parse_unit(object.to_s)
    system.validate_unit(unit)
    Unit.new(1, unit, system)
  when Array
    system.validate_unit(object)
    Unit.new(1, object, system)
  else
    numeric_to_unit(object, system)
  end
end

Public Instance Methods

*(other) click to toggle source
# File lib/unit/class.rb, line 47
def *(other)
  if Numeric === other
    other = coerce_numeric(other)
    Unit.new(other.value * self.value, other.unit + self.unit, system)
  else
    apply_through_coercion(other, __method__)
  end
end
**(exp) click to toggle source
# File lib/unit/class.rb, line 80
def **(exp)
  raise TypeError if Unit === exp
  Unit.new(value ** exp, Unit.power_unit(unit, exp), system)
end
+(other) click to toggle source
# File lib/unit/class.rb, line 70
def +(other)
  if Numeric === other
    other = coerce_numeric_compatible(other)
    a, b = self.normalize, other.normalize
    Unit.new(a.value + b.value, b.unit, system).in(self)
  else
    apply_through_coercion(other, __method__)
  end
end
-(other) click to toggle source
# File lib/unit/class.rb, line 85
def -(other)
  if Numeric === other
    other = coerce_numeric_compatible(other)
    a, b = self.normalize, other.normalize
    Unit.new(a.value - b.value, b.unit, system).in(self)
  else
    apply_through_coercion(other, __method__)
  end
end
-@() click to toggle source
# File lib/unit/class.rb, line 95
def -@
  Unit.new(-value, unit, system)
end
/(other) click to toggle source
# File lib/unit/class.rb, line 56
def /(other)
  if Numeric === other
    other = coerce_numeric(other)
    result = if Integer === value && Integer === other.value
               other.value == 1 ? value : Rational(value, other.value)
             else
               value / other.value
             end
    Unit.new(result, unit + Unit.power_unit(other.unit, -1), system)
  else
    apply_through_coercion(other, __method__)
  end
end
<=>(other) click to toggle source
# File lib/unit/class.rb, line 121
def <=>(other)
  if Numeric === other
    other = coerce_numeric_compatible(other)
    a, b = self.normalize, other.normalize
    a.value <=> b.value
  else
    apply_through_coercion(other, __method__)
  end
end
==(other) click to toggle source
# File lib/unit/class.rb, line 107
def ==(other)
  if Numeric === other
    other = coerce_numeric(other)
    a, b = self.normalize, other.normalize
    a.value == b.value && a.unit == b.unit
  else
    apply_through_coercion(other, __method__)
  end
end
abs() click to toggle source
# File lib/unit/class.rb, line 99
def abs
  Unit.new(value.abs, unit, system)
end
approx() click to toggle source
# File lib/unit/class.rb, line 180
def approx
  Unit.new(self.to_f, unit, system)
end
coerce(other) click to toggle source
# File lib/unit/class.rb, line 188
def coerce(other)
  [coerce_numeric(other), self]
end
compatible?(other) click to toggle source

Compatible units can be added

# File lib/unit/class.rb, line 139
def compatible?(other)
  self.normalize.unit == Unit.to_unit(other, system).normalize.unit
end
Also aliased as: compatible_with?
compatible_with?(other)
Alias for: compatible?
dimensionless?() click to toggle source

Number without dimension

# File lib/unit/class.rb, line 132
def dimensionless?
  normalize.unit.empty?
end
Also aliased as: unitless?
eql?(other) click to toggle source
# File lib/unit/class.rb, line 117
def eql?(other)
  Unit === other && value.eql?(other.value) && unit == other.unit
end
in(unit) click to toggle source

Convert to other unit

# File lib/unit/class.rb, line 146
def in(unit)
  conversion = Unit.new(1, Unit.to_unit(unit, system).unit, system)
  (self / conversion).normalize * conversion
end
in!(unit) click to toggle source
# File lib/unit/class.rb, line 151
def in!(unit)
  unit = coerce_object(unit)
  result = self.in(unit)
  unless result.unit == unit.unit
    raise TypeError, "Unexpected #{result.inspect}, expected to be in #{unit.unit_string}"
  end
  result
end
initialize_copy(other) click to toggle source
# File lib/unit/class.rb, line 14
def initialize_copy(other)
  @system = other.system
  @value = other.value
  @unit = other.unit.dup
  @normalized = other.normalized
end
inspect() click to toggle source
# File lib/unit/class.rb, line 160
def inspect
  unit.empty? ? %{Unit("#{value}")} : %{Unit("#{value_string} #{unit_string('.')}")}
end
method_missing(name, system = nil) click to toggle source
Calls superclass method Numeric#method_missing
# File lib/unit/dsl.rb, line 18
def method_missing(name, system = nil)
  if name.to_s =~ /^in_(.*?)(!?)$/
    unit = Unit.method_name_to_unit($1)
    $2.empty? ? self.in(unit) : self.in!(unit)
  else
    super(name, system || @system)
  end
end
normalize() click to toggle source

Converts to base units

# File lib/unit/class.rb, line 22
def normalize
  @normalized ||= dup.normalize!
end
normalize!() click to toggle source

Converts to base units

# File lib/unit/class.rb, line 27
def normalize!
  if @normalized != self
    begin
      last_unit = @unit
      @unit = []
      last_unit.each do |factor, unit, exp|
        @value *= @system.factor[factor][:value] ** exp if factor != :one
        if Numeric === unit
          @unit << [:one, unit, exp]
        else
          @unit += Unit.power_unit(@system.unit[unit][:def], exp)
        end
      end
    end while last_unit != @unit
    reduce!
    @normalized = self
  end
  self
end
round(precision = 0) click to toggle source
# File lib/unit/class.rb, line 184
def round(precision = 0)
  Unit.new(value.round(precision), unit, system)
end
to_f() click to toggle source
# File lib/unit/class.rb, line 176
def to_f
  @value.to_f
end
to_i() click to toggle source
# File lib/unit/class.rb, line 172
def to_i
  @value.to_i
end
to_s() click to toggle source
# File lib/unit/class.rb, line 164
def to_s
  unit.empty? ? value.to_s : "#{value_string} #{unit_string}"
end
to_tex() click to toggle source
# File lib/unit/class.rb, line 168
def to_tex
  unit.empty? ? value.to_s : "\SI{#{value}}{#{unit_string('.')}}"
end
unit_string(sep = '·') click to toggle source
# File lib/unit/class.rb, line 204
def unit_string(sep = '·')
  (unit_list(@unit.select {|factor, name, exp| exp >= 0 }) +
   unit_list(@unit.select {|factor, name, exp| exp < 0 })).join(sep)
end
unitless?()
Alias for: dimensionless?
value_string() click to toggle source
# File lib/unit/class.rb, line 192
def value_string
  if Rational === value
    if value.denominator == 1
      value.numerator.to_s
    else
      value.inspect
    end
  else
    value.to_s
  end
end
zero?() click to toggle source
# File lib/unit/class.rb, line 103
def zero?
  value.zero?
end

Private Instance Methods

apply_through_coercion(obj, oper) click to toggle source

Given another object and an operator, use the other object's coerce method to perform the operation.

Based on Matrix#apply_through_coercion

# File lib/unit/class.rb, line 275
def apply_through_coercion(obj, oper)
  coercion = obj.coerce(self)
  raise TypeError unless coercion.is_a?(Array) && coercion.length == 2
  first, last = coercion
  first.send(oper, last)
rescue
  raise TypeError, "#{obj.class} can't be coerced into #{self.class}"
end
coerce_numeric(object) click to toggle source
# File lib/unit/class.rb, line 290
def coerce_numeric(object)
  Unit.numeric_to_unit(object, system)
end
coerce_numeric_compatible(object) click to toggle source
# File lib/unit/class.rb, line 284
def coerce_numeric_compatible(object)
  object = coerce_numeric(object)
  raise IncompatibleUnitError, "#{inspect} and #{object.inspect} are incompatible" if !compatible?(object)
  object
end
coerce_object(object) click to toggle source
# File lib/unit/class.rb, line 294
def coerce_object(object)
  Unit.to_unit(object, system)
end
reduce!() click to toggle source

Reduce units and factors

# File lib/unit/class.rb, line 224
def reduce!
  # Remove numbers from units
  numbers = @unit.select {|factor, unit, exp| Numeric === unit }
  @unit -= numbers
  numbers.each do |factor, number, exp|
    raise RuntimeError, 'Numeric unit with factor' if factor != :one
    @value *= number ** exp
  end

  # Reduce units
  @unit.sort!
  i, current = 1, 0
  while i < @unit.size do
    while i < @unit.size && @unit[current][0] == @unit[i][0] && @unit[current][1] == @unit[i][1]
      @unit[current] = @unit[current].dup
      @unit[current][2] += @unit[i][2]
      i += 1
    end
    if @unit[current][2] == 0
      @unit.slice!(current, i - current)
    else
      @unit.slice!(current + 1, i - current - 1)
      current += 1
    end
    i = current + 1
  end

  # Reduce factors
  @unit.each_with_index do |(factor1, _, exp1), k|
    if exp1 > 0
      @unit.each_with_index do |(factor2, _, exp2), j|
        if exp2 == -exp1
          q, r = @system.factor[factor1][:value].divmod @system.factor[factor2][:value]
          if r == 0 && new_factor = @system.factor_value[q]
            @unit[k] = @unit[k].dup
            @unit[j] = @unit[j].dup
            @unit[k][0] = new_factor
            @unit[j][0] = :one
          end
        end
      end
    end
  end

  self
end
unit_list(list) click to toggle source
# File lib/unit/class.rb, line 211
def unit_list(list)
  units = []
  list.each do |factor, name, exp|
    unit = ''
    unit << @system.factor[factor][:symbol] if factor != :one
    unit << @system.unit[name][:symbol]
    unit << '^' << exp.to_s if exp != 1
    units << unit
  end
  units.sort
end