Class: Van::Units::Value

Inherits:
Numeric show all
Includes:
Comparable
Defined in:
lib/van/units/base.rb

Overview

This class represents a Value with a numeric value and a Unit. The numeric value can be any Numeric, though it is not recommended to use Values.

A Value can be added to, subtracted from and multiplied with another value, though only when both Values are using the same Converter. While multiplication is always possible, adding or subtracting values with incompatible units results in a TypeError. When two units are compatible but not the same, the Value with the larger of the units is converted to the smaller of the units. For example adding 100 seconds and 1 minute, the latter is converted to 60 seconds because a second is smaller than a minute. The result is 160 seconds.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(value, unit) ⇒ Value

:nodoc:



411
412
413
# File 'lib/van/units/base.rb', line 411

def initialize(value, unit) # :nodoc:
  @value, @unit = value, unit
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

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



562
563
564
565
566
567
568
569
570
571
572
573
# File 'lib/van/units/base.rb', line 562

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::Value.new(1, 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::Value.new(1, Units::Unit.new({m => 1}, Units::Converter.current))
  end
  ::Exception.with_clean_backtrace("method_missing") {
    super
  }
end

Instance Attribute Details

#unitObject (readonly)

The Unit of this value.



368
369
370
# File 'lib/van/units/base.rb', line 368

def unit
  @unit
end

#valueObject (readonly)

The numeric value of this Value.



366
367
368
# File 'lib/van/units/base.rb', line 366

def value
  @value
end

Class Method Details

.new(value, *args) ⇒ Object

Creates a new Value with the given numeric value and the given unit. Simply returns the given value if the given unit is unitless, i.e., when unit.unitless? is true.



381
382
383
384
385
# File 'lib/van/units/base.rb', line 381

def new(value, *args)
  res = new!(value, *args)
  return res.value if res.unit.unitless?
  res
end

.new!(value, *args) ⇒ Object



387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
# File 'lib/van/units/base.rb', line 387

def new!(value, *args)
  if ::String === value
    str = *args
    converter = case args.length
                when 0
                when 1
                  conv = args[0]
                else
                  raise ArgumentError, "wrong number of arguments"
                end
    value, unit = decode_string(value, converter)
  else
    if args.length == 1
      unit = args[0]
    else
      raise ArgumentError, "wrong number of arguments"
    end
  end
  unit = Unit.new(unit) unless unit.is_a?(Unit)
  old_new(value, unit)
end

.old_newObject



374
# File 'lib/van/units/base.rb', line 374

alias old_new new

Instance Method Details

#**(other) ⇒ Object

:nodoc:



448
449
450
# File 'lib/van/units/base.rb', line 448

def **(other) # :nodoc:
  Units::Value.new(@value ** other, @unit ** other)
end

#+@Object

:nodoc:



444
445
446
# File 'lib/van/units/base.rb', line 444

def +@ # :nodoc:
  self
end

#-@Object

:nodoc:



440
441
442
# File 'lib/van/units/base.rb', line 440

def -@ # :nodoc:
  Value.new(-@value, @unit)
end

#<=>(other) ⇒ Object

:nodoc:



452
453
454
455
456
457
458
459
460
# File 'lib/van/units/base.rb', line 452

def <=>(other) # :nodoc:
  if other == 0
    @value <=> 0
  else
    (self - other).value <=> 0
  end
rescue TypeError
  nil
end

#coerce(other) ⇒ Object

:nodoc:



498
499
500
501
502
503
504
# File 'lib/van/units/base.rb', line 498

def coerce(other) # :nodoc:
  if ::Numeric === other
    [Units::Value.new!(other, Units::Unit.new), self]
  else
    super
  end
end

#div(other) ⇒ Object



436
437
438
# File 'lib/van/units/base.rb', line 436

def div(other)
  do_additive_op(:div, other)[0]
end

#divmod(other) ⇒ Object



431
432
433
434
# File 'lib/van/units/base.rb', line 431

def divmod(other)
  (q, r), unit = *do_additive_op(:divmod, other)
  [q, Units::Value.new(r, unit)]
end

#hashObject



464
465
466
# File 'lib/van/units/base.rb', line 464

def hash
  @value.hash ^ @unit.hash
end

#simplifyObject

Forces simplification of the Unit part of this Value. Returns a new Value or a Float.



546
547
548
549
550
551
552
553
# File 'lib/van/units/base.rb', line 546

def simplify
  mul, new_unit = *@unit.simplify
  if new_unit.unitless?
    @value * mul
  else
    Units::Value.new(@value * mul, new_unit)
  end
end

#to(to_unit, converter = nil) ⇒ Object

Converts this Value to the given Unit. This only works if the Converters used by this Value’s Unit and the given Unit are the same. It obviously fails if the Units are not compatible (can’t add apples and oranges).

Raises:

  • (ArgumentError)


488
489
490
491
492
493
494
495
496
# File 'lib/van/units/base.rb', line 488

def to(to_unit, converter = nil)
  raise ArgumentError, "Wrong number of arguments" if converter && !(::String === to_unit)
  to_unit = to_unit.to_unit(converter)
  raise TypeError, "cannot convert to Unit" unless Units::Unit === to_unit
  conv1, conv2 = unit.coerce(to_unit)
  raise TypeError, "incompatible units for operation" if conv1.units != conv2.units
  mult = conv1.multiplier / conv2.multiplier
  Units::Value.new(value * mult, to_unit)
end

#to_fObject

Returns a float if this Value is unitless, and raises an exception otherwise.



513
514
515
516
517
518
519
520
# File 'lib/van/units/base.rb', line 513

def to_f
  val = simplify
  if Units::Value === val
    raise TypeError, "Cannot convert to float"
  else
    val.to_f
  end
end

#to_iObject

Returns an int if this Value is unitless, and raises an exception otherwise.



524
525
526
527
528
529
530
531
# File 'lib/van/units/base.rb', line 524

def to_i
  val = simplify
  if Units::Value === val
    raise TypeError, "Cannot convert to integer"
  else
    val.to_i
  end
end

#to_intObject

Returns an int if this Value is unitless, and raises an exception otherwise.



535
536
537
538
539
540
541
542
# File 'lib/van/units/base.rb', line 535

def to_int
  val = simplify
  if Units::Value === val
    raise TypeError, "Cannot convert to integer"
  else
    val.to_int
  end
end

#to_sObject Also known as: inspect

Returns a human readable string representation.



507
508
509
# File 'lib/van/units/base.rb', line 507

def to_s
  "#{@value} #{@unit}"
end

#to_value(converter = nil) ⇒ Object

Returns self.



556
557
558
# File 'lib/van/units/base.rb', line 556

def to_value(converter = nil)
  self
end