Class: Money

Inherits:
Object
  • Object
show all
Extended by:
Constructors
Includes:
Comparable, Arithmetic
Defined in:
lib/money/money.rb,
lib/money/version.rb,
lib/money/currency.rb,
lib/money/bank/base.rb,
lib/money/currency/loader.rb,
lib/money/money/formatter.rb,
lib/money/money/allocation.rb,
lib/money/money/arithmetic.rb,
lib/money/money/constructors.rb,
lib/money/rates_store/memory.rb,
lib/money/currency/heuristics.rb,
lib/money/bank/single_currency.rb,
lib/money/bank/variable_exchange.rb,
lib/money/money/formatting_rules.rb

Overview

“Money is any object or record that is generally accepted as payment for goods and services and repayment of debts in a given socio-economic context or country.” -Wikipedia

An instance of Money represents an amount of a specific currency.

Money is a value object and should be treated as immutable.

Defined Under Namespace

Modules: Arithmetic, Bank, Constructors, RatesStore Classes: Allocation, Currency, Formatter, FormattingRules, UndefinedSmallestDenomination

Constant Summary

VERSION =
'6.11.3'

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Constructors

ca_dollar, empty, euro, pound_sterling, us_dollar

Methods included from Arithmetic

#%, #*, #+, #-, #-@, #/, #<=>, #==, #abs, #coerce, #div, #divmod, #eql?, #modulo, #negative?, #nonzero?, #positive?, #remainder, #zero?

Constructor Details

#initialize(obj, currency = Money.default_currency, bank = Money.default_bank) ⇒ Money

Creates a new Money object of value given in the fractional unit of the given currency.

Alternatively you can use the convenience methods like Money::Constructors#ca_dollar and Money::Constructors#us_dollar.

Examples:

Money.new(100)        #=> #<Money @fractional=100 @currency="USD">
Money.new(100, "USD") #=> #<Money @fractional=100 @currency="USD">
Money.new(100, "EUR") #=> #<Money @fractional=100 @currency="EUR">

Parameters:

  • obj (Object)

    Either the fractional value of the money, a Money object, or a currency. (If passed a currency as the first argument, a Money will be created in that currency with fractional value

    0.

  • currency (Currency, String, Symbol) (defaults to: Money.default_currency)

    The currency format.

  • bank (Money::Bank::*) (defaults to: Money.default_bank)

    The exchange bank to use.



258
259
260
261
262
263
# File 'lib/money/money.rb', line 258

def initialize(obj, currency = Money.default_currency, bank = Money.default_bank)
  @fractional = obj.respond_to?(:fractional) ? obj.fractional : as_d(obj)
  @currency   = obj.respond_to?(:currency) ? obj.currency : Currency.wrap(currency)
  @currency ||= Money.default_currency
  @bank       = obj.respond_to?(:bank) ? obj.bank : bank
end

Class Attribute Details

.conversion_precisionInteger

Returns Use this to specify precision for converting Rational to BigDecimal

Returns:

  • (Integer)

    Use this to specify precision for converting Rational to BigDecimal



122
123
# File 'lib/money/money.rb', line 122

attr_accessor :default_bank, :default_formatting_rules,
:use_i18n, :infinite_precision, :conversion_precision

.default_bankMoney::Bank::Base

Returns Each Money object is associated to a bank object, which is responsible for currency exchange. This property allows you to specify the default bank object. The default value for this property is an instance of Bank::VariableExchange. It allows one to specify custom exchange rates.

Returns:

  • (Money::Bank::Base)

    Each Money object is associated to a bank object, which is responsible for currency exchange. This property allows you to specify the default bank object. The default value for this property is an instance of Bank::VariableExchange. It allows one to specify custom exchange rates.



122
123
124
# File 'lib/money/money.rb', line 122

def default_bank
  @default_bank
end

.default_currencyMoney::Currency

Returns The default currency, which is used when Money.new is called without an explicit currency argument. The default value is Currency.new(“USD”). The value must be a valid Money::Currency instance.

Returns:

  • (Money::Currency)

    The default currency, which is used when Money.new is called without an explicit currency argument. The default value is Currency.new(“USD”). The value must be a valid Money::Currency instance.



132
# File 'lib/money/money.rb', line 132

attr_writer :rounding_mode, :default_currency

.default_formatting_rulesHash

Returns Use this to define a default hash of rules for every time Money#format is called. Rules provided on method call will be merged with the default ones. To overwrite a rule, just provide the intended value while calling format.

Examples:

Money.default_formatting_rules = { display_free: true }
Money.new(0, "USD").format                          # => "free"
Money.new(0, "USD").format(display_free: false)  # => "$0.00"

Returns:

  • (Hash)

    Use this to define a default hash of rules for every time Money#format is called. Rules provided on method call will be merged with the default ones. To overwrite a rule, just provide the intended value while calling format.

See Also:

  • for more details.


122
123
# File 'lib/money/money.rb', line 122

attr_accessor :default_bank, :default_formatting_rules,
:use_i18n, :infinite_precision, :conversion_precision

.infinite_precisionBoolean

Returns Use this to enable infinite precision cents

Returns:

  • (Boolean)

    Use this to enable infinite precision cents



122
123
# File 'lib/money/money.rb', line 122

attr_accessor :default_bank, :default_formatting_rules,
:use_i18n, :infinite_precision, :conversion_precision

.rounding_mode(mode = nil) ⇒ BigDecimal::ROUND_MODE, Yield

Use this to return the rounding mode. You may also pass a rounding mode and a block to temporarily change it. It will then return the results of the block instead.

Examples:

fee = Money.rounding_mode(BigDecimal::ROUND_HALF_UP) do
  Money.new(1200) * BigDecimal('0.029')
end

Parameters:

  • mode (BigDecimal::ROUND_MODE) (defaults to: nil)

Returns:

  • (BigDecimal::ROUND_MODE, Yield)

    rounding mode or block results



182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/money/money.rb', line 182

def self.rounding_mode(mode=nil)
  if mode.nil?
    Thread.current[:money_rounding_mode] || @rounding_mode
  else
    begin
      Thread.current[:money_rounding_mode] = mode
      yield
    ensure
      Thread.current[:money_rounding_mode] = nil
    end
  end
end

.use_i18nBoolean

Returns Use this to disable i18n even if it's used by other objects in your app.

Returns:

  • (Boolean)

    Use this to disable i18n even if it's used by other objects in your app.



122
123
# File 'lib/money/money.rb', line 122

attr_accessor :default_bank, :default_formatting_rules,
:use_i18n, :infinite_precision, :conversion_precision

Instance Attribute Details

#bankObject (readonly)

Returns the value of attribute bank



87
# File 'lib/money/money.rb', line 87

attr_reader :currency, :bank

#currencyCurrency (readonly)

Returns The money's currency.

Returns:



87
88
89
# File 'lib/money/money.rb', line 87

def currency
  @currency
end

Class Method Details

.add_rate(from_currency, to_currency, rate) ⇒ Numeric

Adds a new exchange rate to the default bank and return the rate.

Examples:

Money.add_rate("USD", "CAD", 1.25) #=> 1.25

Parameters:

  • from_currency (Currency, String, Symbol)

    Currency to exchange from.

  • to_currency (Currency, String, Symbol)

    Currency to exchange to.

  • rate (Numeric)

    Rate to exchange with.

Returns:

  • (Numeric)


206
207
208
# File 'lib/money/money.rb', line 206

def self.add_rate(from_currency, to_currency, rate)
  Money.default_bank.add_rate(from_currency, to_currency, rate)
end

.disallow_currency_conversion!Object

Sets the default bank to be a SingleCurrency bank that raises on currency exchange. Useful when apps operate in a single currency at a time.



212
213
214
# File 'lib/money/money.rb', line 212

def self.disallow_currency_conversion!
  self.default_bank = Bank::SingleCurrency.instance
end

.from_amount(amount, currency = default_currency, bank = default_bank) ⇒ Money

Creates a new Money object of value given in the unit of the given currency.

Examples:

Money.from_amount(23.45, "USD") # => #<Money fractional:2345 currency:USD>
Money.from_amount(23.45, "JPY") # => #<Money fractional:23 currency:JPY>

Parameters:

  • amount (Numeric)

    The numerical value of the money.

  • currency (Currency, String, Symbol) (defaults to: default_currency)

    The currency format.

  • bank (Money::Bank::*) (defaults to: default_bank)

    The exchange bank to use.

Returns:

See Also:



230
231
232
233
234
235
236
# File 'lib/money/money.rb', line 230

def self.from_amount(amount, currency = default_currency, bank = default_bank)
  Numeric === amount or raise ArgumentError, "'amount' must be numeric"
  currency = Currency.wrap(currency) || Money.default_currency
  value = amount.to_d * currency.subunit_to_unit
  value = value.round(0, rounding_mode) unless infinite_precision
  new(value, currency, bank)
end

.inherited(base) ⇒ Object



164
165
166
# File 'lib/money/money.rb', line 164

def self.inherited(base)
  base.setup_defaults
end

.setup_defaultsObject



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/money/money.rb', line 144

def self.setup_defaults
  # Set the default bank for creating new +Money+ objects.
  self.default_bank = Bank::VariableExchange.instance

  # Set the default currency for creating new +Money+ object.
  self.default_currency = Currency.new("USD")

  # Default to using i18n
  self.use_i18n = true

  # Default to not using infinite precision cents
  self.infinite_precision = false

  # Default to bankers rounding
  self.rounding_mode = BigDecimal::ROUND_HALF_EVEN

  # Default the conversion of Rationals precision to 16
  self.conversion_precision = 16
end

Instance Method Details

#allocate(parts) ⇒ Array<Money> Also known as: split

Splits a given amount in parts without loosing pennies. The left-over pennies will be distributed round-robin amongst the parties. This means that parties listed first will likely receive more pennies than ones that are listed later.

party3 which results in 50% of the cash to party1, 25% to party2, and 25% to party3. Passing a number instead of an array will split the amount evenly (without loosing pennies when rounding).

Examples:

Money.new(5,   "USD").allocate([3, 7]) #=> [Money.new(2), Money.new(3)]
Money.new(100, "USD").allocate([1, 1, 1]) #=> [Money.new(34), Money.new(33), Money.new(33)]
Money.new(100, "USD").allocate(2) #=> [Money.new(50), Money.new(50)]
Money.new(100, "USD").allocate(3) #=> [Money.new(34), Money.new(33), Money.new(33)]

Parameters:

  • pass (Array<Numeric>, Numeric)
    2, 1, 1

    to give twice as much to party1 as party2 or

Returns:



483
484
485
486
# File 'lib/money/money.rb', line 483

def allocate(parts)
  amounts = Money::Allocation.generate(fractional, parts, !Money.infinite_precision)
  amounts.map { |amount| self.class.new(amount, currency) }
end

#amountBigDecimal

Returns the numerical value of the money

Examples:

Money.new(1_00, "USD").amount    # => BigDecimal("1.00")

Returns:

  • (BigDecimal)

See Also:



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

def amount
  to_d
end

#as_ca_dollarMoney

Receive a money object with the same amount as the current Money object in Canadian dollar.

Examples:

n = Money.new(100, "USD").as_ca_dollar
n.currency #=> #<Money::Currency id: cad>

Returns:



451
452
453
# File 'lib/money/money.rb', line 451

def as_ca_dollar
  exchange_to("CAD")
end

#as_euroMoney

Receive a money object with the same amount as the current Money object in euro.

Examples:

n = Money.new(100, "USD").as_euro
n.currency #=> #<Money::Currency id: eur>

Returns:



463
464
465
# File 'lib/money/money.rb', line 463

def as_euro
  exchange_to("EUR")
end

#as_us_dollarMoney

Receive a money object with the same amount as the current Money object in United States dollar.

Examples:

n = Money.new(100, "CAD").as_us_dollar
n.currency #=> #<Money::Currency id: usd>

Returns:



439
440
441
# File 'lib/money/money.rb', line 439

def as_us_dollar
  exchange_to("USD")
end

#centsInteger, BigDecimal

Convenience method for fractional part of the amount. Synonym of #fractional

Returns:

  • (Integer)

    when infinite_precision is false

  • (BigDecimal)

    when infinite_precision is true

See Also:



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

def cents
  fractional
end

#currency_as_stringString

Return string representation of currency object

Examples:

Money.new(100, :USD).currency_as_string #=> "USD"

Returns:

  • (String)


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

def currency_as_string
  currency.to_s
end

#currency_as_string=(val) ⇒ Money::Currency

Set currency object using a string

Examples:

Money.new(100).currency_as_string("CAD") #=> #<Money::Currency id: cad>

Parameters:

  • val (String)

    The currency string.

Returns:



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

def currency_as_string=(val)
  @currency = Currency.wrap(val)
end

#decimal_markString

Returns a decimal mark according to the locale

Returns:

  • (String)


534
535
536
# File 'lib/money/money.rb', line 534

def decimal_mark
  Money::Formatter.new(self, {}).decimal_mark
end

#dollarsBigDecimal

Assuming using a currency using dollars: Returns the value of the money in dollars, instead of in the fractional unit cents.

Synonym of #amount

Examples:

Money.new(1_00, "USD").dollars   # => BigDecimal("1.00")

Returns:

  • (BigDecimal)

See Also:



280
281
282
# File 'lib/money/money.rb', line 280

def dollars
  amount
end

#exchange_to(other_currency) {|n| ... } ⇒ Money

Receive the amount of this money object in another Currency.

Examples:

Money.new(2000, "USD").exchange_to("EUR")
Money.new(2000, "USD").exchange_to("EUR") {|x| x.round}
Money.new(2000, "USD").exchange_to(Currency.new("EUR"))

Parameters:

  • other_currency (Currency, String, Symbol)

    Currency to exchange to.

Yields:

  • (n)

    Optional block to use when rounding after exchanging one currency for another.

Yield Parameters:

  • n (Float)

    The resulting float after exchanging one currency for another.

Yield Returns:

  • (Integer)

Returns:



422
423
424
425
426
427
428
429
# File 'lib/money/money.rb', line 422

def exchange_to(other_currency, &rounding_method)
  other_currency = Currency.wrap(other_currency)
  if self.currency == other_currency
    self
  else
    @bank.exchange_with(self, other_currency, &rounding_method)
  end
end

#format(*rules) ⇒ String

Creates a formatted price string according to several rules.

Parameters:

  • See (Hash)

    Money::Formatter for the list of formatting options

Returns:

  • (String)


518
519
520
# File 'lib/money/money.rb', line 518

def format(*rules)
  Money::Formatter.new(self, *rules).to_s
end

#fractionalInteger, BigDecimal

The value of the monetary amount represented in the fractional or subunit of the currency.

For example, in the US dollar currency the fractional unit is cents, and there are 100 cents in one US dollar. So given the Money representation of one US dollar, the fractional interpretation is 100.

Another example is that of the Kuwaiti dinar. In this case the fractional unit is the fils and there 1000 fils to one Kuwaiti dinar. So given the Money representation of one Kuwaiti dinar, the fractional interpretation is 1000.

Returns:

  • (Integer)

    when infinite_precision is false

  • (BigDecimal)

    when infinite_precision is true

See Also:



52
53
54
55
56
57
58
# File 'lib/money/money.rb', line 52

def fractional
  # Ensure we have a BigDecimal. If the Money object is created
  # from YAML, @fractional can end up being set to a Float.
  fractional = as_d(@fractional)

  return_value(fractional)
end

#hashInteger

Returns a Integer hash value based on the fractional and currency attributes in order to use functions like & (intersection), group_by, etc.

Examples:

Money.new(100).hash #=> 908351

Returns:

  • (Integer)


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

def hash
  [fractional.hash, currency.hash].hash
end

#inspectString

Common inspect function

Returns:

  • (String)


344
345
346
# File 'lib/money/money.rb', line 344

def inspect
  "#<#{self.class.name} fractional:#{fractional} currency:#{currency}>"
end

#round(rounding_mode = self.class.rounding_mode, rounding_precision = 0) ⇒ Money

Note:

This method is only useful when operating with infinite_precision turned on. Without infinite_precision values are rounded to the smallest unit of coinage automatically.

Round the monetary amount to smallest unit of coinage.

Examples:

Money.new(10.1, 'USD').round #=> Money.new(10, 'USD')

Returns:

See Also:



504
505
506
507
508
509
510
# File 'lib/money/money.rb', line 504

def round(rounding_mode = self.class.rounding_mode, rounding_precision = 0)
  if self.class.infinite_precision
    self.class.new(fractional.round(rounding_precision, rounding_mode), self.currency)
  else
    self
  end
end

#round_to_nearest_cash_valueInteger, BigDecimal

Round a given amount of money to the nearest possible amount in cash value. For example, in Swiss franc (CHF), the smallest possible amount of cash value is CHF 0.05. Therefore, this method rounds CHF 0.07 to CHF 0.05, and CHF 0.08 to CHF 0.10.

Returns:

  • (Integer)

    when infinite_precision is false

  • (BigDecimal)

    when infinite_precision is true

See Also:



69
70
71
72
73
74
75
76
77
78
79
# File 'lib/money/money.rb', line 69

def round_to_nearest_cash_value
  unless self.currency.smallest_denomination
    raise UndefinedSmallestDenomination, 'Smallest denomination of this currency is not defined'
  end

  fractional = as_d(@fractional)
  smallest_denomination = as_d(self.currency.smallest_denomination)
  rounded_value = (fractional / smallest_denomination).round(0, self.class.rounding_mode) * smallest_denomination

  return_value(rounded_value)
end

#symbolString

Uses Currency#symbol. If nil is returned, defaults to “¤”.

Examples:

Money.new(100, "USD").symbol #=> "$"

Returns:

  • (String)


337
338
339
# File 'lib/money/money.rb', line 337

def symbol
  currency.symbol || "¤"
end

#thousands_separatorString

Returns a thousands separator according to the locale

Returns:

  • (String)


526
527
528
# File 'lib/money/money.rb', line 526

def thousands_separator
  Money::Formatter.new(self, {}).thousands_separator
end

#to_dBigDecimal

Return the amount of money as a BigDecimal.

Examples:

Money.us_dollar(1_00).to_d #=> BigDecimal("1.00")

Returns:

  • (BigDecimal)


367
368
369
# File 'lib/money/money.rb', line 367

def to_d
  as_d(fractional) / as_d(currency.subunit_to_unit)
end

#to_fFloat

Return the amount of money as a float. Floating points cannot guarantee precision. Therefore, this function should only be used when you no longer need to represent currency or working with another system that requires floats.

Examples:

Money.us_dollar(100).to_f #=> 1.0

Returns:

  • (Float)


390
391
392
# File 'lib/money/money.rb', line 390

def to_f
  to_d.to_f
end

#to_iInteger

Return the amount of money as a Integer.

Examples:

Money.us_dollar(1_00).to_i #=> 1

Returns:

  • (Integer)


377
378
379
# File 'lib/money/money.rb', line 377

def to_i
  to_d.to_i
end

#to_money(given_currency = nil) ⇒ self

Conversation to self.

Returns:

  • (self)


397
398
399
400
401
402
403
404
# File 'lib/money/money.rb', line 397

def to_money(given_currency = nil)
  given_currency = Currency.wrap(given_currency)
  if given_currency.nil? || self.currency == given_currency
    self
  else
    exchange_to(given_currency)
  end
end

#to_sString

Returns the amount of money as a string.

Examples:

Money.ca_dollar(100).to_s #=> "1.00"

Returns:

  • (String)


354
355
356
357
358
359
# File 'lib/money/money.rb', line 354

def to_s
  format thousands_separator: '',
         no_cents_if_whole: currency.decimal_places == 0,
         symbol: false,
         ignore_defaults: true
end