Module: Money::Arithmetic

Included in:
Money
Defined in:
lib/money/money/arithmetic.rb

Defined Under Namespace

Classes: CoercedNumeric

Instance Method Summary collapse

Instance Method Details

#%(val) ⇒ Money

Synonym for #modulo.

Parameters:

  • val (Money, Integer)

    Number take modulo with.

Returns:

See Also:



264
265
266
# File 'lib/money/money/arithmetic.rb', line 264

def %(val)
  modulo(val)
end

#*(value) ⇒ Money

Multiplies the monetary value with the given number and returns a new Money object with this monetary value and the same currency.

Note that you can’t multiply a Money object by an other Money object.

Examples:

Money.new(100) * 2 #=> #<Money @fractional=200>

Parameters:

  • value (Numeric)

    Number to multiply by.

Returns:

  • (Money)

    The resulting money.

Raises:

  • (TypeError)

    If value is NOT a number.



167
168
169
170
171
172
173
174
# File 'lib/money/money/arithmetic.rb', line 167

def *(value)
  value = value.value if value.is_a?(CoercedNumeric)
  if value.is_a? Numeric
    dup_with(fractional: fractional * value)
  else
    raise TypeError, "Can't multiply a #{self.class.name} by a #{value.class.name}'s value"
  end
end

#+(other) ⇒ Money

Returns a new Money object containing the sum of the two operands’ monetary values. If other_money has a different currency then its monetary value is automatically exchanged to this object’s currency using exchange_to.

Returns a new Money object containing the difference between the two operands’ monetary values. If other_money has a different currency then its monetary value is automatically exchanged to this object’s currency using exchange_to.

Examples:

Money.new(100) + Money.new(100) #=> #<Money @fractional=200>
Money.new(100) - Money.new(99) #=> #<Money @fractional=1>

Parameters:

  • other (Money)

    Other Money object to add.

  • other (Money)

    Other Money object to subtract.

Returns:



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/money/money/arithmetic.rb', line 130

[:+, :-].each do |op|
  non_zero_message = lambda do |value|
    "Can't add or subtract a non-zero #{value.class.name} value"
  end

  define_method(op) do |other|
    case other
    when Money
      other = other.exchange_to(currency)
      new_fractional = fractional.public_send(op, other.fractional)
      dup_with(fractional: new_fractional)
    when CoercedNumeric
      raise TypeError, non_zero_message.call(other.value) unless other.zero?
      dup_with(fractional: other.value.public_send(op, fractional))
    when Numeric
      raise TypeError, non_zero_message.call(other) unless other.zero?
      self
    else
      raise TypeError, "Unsupported argument type: #{other.class.name}"
    end
  end
end

#-(other) ⇒ Money

Returns a new Money object containing the sum of the two operands’ monetary values. If other_money has a different currency then its monetary value is automatically exchanged to this object’s currency using exchange_to.

Returns a new Money object containing the difference between the two operands’ monetary values. If other_money has a different currency then its monetary value is automatically exchanged to this object’s currency using exchange_to.

Examples:

Money.new(100) + Money.new(100) #=> #<Money @fractional=200>
Money.new(100) - Money.new(99) #=> #<Money @fractional=1>

Parameters:

  • other (Money)

    Other Money object to add.

  • other (Money)

    Other Money object to subtract.

Returns:



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/money/money/arithmetic.rb', line 130

[:+, :-].each do |op|
  non_zero_message = lambda do |value|
    "Can't add or subtract a non-zero #{value.class.name} value"
  end

  define_method(op) do |other|
    case other
    when Money
      other = other.exchange_to(currency)
      new_fractional = fractional.public_send(op, other.fractional)
      dup_with(fractional: new_fractional)
    when CoercedNumeric
      raise TypeError, non_zero_message.call(other.value) unless other.zero?
      dup_with(fractional: other.value.public_send(op, fractional))
    when Numeric
      raise TypeError, non_zero_message.call(other) unless other.zero?
      self
    else
      raise TypeError, "Unsupported argument type: #{other.class.name}"
    end
  end
end

#-@Money

Returns a money object with changed polarity.

Examples:

- Money.new(100) #=> #<Money @fractional=-100>

Returns:



18
19
20
# File 'lib/money/money/arithmetic.rb', line 18

def -@
  dup_with(fractional: -fractional)
end

#/(value) ⇒ Money, Float

Divides the monetary value with the given number and returns a new Money object with this monetary value and the same currency. Can also divide by another Money object to get a ratio.

Money/Numeric returns Money. Money/Money returns Float.

Examples:

Money.new(100) / 10            #=> #<Money @fractional=10>
Money.new(100) / Money.new(10) #=> 10.0

Parameters:

  • value (Money, Numeric)

    Number to divide by.

Returns:

  • (Money)

    The resulting money if you divide Money by a number.

  • (Float)

    The resulting number if you divide Money by a Money.



191
192
193
194
195
196
197
198
# File 'lib/money/money/arithmetic.rb', line 191

def /(value)
  if value.is_a?(self.class)
    fractional / as_d(value.exchange_to(currency).fractional).to_f
  else
    raise TypeError, 'Can not divide by Money' if value.is_a?(CoercedNumeric)
    dup_with(fractional: fractional / as_d(value))
  end
end

#<=>(other) ⇒ Integer

Compares two Money objects. If money objects have a different currency it will attempt to convert the currency.

Parameters:

  • other (Money)

    Value to compare with.

Returns:

  • (Integer)

Raises:

  • (TypeError)

    when other object is not Money



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/money/money/arithmetic.rb', line 55

def <=>(other)
  unless other.is_a?(Money)
    return unless other.respond_to?(:zero?) && other.zero?
    return other.is_a?(CoercedNumeric) ? 0 <=> fractional : fractional <=> 0
  end

  # Always allow comparison with zero
  if zero? || other.zero?
    return fractional <=> other.fractional
  end

  other = other.exchange_to(currency)
  fractional <=> other.fractional
rescue Money::Bank::UnknownRate
end

#==(other) ⇒ Object

Uses Comparable’s implementation but raises ArgumentError if non-zero numeric value is given.



73
74
75
76
77
78
# File 'lib/money/money/arithmetic.rb', line 73

def ==(other)
  if other.is_a?(Numeric) && !other.zero?
    raise ArgumentError, 'Money#== supports only zero numerics'
  end
  super
end

#absMoney

Return absolute value of self as a new Money object.

Examples:

Money.new(-100).abs #=> #<Money @fractional=100>

Returns:



294
295
296
# File 'lib/money/money/arithmetic.rb', line 294

def abs
  dup_with(fractional: fractional.abs)
end

#coerce(other) ⇒ Array

Used to make Money instance handle the operations when arguments order is reversed

Examples:

2 * Money.new(10) #=> #<Money @fractional=20>

Returns:

  • (Array)


326
327
328
# File 'lib/money/money/arithmetic.rb', line 326

def coerce(other)
  [self, CoercedNumeric.new(other)]
end

#div(value) ⇒ Money, Float

Synonym for #/.

Parameters:

  • value (Money, Numeric)

    Number to divide by.

Returns:

  • (Money)

    The resulting money if you divide Money by a number.

  • (Float)

    The resulting number if you divide Money by a Money.

See Also:



209
210
211
# File 'lib/money/money/arithmetic.rb', line 209

def div(value)
  self / value
end

#divmod(val) ⇒ Array<Money,Money>, Array<Integer,Money>

Divide money by money or fixnum and return array containing quotient and modulus.

Examples:

Money.new(100).divmod(9)            #=> [#<Money @fractional=11>, #<Money @fractional=1>]
Money.new(100).divmod(Money.new(9)) #=> [11, #<Money @fractional=1>]

Parameters:

  • val (Money, Integer)

    Number to divmod by.

Returns:



223
224
225
226
227
228
229
# File 'lib/money/money/arithmetic.rb', line 223

def divmod(val)
  if val.is_a?(Money)
    divmod_money(val)
  else
    divmod_other(val)
  end
end

#eql?(other_money) ⇒ Boolean

Checks whether two Money objects have the same currency and the same amount. If Money objects have a different currency it will only be true if the amounts are both zero. Checks against objects that are not Money or a subclass will always return false.

Examples:

Money.new(100).eql?(Money.new(101))                #=> false
Money.new(100).eql?(Money.new(100))                #=> true
Money.new(100, "USD").eql?(Money.new(100, "GBP"))  #=> false
Money.new(0, "USD").eql?(Money.new(0, "EUR"))      #=> true
Money.new(100).eql?("1.00")                        #=> false

Parameters:

  • other_money (Money)

    Value to compare with.

Returns:

  • (Boolean)


37
38
39
40
41
42
43
44
# File 'lib/money/money/arithmetic.rb', line 37

def eql?(other_money)
  if other_money.is_a?(Money)
    (fractional == other_money.fractional && currency == other_money.currency) ||
      (fractional == 0 && other_money.fractional == 0)
  else
    false
  end
end

#modulo(val) ⇒ Money

Equivalent to self.divmod(val)

Examples:

Money.new(100).modulo(9)            #=> #<Money @fractional=1>
Money.new(100).modulo(Money.new(9)) #=> #<Money @fractional=1>

Parameters:

  • val (Money, Integer)

    Number take modulo with.

Returns:



253
254
255
# File 'lib/money/money/arithmetic.rb', line 253

def modulo(val)
  divmod(val)[1]
end

#negative?Boolean

Test if the amount is negative. Returns true if the money amount is less than 0, false otherwise.

Examples:

Money.new(-1).negative? #=> true
Money.new(0).negative?  #=> false
Money.new(1).negative?  #=> false

Returns:

  • (Boolean)


102
103
104
# File 'lib/money/money/arithmetic.rb', line 102

def negative?
  fractional < 0
end

#nonzero?Money?

Test if the money amount is non-zero. Returns this money object if it is non-zero, or nil otherwise, like Numeric#nonzero?.

Examples:

Money.new(100).nonzero? #=> #<Money @fractional=100>
Money.new(0).nonzero?   #=> nil

Returns:



317
318
319
# File 'lib/money/money/arithmetic.rb', line 317

def nonzero?
  fractional != 0 ? self : nil
end

#positive?Boolean

Test if the amount is positive. Returns true if the money amount is greater than 0, false otherwise.

Examples:

Money.new(1).positive?  #=> true
Money.new(0).positive?  #=> false
Money.new(-1).positive? #=> false

Returns:

  • (Boolean)


89
90
91
# File 'lib/money/money/arithmetic.rb', line 89

def positive?
  fractional > 0
end

#remainder(val) ⇒ Money

If different signs self.modulo(val) - val otherwise self.modulo(val)

Examples:

Money.new(100).remainder(9) #=> #<Money @fractional=1>

Parameters:

  • val (Money, Integer)

    Number to rake remainder with.

Returns:



276
277
278
279
280
281
282
283
284
285
286
# File 'lib/money/money/arithmetic.rb', line 276

def remainder(val)
  if val.is_a?(Money) && currency != val.currency
    val = val.exchange_to(currency)
  end

  if (fractional < 0 && val < 0) || (fractional > 0 && val > 0)
    self.modulo(val)
  else
    self.modulo(val) - (val.is_a?(Money) ? val : dup_with(fractional: val))
  end
end

#zero?Boolean

Test if the money amount is zero.

Examples:

Money.new(100).zero? #=> false
Money.new(0).zero?   #=> true

Returns:

  • (Boolean)


305
306
307
# File 'lib/money/money/arithmetic.rb', line 305

def zero?
  fractional == 0
end