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$ " },
  "ZWD" => { :delimiter => ",", :separator => ".", :symbol => "Z$"},
  "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



91
92
93
94
95
# File 'lib/money/money.rb', line 91

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



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

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



82
83
84
# File 'lib/money/money.rb', line 82

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.



63
64
65
# File 'lib/money/money.rb', line 63

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

.empty(currency = default_currency) ⇒ Object

Create a new money object with value 0.



58
59
60
# File 'lib/money/money.rb', line 58

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.



73
74
75
# File 'lib/money/money.rb', line 73

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.



78
79
80
# File 'lib/money/money.rb', line 78

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.



68
69
70
# File 'lib/money/money.rb', line 68

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

Instance Method Details

#%(fixnum) ⇒ Object



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

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

#*(fixnum) ⇒ Object

multiply money by fixnum



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

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

#+(other_money) ⇒ Object



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

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



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

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

#-@Object



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

def -@
  Money.new(-cents)
end

#/(fixnum) ⇒ Object

divide money by fixnum check out split_in_installments method too



141
142
143
# File 'lib/money/money.rb', line 141

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

#<=>(other_money) ⇒ Object



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

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



98
99
100
101
# File 'lib/money/money.rb', line 98

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



196
197
198
# File 'lib/money/money.rb', line 196

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



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

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.



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

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(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"
Money.new(100, :currency => "GBP").format(:symbol => "UU") => "UU1.00"

:display_free

Money.ca_dollar(0).format => "free"
Money.real(0).format(:display_free => "Gratis") => "Gratis"

:html

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


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
288
# File 'lib/money/money.rb', line 252

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

  curr = CURRENCIES[currency]
  symbol = rules.has_key?(:symbol) ? (rules[:symbol] || "") : (curr ? curr[:symbol] : "$")
  delimiter = (curr ? curr[:delimiter] : "," )
  separator = (curr ? curr[: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 << '<span class="currency">' if rules[:html]
    formatted << currency
    formatted << '</span>' if rules[:html]
  end
  formatted.gsub!(symbol,curr[: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)



218
219
220
# File 'lib/money/money.rb', line 218

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

#normalize_formatting_rules(rules) ⇒ Object



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

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


171
172
173
174
175
# File 'lib/money/money.rb', line 171

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



161
162
163
# File 'lib/money/money.rb', line 161

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)



205
206
207
208
209
210
211
# File 'lib/money/money.rb', line 205

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


180
181
182
183
# File 'lib/money/money.rb', line 180

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



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

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”



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

def to_f
  cents / 100.0
end

#to_moneyObject

Conversation to self



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

def to_money
  self
end

#to_sObject

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



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

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

#zero?Boolean

Test if the money amount is zero

Returns:

  • (Boolean)


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

def zero?
  cents == 0
end