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