Module: Horologium::PreciseValue

Includes:
Comparable
Included in:
Duration, Instant
Defined in:
lib/horologium/precise_value.rb,
sig/horologium/precise_value.rbs

Overview

Shared behaviour for the library's immutable precise values, Instant and Duration. Each holds a numeric value in a fixed precision and is compared by the value it denotes, across precisions.

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#precisionSymbol (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The precision, set when the value was built.

Returns:

  • (Symbol)

    :standard or :exact



21
22
23
# File 'lib/horologium/precise_value.rb', line 21

def precision
  @precision
end

#rationalRational (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The value denoted, as a Rational, computed once at construction so a frozen value never recomputes it for comparison.

Returns:

  • (Rational)


83
84
85
# File 'lib/horologium/precise_value.rb', line 83

def rational
  @rational
end

#valueHorologium::Numeric::TwoPartFloat, Horologium::Numeric::Exact (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The numeric value, held as a Numeric::TwoPartFloat or a Numeric::Exact.



15
16
17
# File 'lib/horologium/precise_value.rb', line 15

def value
  @value
end

Instance Method Details

#<=>(other) ⇒ Integer?

Orders by the value denoted, across precisions. The same value compares equal whatever the precision, so == (from Comparable) and sorting ignore it.

Parameters:

  • other (Object)

    the value to compare with

Returns:

  • (Integer, nil)

    -1, 0, or 1, or nil when other is not the same kind of value



53
54
55
56
57
# File 'lib/horologium/precise_value.rb', line 53

def <=>(other)
  return unless other.is_a?(self.class)

  rational <=> other.rational
end

#eql?(other) ⇒ Boolean

Stricter equality, for Hash keys and Sets. Two values are eql? only when they are the same kind, share a precision, and denote the same value.

Parameters:

  • other (Object)

    the value to compare with

Returns:

  • (Boolean)


64
65
66
67
68
# File 'lib/horologium/precise_value.rb', line 64

def eql?(other)
  other.is_a?(self.class) &&
    precision == other.precision &&
    rational == other.rational
end

#hashInteger

Returns a hash matching #eql?, from the kind, precision, and value.

Returns:

  • (Integer)

    a hash matching #eql?, from the kind, precision, and value



72
73
74
# File 'lib/horologium/precise_value.rb', line 72

def hash
  [self.class, precision, rational].hash
end

#initialize(value, precision) ⇒ PreciseValue

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Wraps a numeric value in a precision. The value must match the precision: a Numeric::Exact for :exact, a Numeric::TwoPartFloat for :standard.

Parameters:

Returns:

Raises:

  • (UnknownPrecisionError)

    when the precision is not recognised

  • (ArgumentError)

    when the value does not match the precision



33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/horologium/precise_value.rb', line 33

def initialize(value, precision)
  expected = Numeric::Precision.value_type(precision)
  unless value.is_a?(expected)
    raise ArgumentError,
      "a #{precision} value must be a #{expected}, got a #{value.class}"
  end

  @value = value
  @precision = precision
  @rational = value.to_r
  freeze
end