Module: WhittakerTech::Midas::Coin::Arithmetic
- Included in:
- WhittakerTech::Midas::Coin
- Defined in:
- app/models/whittaker_tech/midas/coin/arithmetic.rb
Overview
Arithmetic defines the arithmetic and equality semantics of a Coin.
Design invariants
- Immutable — all operations return new, frozen
Coinobjects. - Closed — operations always return a
Coin, never a primitive. - Policy-aware only where unavoidable — division accepts a rounding policy; all other operations are exact.
- Currency-strict — binary operations (
+,-,==) raiseArgumentErrorwhen the operands have different currency codes.
Convenience division helpers
For each key in WhittakerTech::Midas::ROUNDING_POLICIES a named shorthand
is generated:
coin.divide_round(3) # same as coin.divide(3, rounding_policy: :round)
coin.divide_ceil(3)
coin.divide_floor(3)
coin.divide_bankers(3)
Instance Method Summary collapse
-
#%(other) ⇒ Coin
Returns the remainder after dividing by an integer.
-
#*(other) ⇒ Coin
Multiplies the Coin by an integer scalar.
-
#+(other) ⇒ Coin
Adds two Coins and returns the sum as a new Coin.
-
#-(other) ⇒ Coin
Subtracts another Coin from the receiver and returns the difference.
-
#-@ ⇒ Coin
Unary minus operator — shorthand for
#negate. -
#==(other) ⇒ Boolean
(also: #eql?)
Tests value equality with another Coin.
-
#divide(divisor, rounding_policy: WhittakerTech::Midas::DEFAULT_ROUNDING_POLICY) ⇒ Coin
Divides the Coin by a numeric divisor and returns the quotient.
-
#hash ⇒ Integer
Returns a hash value consistent with
#eql?. -
#negate ⇒ Coin
Returns a new Coin with the sign reversed.
Instance Method Details
#%(other) ⇒ Coin
Returns the remainder after dividing by an integer.
109 110 111 112 113 114 |
# File 'app/models/whittaker_tech/midas/coin/arithmetic.rb', line 109 def %(other) raise TypeError unless other.is_a?(Integer) raise ZeroDivisionError if other.zero? WhittakerTech::Midas::Coin.value(currency_minor % other, currency_code).freeze end |
#*(other) ⇒ Coin
Multiplies the Coin by an integer scalar.
94 95 96 97 98 |
# File 'app/models/whittaker_tech/midas/coin/arithmetic.rb', line 94 def *(other) raise TypeError unless other.is_a?(Integer) WhittakerTech::Midas::Coin.value(currency_minor * other, currency_code).freeze end |
#+(other) ⇒ Coin
Adds two Coins and returns the sum as a new Coin.
65 66 67 68 |
# File 'app/models/whittaker_tech/midas/coin/arithmetic.rb', line 65 def +(other) ensure_same_currency!(other) WhittakerTech::Midas::Coin.value(currency_minor + other.currency_minor, currency_code).freeze end |
#-(other) ⇒ Coin
Subtracts another Coin from the receiver and returns the difference.
81 82 83 84 |
# File 'app/models/whittaker_tech/midas/coin/arithmetic.rb', line 81 def -(other) ensure_same_currency!(other) WhittakerTech::Midas::Coin.value(currency_minor - other.currency_minor, currency_code).freeze end |
#-@ ⇒ Coin
Unary minus operator — shorthand for #negate.
129 130 131 |
# File 'app/models/whittaker_tech/midas/coin/arithmetic.rb', line 129 def -@ negate end |
#==(other) ⇒ Boolean Also known as: eql?
Tests value equality with another Coin.
Two Coins are equal when they have the same currency code and the same minor-unit amount. A Coin is never equal to a non-Coin object.
33 34 35 36 37 |
# File 'app/models/whittaker_tech/midas/coin/arithmetic.rb', line 33 def ==(other) other.is_a?(WhittakerTech::Midas::Coin) && currency_code == other.currency_code && currency_minor == other.currency_minor end |
#divide(divisor, rounding_policy: WhittakerTech::Midas::DEFAULT_ROUNDING_POLICY) ⇒ Coin
Divides the Coin by a numeric divisor and returns the quotient.
Division is the only arithmetic operation that requires a rounding policy because dividing integer minor units can produce a non-integer result.
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'app/models/whittaker_tech/midas/coin/arithmetic.rb', line 150 def divide(divisor, rounding_policy: WhittakerTech::Midas::DEFAULT_ROUNDING_POLICY) raise TypeError unless divisor.is_a?(Numeric) raise ZeroDivisionError if divisor.zero? mode = WhittakerTech::Midas::ROUNDING_POLICIES[rounding_policy] unless mode warn "Unknown rounding mode: #{rounding_policy.inspect}. Using default rounding mode." mode = WhittakerTech::Midas::ROUNDING_POLICIES[ WhittakerTech::Midas::DEFAULT_ROUNDING_POLICY ] end raw = currency_minor.to_f / divisor minor = mode.call(raw).to_i WhittakerTech::Midas::Coin.value(minor, currency_code).freeze end |
#hash ⇒ Integer
Returns a hash value consistent with #eql?.
Coins with the same currency code and minor-unit amount produce the same hash, making them interchangeable as Hash keys or Set members.
50 51 52 |
# File 'app/models/whittaker_tech/midas/coin/arithmetic.rb', line 50 def hash [currency_code, currency_minor].hash end |
#negate ⇒ Coin
Returns a new Coin with the sign reversed.
122 123 124 |
# File 'app/models/whittaker_tech/midas/coin/arithmetic.rb', line 122 def negate WhittakerTech::Midas::Coin.value(-currency_minor, currency_code).freeze end |