Class: RubyUnits::Unit

Inherits:
Numeric show all
Includes:
Comparable
Defined in:
lib/ruby_units/unit.rb,
lib/ruby_units/cache.rb,
lib/ruby_units/version.rb,
lib/ruby_units/definition.rb

Defined Under Namespace

Modules: Version Classes: Cache, Definition

Constant Summary collapse

VERSION =
Unit::Version::STRING
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+)\/(\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 =
['<kelvin>']
FAHRENHEIT =
['<fahrenheit>']
RANKINE =
['<rankine>']
CELSIUS =
['<celsius>']
SIGNATURE_VECTOR =
[
    :length,
    :time,
    :temperature,
    :mass,
    :current,
    :substance,
    :luminosity,
    :currency,
    :information,
    :angle
]
@@definitions =
{}
@@PREFIX_VALUES =
{}
@@PREFIX_MAP =
{}
@@UNIT_MAP =
{}
@@UNIT_VALUES =
{}
@@UNIT_REGEX =
nil
@@UNIT_MATCH_REGEX =
nil
@@TEMP_REGEX =
nil
@@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       => :conductance,
    312078       => :capacitance,
    3199980      => :activity,
    3199997      => :molar_concentration,
    3200000      => :substance,
    63999998     => :illuminance,
    64000000     => :luminous_power,
    1280000000   => :currency,
    25600000000  => :information,
    511999999980 => :angular_velocity,
    512000000000 => :angle
}
@@cached_units =
{}
@@base_unit_cache =
{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*options) ⇒ Unit

Create a new Unit object. Can be initialized using a String, a Hash, an Array, Time, DateTime

Examples:

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'}

Parameters:

Raises:

  • (ArgumentError)

    if absolute value of a temperature is less than absolute zero

  • (ArgumentError)

    if no unit is specified

  • (ArgumentError)

    if an invalid unit is specified



312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
# File 'lib/ruby_units/unit.rb', line 312

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

  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   = ['<second>']
      @denominator = UNITY_ARRAY
    when DateTime, Date
      @scalar      = options[0].ajd
      @numerator   = ['<day>']
      @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?(.+)?|&plusmn;|\+\/-/)
      @@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

Instance Attribute Details

#base_denominatorArray

Returns:



238
239
240
# File 'lib/ruby_units/unit.rb', line 238

def base_denominator
  @base_denominator
end

#base_numeratorArray

Returns:



235
236
237
# File 'lib/ruby_units/unit.rb', line 235

def base_numerator
  @base_numerator
end

#base_scalarNumeric

Returns:



232
233
234
# File 'lib/ruby_units/unit.rb', line 232

def base_scalar
  @base_scalar
end

#denominatorArray

Returns:



226
227
228
# File 'lib/ruby_units/unit.rb', line 226

def denominator
  @denominator
end

#numeratorArray

Returns:



223
224
225
# File 'lib/ruby_units/unit.rb', line 223

def numerator
  @numerator
end

#outputString

Returns:



241
242
243
# File 'lib/ruby_units/unit.rb', line 241

def output
  @output
end

#scalarNumeric

Returns:



220
221
222
# File 'lib/ruby_units/unit.rb', line 220

def scalar
  @scalar
end

#signatureInteger

Returns:

  • (Integer)


229
230
231
# File 'lib/ruby_units/unit.rb', line 229

def signature
  @signature
end

#unit_nameString

Returns:



244
245
246
# File 'lib/ruby_units/unit.rb', line 244

def unit_name
  @unit_name
end

Class Method Details

.base_unit_cacheHash

Returns:

  • (Hash)


412
413
414
# File 'lib/ruby_units/unit.rb', line 412

def self.base_unit_cache
  return @@base_unit_cache
end

.cachedHash

Returns:

  • (Hash)


397
398
399
# File 'lib/ruby_units/unit.rb', line 397

def self.cached
  return @@cached_units
end

.clear_cachetrue

Returns:

  • (true)


403
404
405
406
407
408
# File 'lib/ruby_units/unit.rb', line 403

def self.clear_cache
  @@cached_units    = {}
  @@base_unit_cache = {}
  RubyUnits::Unit.new(1)
  return true
end

.define(unit_definition, &block) ⇒ RubyUnits::Unit::Definition

Unpack a unit definition and add it to the array of defined units

Examples:

Block form

RubyUnits::Unit.define('foobar') do |foobar|
  foobar.definition = RubyUnits::Unit.new("1 baz")
end

RubyUnits::Unit::Definition form

unit_definition = RubyUnits::Unit::Definition.new("foobar") {|foobar| foobar.definition = RubyUnits::Unit.new("1 baz")}
RubyUnits::Unit.define(unit_definition)

Parameters:

Returns:

Raises:

  • (ArgumentError)

    when passed a non-string if using the block form



186
187
188
189
190
191
192
193
194
# File 'lib/ruby_units/unit.rb', line 186

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

.defined?(unit) ⇒ Boolean

determine if a unit is already defined

Parameters:

Returns:

  • (Boolean)


154
155
156
# File 'lib/ruby_units/unit.rb', line 154

def self.defined?(unit)
  self.definitions.values.any? { |d| d.aliases.include?(unit) }
end

.definition(_unit) ⇒ RubyUnits::Unit::Definition?

return the unit definition for a unit

Parameters:

Returns:



161
162
163
164
# File 'lib/ruby_units/unit.rb', line 161

def self.definition(_unit)
  unit = (_unit =~ /^<.+>$/) ? _unit : "<#{_unit}>"
  return @@definitions[unit]
end

.definitionsArray

return a list of all defined units

Returns:



168
169
170
# File 'lib/ruby_units/unit.rb', line 168

def self.definitions
  return @@definitions
end

.parse(input) ⇒ Unit

Examples:

parse strings

"1 minute in seconds"

Parameters:

Returns:



420
421
422
423
# File 'lib/ruby_units/unit.rb', line 420

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

.redefine!(name, &block) {|RubyUnits::Unit::Definition| ... } ⇒ RubyUnits::Unit::Definition

Get the definition for a unit and allow it to be redefined

Parameters:

  • name (String)

    Name of unit to redefine

  • block (Block)

Yields:

Returns:

Raises:

  • (ArgumentError)

    if a block is not given



202
203
204
205
206
207
# File 'lib/ruby_units/unit.rb', line 202

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

.setuptrue

setup internal arrays and hashes

Returns:

  • (true)


132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/ruby_units/unit.rb', line 132

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

  RubyUnits::Unit.new(1)
  return true
end

.undefine!(unit) ⇒ true

Undefine a unit. Will not raise an exception for unknown units.

Parameters:

  • name (String)

    of unit to undefine

Returns:

  • (true)


212
213
214
215
# File 'lib/ruby_units/unit.rb', line 212

def self.undefine!(unit)
  @@definitions.delete("<#{unit}>")
  RubyUnits::Unit.setup
end

Instance Method Details

#%(other) ⇒ Integer

perform a modulo on a unit, will raise an exception if the units are not compatible

Parameters:

Returns:

  • (Integer)


833
834
835
# File 'lib/ruby_units/unit.rb', line 833

def %(other)
  return self.divmod(other).last
end

#*(other) ⇒ Unit

Multiply two units.

Parameters:

Returns:

Raises:

  • (ArgumentError)

    when attempting to multiply two temperatures



778
779
780
781
782
783
784
785
786
787
788
789
790
791
# File 'lib/ruby_units/unit.rb', line 778

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

#**(other) ⇒ Unit

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

Parameters:

Returns:

Raises:

  • (ArgumentError)

    when raising a temperature to a power

  • (ArgumentError)

    when n not in the set integers from (1..9)

  • (ArgumentError)

    when attempting to raise to a complex number

  • (ArgumentError)

    when an invalid exponent is passed



851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
# File 'lib/ruby_units/unit.rb', line 851

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

#+(other) ⇒ Unit

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

Parameters:

Returns:

Raises:

  • (ArgumentError)

    when two temperatures are added

  • (ArgumentError)

    when units are not compatible

  • (ArgumentError)

    when adding a fixed time or date to a time span



706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
# File 'lib/ruby_units/unit.rb', line 706

def +(other)
  case other
    when Unit
      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?
              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
          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
      x, y = coerce(other)
      y + x
  end
end

#-(other) ⇒ Unit

Subtract two units. Result is same units as receiver and scalar and base_scalar are updated appropriately

Parameters:

Returns:

Raises:

  • (ArgumentError)

    when subtracting a temperature from a degree

  • (ArgumentError)

    when units are not compatible

  • (ArgumentError)

    when subtracting a fixed time from a time span



741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
# File 'lib/ruby_units/unit.rb', line 741

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 => ['<tempK>'], :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

#-@Numeric, Unit

negates the scalar of the Unit

Returns:



1098
1099
1100
1101
# File 'lib/ruby_units/unit.rb', line 1098

def -@
  return -@scalar if self.unitless?
  return (self.dup * -1)
end

#/(other) ⇒ Unit

Divide two units. Throws an exception if divisor is 0

Parameters:

Returns:

Raises:

  • (ZeroDivisionError)

    if divisor is zero

  • (ArgumentError)

    if attempting to divide a temperature by another temperature



799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
# File 'lib/ruby_units/unit.rb', line 799

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

#<=>(other) ⇒ -1|0|1|nil

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.

Parameters:

Returns:

  • (-1|0|1|nil)

Raises:

  • (NoMethodError)

    when other does not define <=>

  • (ArgumentError)

    when units are not compatible



607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
# File 'lib/ruby_units/unit.rb', line 607

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.respond_to?(:zero?) && other.zero?
      return self.base_scalar <=> 0
    when other.instance_of?(Unit)
      raise ArgumentError, "Incompatible Units ('#{self.units}' not compatible with '#{other.units}')" unless self =~ other
      return self.base_scalar <=> other.base_scalar
    else
      x, y = coerce(other)
      return y <=> x
  end
end

#==(other) ⇒ Boolean

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.

Parameters:

Returns:

  • (Boolean)


632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
# File 'lib/ruby_units/unit.rb', line 632

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

#===(other) ⇒ Boolean Also known as: same?, same_as?

Compare two units. Returns true if quantities and units match

Examples:

RubyUnits::Unit.new("100 cm") === RubyUnits::Unit.new("100 cm")   # => true
RubyUnits::Unit.new("100 cm") === RubyUnits::Unit.new("1 m")      # => false

Parameters:

Returns:

  • (Boolean)


681
682
683
684
685
686
687
688
689
690
691
692
693
# File 'lib/ruby_units/unit.rb', line 681

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

#=~(other) ⇒ Boolean Also known as: compatible?, compatible_with?

Note:

if you want to do a regexp comparison of the unit string do this … unit.units =~ /regexp/

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

Examples:

this permits a syntax like:

unit =~ "mm"

Parameters:

Returns:

  • (Boolean)


658
659
660
661
662
663
664
665
666
667
668
669
670
# File 'lib/ruby_units/unit.rb', line 658

def =~(other)
  case other
    when Unit
      self.signature == other.signature
    else
      begin
        x, y = coerce(other)
        return x =~ y
      rescue ArgumentError
        return false
      end
  end
end

#absNumeric, Unit

absolute value of a unit

Returns:



1105
1106
1107
1108
# File 'lib/ruby_units/unit.rb', line 1105

def abs
  return @scalar.abs if self.unitless?
  return RubyUnits::Unit.new(@scalar.abs, @numerator, @denominator)
end

#agoUnit

Examples:

‘5 min’.unit.ago

Returns:



1191
1192
1193
# File 'lib/ruby_units/unit.rb', line 1191

def ago
  return self.before
end

#as_json(*args) ⇒ String

Returns string formatted for json

Returns:



1045
1046
1047
# File 'lib/ruby_units/unit.rb', line 1045

def as_json(*args)
  to_s
end

#before(time_point = ::Time.now) ⇒ Unit Also known as: before_now

Examples:

‘5 min’.before(time)

Returns:



1197
1198
1199
1200
1201
1202
1203
1204
# File 'lib/ruby_units/unit.rb', line 1197

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

#best_prefixObject

returns a new unit that has been scaled to be more in line with typical usage.



1270
1271
1272
1273
1274
1275
1276
1277
1278
# File 'lib/ruby_units/unit.rb', line 1270

def best_prefix
  return self.to_base if self.scalar == 0
  _best_prefix =  if (self.kind == :information)
    @@PREFIX_VALUES.key(2**((Math.log(self.base_scalar,2) / 10.0).floor * 10))
  else
    @@PREFIX_VALUES.key(10**((Math.log10(self.base_scalar) / 3.0).floor * 3))
  end
  self.to(RubyUnits::Unit.new(@@PREFIX_MAP.key(_best_prefix)+self.units(false)))
end

#ceilNumeric, Unit

ceil of a unit

Returns:



1112
1113
1114
1115
# File 'lib/ruby_units/unit.rb', line 1112

def ceil
  return @scalar.ceil if self.unitless?
  return RubyUnits::Unit.new(@scalar.ceil, @numerator, @denominator)
end

#coerce(other) ⇒ Array

automatically coerce objects to units when possible if an object defines a ‘to_unit’ method, it will be coerced using that method

Parameters:

Returns:



1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
# File 'lib/ruby_units/unit.rb', line 1257

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

#convert_to(other) ⇒ Unit Also known as: >>, to

Note:

If temperature is part of a compound unit, the temperature will be treated as a differential and the units will be scaled appropriately.

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.

Parameters:

Returns:

Raises:

  • (ArgumentError)

    when attempting to convert a degree to a temperature

  • (ArgumentError)

    when target unit is unknown

  • (ArgumentError)

    when target unit is incompatible



953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
# File 'lib/ruby_units/unit.rb', line 953

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 '<tempC>'
                         @scalar + 273.15
                       when '<tempK>'
                         @scalar
                       when '<tempF>'
                         (@scalar+459.67)*Rational(5, 9)
                       when '<tempR>'
                         @scalar*Rational(5, 9)
                     end
    end
    q= case @@UNIT_MAP[target_unit]
         when '<tempC>'
           @base_scalar - 273.15
         when '<tempK>'
           @base_scalar
         when '<tempF>'
           @base_scalar * Rational(9, 5) - 459.67
         when '<tempR>'
           @base_scalar * Rational(9, 5)
       end
    return RubyUnits::Unit.new("#{q} #{target_unit}")
  else
    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 ('#{self}' not compatible with '#{other}')" 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
end

#copy(from) ⇒ Unit

Used to copy one unit to another

Parameters:

  • from (Unit)

    Unit to copy definition from

Returns:



256
257
258
259
260
261
262
263
264
265
# File 'lib/ruby_units/unit.rb', line 256

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

#divmod(other) ⇒ Array

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

Parameters:

Returns:

Raises:

  • (ArgumentError)


821
822
823
824
825
826
827
828
# File 'lib/ruby_units/unit.rb', line 821

def divmod(other)
  raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')" 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

#floorNumeric, Unit

Returns:



1118
1119
1120
1121
# File 'lib/ruby_units/unit.rb', line 1118

def floor
  return @scalar.floor if self.unitless?
  return RubyUnits::Unit.new(@scalar.floor, @numerator, @denominator)
end

#from(time_point) ⇒ Time, ... Also known as: after, from_now

Examples:

‘5 min’.from(time)

Parameters:

Returns:

Raises:

  • (ArgumentError)

    when passed argument is not a Time, Date, or DateTime



1241
1242
1243
1244
1245
1246
1247
1248
# File 'lib/ruby_units/unit.rb', line 1241

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

#inspect(option = nil) ⇒ String

Deprecated.

Normally pretty prints the unit, but if you really want to see the guts of it, pass ‘:dump’

Returns:



564
565
566
567
# File 'lib/ruby_units/unit.rb', line 564

def inspect(option=nil)
  return super() if option == :dump
  return self.to_s
end

#inverseUnit

returns inverse of Unit (1/unit)

Returns:



930
931
932
# File 'lib/ruby_units/unit.rb', line 930

def inverse
  return RubyUnits::Unit.new("1") / self
end

#is_base?Boolean Also known as: base?

Is this unit in base form?

Returns:

  • (Boolean)


434
435
436
437
438
439
440
# File 'lib/ruby_units/unit.rb', line 434

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

#is_degree?Boolean Also known as: degree?

true if a degree unit or equivalent.

Returns:

  • (Boolean)


580
581
582
# File 'lib/ruby_units/unit.rb', line 580

def is_degree?
  return self.kind == :temperature
end

#is_temperature?Boolean Also known as: temperature?

TODO:

use unit definition to determine if it’s a temperature instead of a regex

true if unit is a ‘temperature’, false if a ‘degree’ or anything else

Returns:

  • (Boolean)


572
573
574
# File 'lib/ruby_units/unit.rb', line 572

def is_temperature?
  return self.is_degree? && (!(@@UNIT_MAP[self.units] =~ /temp[CFRK]/).nil?)
end

#kindSymbol

@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…)

Returns:

  • (Symbol)


391
392
393
# File 'lib/ruby_units/unit.rb', line 391

def kind
  return @@KINDS[self.signature]
end

#kind_of?(klass) ⇒ Boolean

needed to make complex units play nice – otherwise not detected as a complex_generic

Parameters:

  • (Class)

Returns:

  • (Boolean)


249
250
251
# File 'lib/ruby_units/unit.rb', line 249

def kind_of?(klass)
  self.scalar.kind_of?(klass)
end

#power(n) ⇒ Unit

returns the unit raised to the n-th power

Parameters:

  • n (Integer)

Returns:

Raises:

  • (ArgumentError)

    when attempting to raise a temperature to a power

  • (ArgumentError)

    when n is not an integer



880
881
882
883
884
885
886
887
888
889
890
891
# File 'lib/ruby_units/unit.rb', line 880

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

#predUnit

returns previous unit in a range. ‘2 mm’.unit.pred #=> ‘1 mm’.unit only works when the scalar is an integer

Returns:

Raises:

  • (ArgumentError)

    when scalar is not equal to an integer



1158
1159
1160
1161
# File 'lib/ruby_units/unit.rb', line 1158

def pred
  raise ArgumentError, "Non Integer Scalar" unless @scalar == @scalar.to_i
  return RubyUnits::Unit.new(@scalar.to_i.pred, @numerator, @denominator)
end

#root(n) ⇒ Unit

Calculates the n-th root of a unit if n < 0, returns 1/unit^(1/n)

Parameters:

  • n (Integer)

Returns:

Raises:

  • (ArgumentError)

    when attemptint to take the root of a temperature

  • (ArgumentError)

    when n is not an integer

  • (ArgumentError)

    when n is 0



900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
# File 'lib/ruby_units/unit.rb', line 900

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 RubyUnits::Unit.new(:scalar => q, :numerator => num, :denominator => den)
end

#round(ndigits = 0) ⇒ Numeric, Unit

Returns:



1125
1126
1127
1128
# File 'lib/ruby_units/unit.rb', line 1125

def round
  return @scalar.round if self.unitless?
  return RubyUnits::Unit.new(@scalar.round, @numerator, @denominator)
end

#since(time_point) ⇒ Unit

Examples:

‘min’.since(time)

Parameters:

Returns:

Raises:

  • (ArgumentError)

    when time point is not a Time, Date, or DateTime



1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
# File 'lib/ruby_units/unit.rb', line 1212

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

#succUnit Also known as: next

returns next unit in a range. ‘1 mm’.unit.succ #=> ‘2 mm’.unit only works when the scalar is an integer

Returns:

Raises:

  • (ArgumentError)

    when scalar is not equal to an integer



1147
1148
1149
1150
# File 'lib/ruby_units/unit.rb', line 1147

def succ
  raise ArgumentError, "Non Integer Scalar" unless @scalar == @scalar.to_i
  return RubyUnits::Unit.new(@scalar.to_i.succ, @numerator, @denominator)
end

#temperature_scaleString

returns the ‘degree’ unit associated with a temperature unit

Examples:

‘100 tempC’.unit.temperature_scale #=> ‘degC’

Returns:

  • (String)

    possible values: degC, degF, degR, or degK



589
590
591
592
# File 'lib/ruby_units/unit.rb', line 589

def temperature_scale
  return nil unless self.is_temperature?
  return "deg#{@@UNIT_MAP[self.units][/temp([CFRK])/, 1]}"
end

#to_baseUnit Also known as: base

TODO:

this is brittle as it depends on the display_name of a unit, which can be changed

convert to base SI units results of the conversion are cached so subsequent calls to this will be fast

Returns:



448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
# File 'lib/ruby_units/unit.rb', line 448

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

  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
      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
  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]
    end
  end

  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

#to_cComplex

converts the unit back to a complex if it is unitless. Otherwise raises an exception

Returns:

  • (Complex)

Raises:

  • (RuntimeError)

    when not unitless



1020
1021
1022
1023
# File 'lib/ruby_units/unit.rb', line 1020

def to_c
  return Complex(@scalar) if self.unitless?
  raise RuntimeError, "Cannot convert '#{self.to_s}' to Complex unless unitless.  Use Unit#scalar"
end

#to_dateDate

Returns:



1179
1180
1181
# File 'lib/ruby_units/unit.rb', line 1179

def to_date
  return Date.new0(self.convert_to('d').scalar)
end

#to_datetimeDateTime

convert a duration to a DateTime. This will work so long as the duration is the duration from the zero date defined by DateTime

Returns:

  • (DateTime)


1174
1175
1176
# File 'lib/ruby_units/unit.rb', line 1174

def to_datetime
  return DateTime.new!(self.convert_to('d').scalar)
end

#to_fFloat

converts the unit back to a float if it is unitless. Otherwise raises an exception

Returns:

  • (Float)

Raises:

  • (RuntimeError)

    when not unitless



1012
1013
1014
1015
# File 'lib/ruby_units/unit.rb', line 1012

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

#to_iInteger Also known as: to_int

if unitless, returns an int, otherwise raises an error

Returns:

  • (Integer)

Raises:

  • (RuntimeError)

    when not unitless



1028
1029
1030
1031
# File 'lib/ruby_units/unit.rb', line 1028

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

#to_rRational

if unitless, returns a Rational, otherwise raises an error

Returns:

  • (Rational)

Raises:

  • (RuntimeError)

    when not unitless



1038
1039
1040
1041
# File 'lib/ruby_units/unit.rb', line 1038

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

#to_s(target_units = nil) ⇒ String

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

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

Examples:

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)

Parameters:

  • target_units (Symbol) (defaults to: nil)

Returns:



519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
# File 'lib/ruby_units/unit.rb', line 519

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

#to_timeTime Also known as: time

Tries to make a Time object from current unit. Assumes the current unit hold the duration in seconds from the epoch.

Returns:



1165
1166
1167
# File 'lib/ruby_units/unit.rb', line 1165

def to_time
  return Time.at(self)
end

#to_unitUnit Also known as: unit

Returns:



426
427
428
# File 'lib/ruby_units/unit.rb', line 426

def to_unit
  self
end

#to_yaml(opts = {}) ⇒ String

basically a copy of the basic to_yaml. Needed because otherwise it ends up coercing the object to a string before YAML’izing it.

Parameters:

  • opts (Hash) (defaults to: {})

Returns:



280
281
282
283
284
285
286
287
288
# File 'lib/ruby_units/unit.rb', line 280

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

#to_yaml_propertiesArray

a list of properties to emit to yaml

Returns:



272
273
274
# File 'lib/ruby_units/unit.rb', line 272

def to_yaml_properties
  %w{@scalar @numerator @denominator @signature @base_scalar}
end

#truncateNumeric, Unit

Returns:



1138
1139
1140
1141
# File 'lib/ruby_units/unit.rb', line 1138

def truncate
  return @scalar.truncate if self.unitless?
  return RubyUnits::Unit.new(@scalar.truncate, @numerator, @denominator)
end

#unitless?Boolean

returns true if no associated units false, even if the units are “unitless” like ‘radians, each, etc’

Returns:

  • (Boolean)


597
598
599
# File 'lib/ruby_units/unit.rb', line 597

def unitless?
  return(@numerator == UNITY_ARRAY && @denominator == UNITY_ARRAY)
end

#units(with_prefix = true) ⇒ String

returns the ‘unit’ part of the Unit object without the scalar

Returns:



1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
# File 'lib/ruby_units/unit.rb', line 1051

def units(with_prefix = true)
  return "" if @numerator == UNITY_ARRAY && @denominator == UNITY_ARRAY
  output_numerator   = []
  output_denominator = []
  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?
        if with_prefix
          output_numerator << (defn.display_name + RubyUnits::Unit.definition(num.shift).display_name)
        end
      else
        output_numerator << defn.display_name
      end
    end
  end

  if @denominator == UNITY_ARRAY
    output_denominator = []
  else
    while defn = RubyUnits::Unit.definition(den.shift) do
      if defn && defn.prefix?
        if with_prefix
          output_denominator << (defn.display_name + RubyUnits::Unit.definition(den.shift).display_name)
        end
      else
        output_denominator << defn.display_name
      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
  return out
end

#until(time_point) ⇒ Unit

Examples:

‘min’.until(time)

Parameters:

Returns:



1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
# File 'lib/ruby_units/unit.rb', line 1226

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

#zero?Boolean

true if scalar is zero

Returns:

  • (Boolean)


1185
1186
1187
# File 'lib/ruby_units/unit.rb', line 1185

def zero?
  return self.base_scalar.zero?
end