Class: Money

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/money/money.rb,
lib/money/errors.rb,
lib/money/exchange_bank.rb

Overview

bank.exchange(100_00, “USD”, “CAD”) # => 6450

Defined Under Namespace

Classes: ExchangeBank, UnknownRate

Constant Summary collapse

CURRENCIES =
{
  "USD" => { :delimiter => ",", :separator => ".", :symbol => "$" },
  "CAD" => { :delimiter => ",", :separator => ".", :symbol => "$" },
  "HKD" => { :delimiter => ",", :separator => ".", :symbol => "$" },
  "SGD" => { :delimiter => ",", :separator => ".", :symbol => "$" },
  "BRL" => { :delimiter => ".", :separator => ",", :symbol => "R$" },
  "EUR" => { :delimiter => ",", :separator => ".", :symbol => '€', :html => '€' },
  "GBP" => { :delimiter => ",", :separator => ".", :symbol => '£', :html => '£' },
  "JPY" => { :delimiter => ".", :separator => ".", :symbol => '¥', :html => '¥' },
}

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(cents, currency = nil, bank = nil) ⇒ Money

Creates a new money object.

Money.new(100)

Alternativly you can use the convinience methods like Money.ca_dollar and Money.us_dollar



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

def initialize(cents, currency = nil, bank = nil)
  @cents = cents.to_i
  @currency = (currency || Money.default_currency).upcase
  @bank = bank || Money.default_bank
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(m, *x) ⇒ Object



322
323
324
325
326
327
328
# File 'lib/money/money.rb', line 322

def method_missing(m,*x)
  if m.to_s =~ /^as/
    exchange_to(m.to_s.split("_").last.upcase)
  else
    super
  end
end

Class Attribute Details

.default_bankObject

Each Money object is associated to a bank object, which is responsible for currency exchange. This property allows one to specify the default bank object.

bank1 = MyBank.new
bank2 = MyOtherBank.new

Money.default_bank = bank1
money1 = Money.new(10)
money1.bank  # => bank1

Money.default_bank = bank2
money2 = Money.new(10)
money2.bank  # => bank2
money1.bank  # => bank1

The default value for this property is an instance if VariableExchangeBank. It allows one to specify custom exchange rates:

Money.default_bank.add_rate("USD", "CAD", 1.24515)
Money.default_bank.add_rate("CAD", "USD", 0.803115)
Money.us_dollar(100).exchange_to("CAD")  # => Money.ca_dollar(124)
Money.ca_dollar(100).exchange_to("USD")  # => Money.us_dollar(80)


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

def default_bank
  @default_bank
end

.default_currencyObject

the default currency, which is used when Money.new is called without an explicit currency argument. The default value is “USD”.



38
39
40
# File 'lib/money/money.rb', line 38

def default_currency
  @default_currency
end

Instance Attribute Details

#bankObject (readonly)

Returns the value of attribute bank.



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

def bank
  @bank
end

#centsObject (readonly) Also known as: to_i

Returns the value of attribute cents.



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

def cents
  @cents
end

#currencyObject (readonly)

Returns the value of attribute currency.



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

def currency
  @currency
end

Class Method Details

.add_rate(*params) ⇒ Object



80
81
82
# File 'lib/money/money.rb', line 80

def self.add_rate(*params)
  Money.default_bank.add_rate(*params)
end

.ca_dollar(cents) ⇒ Object

Creates a new Money object of the given value, using the Canadian dollar currency.



61
62
63
# File 'lib/money/money.rb', line 61

def self.ca_dollar(cents)
  Money.new(cents, "CAD")
end

.empty(currency = default_currency) ⇒ Object

Create a new money object with value 0.



56
57
58
# File 'lib/money/money.rb', line 56

def self.empty(currency = default_currency)
  Money.new(0, currency)
end

.euro(cents) ⇒ Object

Creates a new Money object of the given value, using the Euro currency.



71
72
73
# File 'lib/money/money.rb', line 71

def self.euro(cents)
  Money.new(cents, "EUR")
end

.real(cents) ⇒ Object

Creates a new Money object of the given value, using the Brazilian Real currency.



76
77
78
# File 'lib/money/money.rb', line 76

def self.real(cents)
  Money.new(cents, "BRL")
end

.us_dollar(cents) ⇒ Object

Creates a new Money object of the given value, using the American dollar currency.



66
67
68
# File 'lib/money/money.rb', line 66

def self.us_dollar(cents)
  Money.new(cents, "USD")
end

Instance Method Details

#%(fixnum) ⇒ Object



139
140
141
# File 'lib/money/money.rb', line 139

def %(fixnum)
  Money.new(cents % fixnum, currency)
end

#*(fixnum) ⇒ Object

multiply money by fixnum



129
130
131
# File 'lib/money/money.rb', line 129

def *(fixnum)
  Money.new(cents * fixnum, currency)
end

#+(other_money) ⇒ Object



110
111
112
113
114
115
116
117
# File 'lib/money/money.rb', line 110

def +(other_money)
  other_money = Money.new(other_money) unless other_money.is_a? Money
  if currency == other_money.currency
    Money.new(cents + other_money.cents, other_money.currency)
  else
    Money.new(cents + other_money.exchange_to(currency).cents,currency)
  end
end

#-(other_money) ⇒ Object



119
120
121
122
123
124
125
126
# File 'lib/money/money.rb', line 119

def -(other_money)
  other_money = Money.new(other_money) unless other_money.is_a? Money
  if currency == other_money.currency
    Money.new(cents - other_money.cents, other_money.currency)
  else
    Money.new(cents - other_money.exchange_to(currency).cents, currency)
  end
end

#/(fixnum) ⇒ Object

divide money by fixnum check out split_in_installments method too



135
136
137
# File 'lib/money/money.rb', line 135

def /(fixnum)
  Money.new(cents / fixnum, currency)
end

#<=>(other_money) ⇒ Object



101
102
103
104
105
106
107
108
# File 'lib/money/money.rb', line 101

def <=>(other_money)
  other_money = Money.new(other_money) unless other_money.is_a? Money
  if bank.same_currency?(currency, other_money.currency)
    cents <=> other_money.cents
  else
    cents <=> other_money.exchange_to(currency).cents
  end
end

#==(other_money) ⇒ Object

Do two money objects equal? Only works if both objects are of the same currency



96
97
98
99
# File 'lib/money/money.rb', line 96

def ==(other_money)
  other_money.respond_to?(:cents) && cents == other_money.cents &&
    other_money.respond_to?(:currency) && bank.same_currency?(currency, other_money.currency)
end

#add_tax(tax) ⇒ Object

Just a helper if you got tax inputs in percentage. Ie. add_tax(20) => cents * 1.20



190
191
192
# File 'lib/money/money.rb', line 190

def add_tax(tax)
  tax_breakdown(tax)[0]
end

#compound_interest(rate, count = 1, period = 12) ⇒ Object

Calculates compound interest Returns a money object with the sum of self + it



150
151
152
# File 'lib/money/money.rb', line 150

def compound_interest(rate, count = 1, period = 12)
  Money.new(cents * ((1 + rate / 100.0 / period) ** count - 1))
end

#exchange_to(other_currency) ⇒ Object

Recieve the amount of this money object in another currency.



313
314
315
# File 'lib/money/money.rb', line 313

def exchange_to(other_currency)
  Money.new(@bank.exchange(self.cents, currency, other_currency), other_currency)
end

#format(*rules) ⇒ Object

Format the price according to several rules Currently supported are :with_currency, :no_cents, :symbol and :html

with_currency:

Money.ca_dollar(0).format => "free"
Money.ca_dollar(100).format => "$1.00"
Money.ca_dollar(100).format(:with_currency => true) => "$1.00 CAD"
Money.us_dollar(85).format(:with_currency => true) => "$0.85 USD"

no_cents:

Money.ca_dollar(100).format(:no_cents) => "$1"
Money.ca_dollar(599).format(:no_cents) => "$5"

Money.ca_dollar(570).format(:no_cents, :with_currency) => "$5 CAD"
Money.ca_dollar(39000).format(:no_cents) => "$390"

symbol:

Money.new(100, :currency => "GBP").format(:symbol => "£") => "£1.00"

html:

Money.ca_dollar(570).format(:html => true, :with_currency => true) =>  "$5.70 <span class=\"currency\">CAD</span>"


241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/money/money.rb', line 241

def format(*rules)
 # support for old format parameters
 rules = normalize_formatting_rules(rules)

 if cents == 0
   if rules[:display_free].respond_to?(:to_str)
     return rules[:display_free]
   elsif rules[:display_free]
     return "free"
   end
 end

 if rules.has_key?(:symbol)
   if rules[:symbol]
     symbol = rules[:symbol]
   else
     symbol = ""
   end
 else
   symbol = (CURRENCIES[currency] ? CURRENCIES[currency][:symbol] : "$")
 end
 self.currency

 delimiter = (CURRENCIES[currency] ? CURRENCIES[currency][:delimiter] : "," )
 separator = (CURRENCIES[currency] ? CURRENCIES[currency][:separator] : "." )

 if rules[:no_cents]
   formatted = sprintf("#{symbol}%d", cents.to_f / 100)
   formatted.gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
 else
   formatted = sprintf("#{symbol}%.2f", cents.to_f / 100).split('.')
   formatted[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
   formatted = formatted.join(separator)
 end

 # Commify ("10000" => "10,000")
 formatted.gsub!(/(\d)(?=\d{3}+(?:\.|$))(\d{3}\..*)?/,'\1,\2')

 if rules[:with_currency]
   formatted << " "
   formatted << '<span class="currency">' if rules[:html]
   formatted << currency
   formatted << '</span>' if rules[:html]
 end
 formatted.gsub!(symbol,CURRENCIES[currency][:html]) if rules[:html]
 formatted
end

#in_installments_of(other_money, order = false) ⇒ Object

Split money in installments based on payment value

Money.new(1000_00).split_in_installments(Money.new(300_00))

> [ 334_00, 333_00, 333_00 ] (All Money instances)



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

def in_installments_of(other_money, order=false)
  split_in_installments(cents/other_money.cents, order)
end

#normalize_formatting_rules(rules) ⇒ Object



289
290
291
292
293
294
295
296
297
298
299
300
# File 'lib/money/money.rb', line 289

def normalize_formatting_rules(rules)
  if rules.size == 1
    rules = rules.pop
    rules = { rules => true } if rules.is_a?(Symbol)
  else
    rules = rules.inject({}) do |h,s|
      h[s] = true
      h
    end
  end
  rules
end

#round_to_coin(coin) ⇒ Object

Round to nearest coin value basically, we don’t have coins for cents in CZK, our smallest fraction is 0.50CZK

Money.new(14_58).round_to_coin(50) => 14.50


165
166
167
168
169
# File 'lib/money/money.rb', line 165

def round_to_coin(coin)
  coef = 1.0/coin
  val = (cents * coef).floor / coef
  Money.new(val, currency)
end

#simple_interest(rate, count = 1, period = 12) ⇒ Object

Calculate self + simple interest



155
156
157
# File 'lib/money/money.rb', line 155

def simple_interest(rate, count = 1, period = 12)
  Money.new(rate / 100 / period * cents * count)
end

#split_in_installments(fixnum, order = false) ⇒ Object

Split money in number of installments

Money.new(10_00).split_in_installments(3)

> [ 3.34, 3.33, 3.33 ] (All Money instances)



199
200
201
202
203
204
205
# File 'lib/money/money.rb', line 199

def split_in_installments(fixnum, order=false)
  wallet = Wallet.new(fixnum, Money.new(cents/fixnum,currency))
  to_add = cents % fixnum
  to_add.times { |m| wallet[m] += Money.new(1) }
  wallet.reverse! if order
  wallet
end

#tax_breakdown(tax) ⇒ Object

Returns array a where

a[0] is price _after_ applying tax (tax base)
a[1] is tax


174
175
176
177
# File 'lib/money/money.rb', line 174

def tax_breakdown(tax)
  _tax = (cents * (tax / 100.0)).round
  [Money.new(cents + _tax, currency), Money.new(_tax, currency)]
end

#tax_reverse_breakdown(tax) ⇒ Object

Returns array a where a is price before applying tax (tax base) a is tax



182
183
184
185
186
# File 'lib/money/money.rb', line 182

def tax_reverse_breakdown(tax)
  coef = tax/100.0
  [Money.new((cents / (1+coef)).round, currency),
   Money.new((cents*coef/(1+coef)).round, currency) ]
end

#to_fObject

Money.ca_dollar(100).to_f => “1.0”



308
309
310
# File 'lib/money/money.rb', line 308

def to_f
  cents / 100.0
end

#to_moneyObject

Conversation to self



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

def to_money
  self
end

#to_sObject

Money.ca_dollar(100).to_s => “1.00”



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

def to_s
  sprintf("%.2f", cents / 100.0)
end

#zero?Boolean

Test if the money amount is zero

Returns:

  • (Boolean)


144
145
146
# File 'lib/money/money.rb', line 144

def zero?
  cents == 0
end