Class: Stick::Units::Unit

Inherits:
Object
  • Object
show all
Defined in:
lib/stick/units/base.rb

Overview

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, divided, and raised to a given power. 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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(units = {}, converter = nil) ⇒ Unit

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



206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/stick/units/base.rb', line 206

def initialize(units = {}, converter = nil)
  conv = proc { converter ||= Units::Converter.current }
  if units.is_a? ::String
    @units = decode_string(units, conv)
  else
    @units = {}
    units.each_pair do |k, v|
      k = conv[].base_unit(k.to_sym) if not k.is_a? Units::BaseUnit
      @units[k] = v
    end
  end
  normalize_units
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(m, *args, &blk) ⇒ Object



291
292
293
294
295
296
297
298
299
300
301
302
# File 'lib/stick/units/base.rb', line 291

def method_missing(m, *args, &blk)
  if args.length == 1
    args[0] = (Units::Converter.converter(args[0]) rescue nil) if not args[0].is_a? Units::Converter
    return self * Units::Unit.new({m => 1}, args[0]) if args[0] && args[0].registered?(m)
  elsif (Units::Converter.current.registered?(m) rescue false)
    raise ::ArgumentError, "Wrong number of arguments" if args.length != 0
    return self * Units::Unit.new({m => 1}, Units::Converter.current)
  end
  ::Exception.with_clean_backtrace("method_missing") {
    super
  }
end

Instance Attribute Details

#unitsObject (readonly)

Returns the value of attribute units.



194
195
196
# File 'lib/stick/units/base.rb', line 194

def units
  @units
end

Instance Method Details

#*(other) ⇒ Object

Multiplies with the given Unit.



230
231
232
# File 'lib/stick/units/base.rb', line 230

def *(other)
  do_op(:*, :+, other)
end

#**(p) ⇒ Object

Raises to the given power.



221
222
223
224
225
226
227
# File 'lib/stick/units/base.rb', line 221

def **(p)
  result = {}
  @units.each_pair do |u, e|
    result[u] = e * p
  end
  Units::Unit.new(result)
end

#/(other) ⇒ Object

Divides by the given Unit.



235
236
237
# File 'lib/stick/units/base.rb', line 235

def /(other)
  do_op(:/, :-, other)
end

#==(other) ⇒ Object Also known as: eql?

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.



255
256
257
# File 'lib/stick/units/base.rb', line 255

def ==(other)
  other.is_a?(Units::Unit) && other.units == units
end

#coerce(other) ⇒ Object

:nodoc:



244
245
246
247
# File 'lib/stick/units/base.rb', line 244

def coerce(other) # :nodoc:
  return [Units::Unit.new({}), self] if other == 1
  Units::Converter.coerce_units(self, other)
end

#compatible_with?(other) ⇒ Boolean

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.

Returns:

  • (Boolean)


268
269
270
271
# File 'lib/stick/units/base.rb', line 268

def compatible_with?(other)
  conv1, conv2 = Units::Converter.coerce_units(self, other)
  conv1.units == conv2.units
end

#hashObject



261
262
263
# File 'lib/stick/units/base.rb', line 261

def hash
  @units.to_a.map { |e| e.hash }.hash
end

#simplifyObject



249
250
251
# File 'lib/stick/units/base.rb', line 249

def simplify
  Units::Converter.simplify_unit(self)
end

#to_sObject Also known as: inspect

Returns a human readable string representation.



274
275
276
277
278
279
280
281
282
# File 'lib/stick/units/base.rb', line 274

def to_s
  numerator = ""
  denominator = ""
  @units.each_pair do |u, e|
    e_abs = e > 0 ? e : -e # This works with Complex too
    (e > 0 ? numerator : denominator) << " #{u.to_s}#{"**#{e_abs}" if e_abs != 1}"
  end
  "#{numerator.lstrip}#{"/" + denominator.lstrip if not denominator.empty?}"
end

#to_unit(converter = nil) ⇒ Object

Returns self.



285
286
287
# File 'lib/stick/units/base.rb', line 285

def to_unit(converter = nil)
  self
end

#unitless?Boolean

Returns true iff this Unit has all exponents equal to 0.

Returns:

  • (Boolean)


240
241
242
# File 'lib/stick/units/base.rb', line 240

def unitless?
  @units.empty?
end