Class: Mint::Money

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/minting/money/money.rb,
lib/minting/money/coercion.rb,
lib/minting/money/allocation.rb,
lib/minting/money/comparable.rb,
lib/minting/money/conversion.rb,
lib/minting/money/arithmetics.rb

Overview

:nodoc Arithmetic funcions for money ojects

Defined Under Namespace

Classes: CoercedNumber

Constant Summary collapse

DEFAULT_FORMAT =
'%<symbol>s%<amount>f'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(amount, currency) ⇒ Money

Returns a new instance of Money.

Raises:

  • (ArgumentError)


11
12
13
14
15
16
17
18
19
20
21
# File 'lib/minting/money/money.rb', line 11

def initialize(amount, currency)
  raise ArgumentError, 'amount must be Numeric' unless amount.is_a?(Numeric)

  unless currency.is_a?(Currency)
    raise ArgumentError,
          'currency must be a Currency object'
  end

  @amount = amount.to_r.round(currency.subunit)
  @currency = currency
end

Instance Attribute Details

#amountObject (readonly)

Returns the value of attribute amount.



9
10
11
# File 'lib/minting/money/money.rb', line 9

def amount
  @amount
end

#currencyObject (readonly)

Returns the value of attribute currency.



9
10
11
# File 'lib/minting/money/money.rb', line 9

def currency
  @currency
end

Instance Method Details

#*(multiplicand) ⇒ Object

Raises:

  • (TypeError)


37
38
39
40
41
# File 'lib/minting/money/arithmetics.rb', line 37

def *(multiplicand)
  return mint(amount * multiplicand.to_r) if multiplicand.is_a?(Numeric)

  raise TypeError, "#{self} can't be multiplied by #{multiplicand}"
end

#+(addend) ⇒ Object

Raises:

  • (TypeError)


19
20
21
22
23
24
# File 'lib/minting/money/arithmetics.rb', line 19

def +(addend)
  return mint(amount + addend.amount) if same_currency?(addend)
  return self unless addend.is_a?(Money) || addend.nonzero?

  raise TypeError, "#{addend} can't be added to #{self}"
end

#-(subtrahend) ⇒ Object

Raises:

  • (TypeError)


26
27
28
29
30
31
# File 'lib/minting/money/arithmetics.rb', line 26

def -(subtrahend)
  return self if subtrahend.zero?
  return mint(amount - subtrahend.amount) if same_currency?(subtrahend)

  raise TypeError, "#{subtrahend} can't be subtracted from #{self}"
end

#-@Object



33
34
35
# File 'lib/minting/money/arithmetics.rb', line 33

def -@
  mint(-amount)
end

#/(divisor) ⇒ Object

Raises:

  • (TypeError)


43
44
45
46
47
48
# File 'lib/minting/money/arithmetics.rb', line 43

def /(divisor)
  return mint(amount / divisor) if divisor.is_a?(Numeric)
  return amount / divisor.amount if same_currency? divisor

  raise TypeError, "#{self} can't be divided by #{divisor}"
end

#<=>(other) ⇒ Object

Examples:

two_usd == Mint.money(2r, Currency['USD']) #=> [$ 2.00]
two_usd > 0                                    #=> true
two_usd > Mint.money(1r, Currency['USD'])  #=> true
two_usd > 1
=> TypeError: [$ 2.00] can't be compared to 1
two_usd > Mint.money(2, Currency['BRL'])
=> TypeError: [$ 2.00] can't be compared to [R$ 2.00]

Raises:

  • (TypeError)


27
28
29
30
31
32
33
34
35
# File 'lib/minting/money/comparable.rb', line 27

def <=>(other)
  case other
  when Numeric
    return amount <=> other if other.zero?
  when Mint::Money
    return amount <=> other.amount if currency == other.currency
  end
  raise TypeError, "#{inspect} can't be compared to #{other.inspect}"
end

#==(other) ⇒ Object

Returns true if both are zero, or both have same amount and same currency.

Returns:

  • true if both are zero, or both have same amount and same currency



10
11
12
13
14
15
16
# File 'lib/minting/money/comparable.rb', line 10

def ==(other)
  return true if other.is_a?(Numeric) && zero? && other.zero?
  return false unless other.is_a?(Mint::Money)
  return false if nonzero? && currency != other.currency

  amount == other.amount
end

#absObject



7
8
9
# File 'lib/minting/money/arithmetics.rb', line 7

def abs
  mint(amount.abs)
end

#allocate(proportions) ⇒ Object

Raises:

  • (ArgumentError)


7
8
9
10
11
12
13
14
# File 'lib/minting/money/allocation.rb', line 7

def allocate(proportions)
  raise ArgumentError, 'Need at least 1 proportion element' if proportions.empty?

  whole = proportions.sum.to_r
  allocation = proportions.map { |rate| mint(amount * rate.to_r / whole) }
  left_over =  self - allocation.sum
  allocate_left_over(allocation, left_over)
end

#coerce(other) ⇒ Object



7
8
9
# File 'lib/minting/money/coercion.rb', line 7

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

#currency_codeObject



23
24
25
# File 'lib/minting/money/money.rb', line 23

def currency_code
  currency.code
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


37
38
39
# File 'lib/minting/money/comparable.rb', line 37

def eql?(other)
  self == other
end

#hashObject



41
42
43
# File 'lib/minting/money/comparable.rb', line 41

def hash
  @hash ||= zero? ? 0.hash : [amount, currency].hash
end

#inspectObject



31
32
33
# File 'lib/minting/money/money.rb', line 31

def inspect
  Kernel.format "[#{currency_code} %0.#{currency.subunit}f]", amount
end

#mint(new_amount) ⇒ Object



27
28
29
# File 'lib/minting/money/money.rb', line 27

def mint(new_amount)
  new_amount.to_r == amount ? self : Money.new(new_amount, currency)
end

#negative?Boolean

Returns:

  • (Boolean)


11
12
13
# File 'lib/minting/money/arithmetics.rb', line 11

def negative?
  amount.negative?
end

#nonzero?Boolean

Returns:

  • (Boolean)


45
46
47
# File 'lib/minting/money/comparable.rb', line 45

def nonzero?
  amount.nonzero?
end

#positive?Boolean

Returns:

  • (Boolean)


15
16
17
# File 'lib/minting/money/arithmetics.rb', line 15

def positive?
  amount.positive?
end

#same_currency?(other) ⇒ Boolean

Returns:

  • (Boolean)


35
36
37
# File 'lib/minting/money/money.rb', line 35

def same_currency?(other)
  other.respond_to?(:currency) && other.currency == currency
end

#split(quantity) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
# File 'lib/minting/money/allocation.rb', line 16

def split(quantity)
  unless quantity.positive? && quantity.integer?
    raise ArgumentError,
          'quantitity must be an integer > 0'
  end

  fraction = self / quantity
  allocation = Array.new(quantity, fraction)
  left_over = self - (fraction * quantity)
  allocate_left_over(allocation, left_over)
end

#to_dObject



6
7
8
# File 'lib/minting/money/conversion.rb', line 6

def to_d
  amount.to_d 0
end

#to_fObject



10
11
12
# File 'lib/minting/money/conversion.rb', line 10

def to_f
  amount.to_f
end

#to_html(format = DEFAULT_FORMAT) ⇒ Object



14
15
16
17
# File 'lib/minting/money/conversion.rb', line 14

def to_html(format = DEFAULT_FORMAT)
  title = Kernel.format("#{currency_code} %0.#{currency.subunit}f", amount)
  %(<data class='money' title='#{title}'>#{to_s(format: format)}</data>)
end

#to_iObject



19
20
21
# File 'lib/minting/money/conversion.rb', line 19

def to_i
  amount.to_i
end

#to_json(*_args) ⇒ Object



23
24
25
26
27
28
29
# File 'lib/minting/money/conversion.rb', line 23

def to_json(*_args)
  subunit = currency.subunit
  Kernel.format(
    %({"currency": "#{currency_code}", "amount": "%0.#{subunit}f"}),
    amount
  )
end

#to_rObject



31
32
33
# File 'lib/minting/money/conversion.rb', line 31

def to_r
  amount
end

#to_s(format: '%<symbol>s%<amount>f', delimiter: false, separator: '.') ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/minting/money/conversion.rb', line 35

def to_s(format: '%<symbol>s%<amount>f', delimiter: false, separator: '.')
  format = format.gsub(/%<amount>(\+?\d*)f/,
                       "%<amount>\\1.#{currency.subunit}f")
  formatted = Kernel.format(format, amount: amount, currency: currency_code,
                                    symbol: currency.symbol)
  if delimiter
    # Thanks Money gem for the regular expression
    formatted.gsub!(/(\d)(?=(?:\d{3})+(?:[^\d]{1}|$))/, "\\1#{delimiter}")
  end
  formatted.tr!('.', separator) if separator != '.'
  formatted
end

#zero?Boolean

Returns:

  • (Boolean)


49
50
51
# File 'lib/minting/money/comparable.rb', line 49

def zero?
  amount.zero?
end