Class: MoreMoney::Money

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/more_money/more_money.rb

Constant Summary collapse

CURRENCIES =
{}
DEFAULT_FORMATS =
{}
EXCHANGE_RATES =
{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(cents, currency = Money.default_currency) ⇒ Money

Creates a new money object.

Money.new(100)


131
132
133
134
135
# File 'lib/more_money/more_money.rb', line 131

def initialize(cents, currency = Money.default_currency)
  self.class.check_currency(currency)
  @currency = currency
  @cents = cents.nil? ? nil : cents.round
end

Instance Attribute Details

#currencyObject (readonly)

Returns the value of attribute currency.



11
12
13
# File 'lib/more_money/more_money.rb', line 11

def currency
  @currency
end

Class Method Details

.add_currency(currency_hash) ⇒ Object

adds a currency to the set of available ones.

MoreMoney::Money.add_currency({:code => 'USD', :symbol => '$', :description => 'us_dollar'})

the line above will add the US dollar currency, the description will be used to create the method MoreMoney::Money.us_dollar(cents) which can be used to instantiate new Money object with USD as a currency

2 optional parameters can be specified: :format, :format_defaults

:format option can be specified to control the formatting method for the specific currency the :format parameter will be called passing 4 arguments:

cents, currency, currency symbol, rules

:format_defaults need to be an hash with the cents value as keys and the custom string format to use

MoreMoney::Money.add_currency({:code => 'USD', :symbol => '$', :description => 'us_dollar'})

MoreMoney::Money.new(0, 'USD').format

=> '$ 0.00'

MoreMoney::Money.add_currency({:code => 'USD', :symbol => '$', :description => 'us_dollar', :format_defaults => { 0 => 'free' }})

MoreMoney::Money.new(0, 'USD').format

=> 'free'


89
90
91
92
93
94
95
96
97
98
99
# File 'lib/more_money/more_money.rb', line 89

def self.add_currency(currency_hash)
  code = currency_hash.delete(:code)
  CURRENCIES[code]= currency_hash
  if currency_hash[:description]
    (class << self; self; end).module_eval do
      define_method(currency_hash[:description]) do |cents|
        Money.new(cents, code) 
      end
    end
  end
end

.check_currency(currency) ⇒ Object



112
113
114
# File 'lib/more_money/more_money.rb', line 112

def self.check_currency(currency)
  raise MoneyInvalidCurrency, "#{currency} is not defined as a currency" unless CURRENCIES.key?(currency)
end

.curr_symbol(currency = Money.default_currency) ⇒ Object

returns the symbol for the given currency code

MoreMoney::Money.curr_symbol('USD')

=> '$'


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

def self.curr_symbol(currency = Money.default_currency)
  check_currency(currency)
  CURRENCIES[currency][:symbol].dup
end

.default_currencyObject

the current default currency



20
21
22
# File 'lib/more_money/more_money.rb', line 20

def self.default_currency
  @default_currency
end

.default_currency=(currency) ⇒ Object

set the default currency

MoreMoney::Money.default_currency = 'GBP'


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

def self.default_currency=(currency)
  @default_currency = currency
end

.empty(currency = default_currency) ⇒ Object

Create a new money object with value 0



279
280
281
# File 'lib/more_money/more_money.rb', line 279

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

.get_exchange_rate(starting_currency, destination_currency) ⇒ Object

returns the exchange rate from the first currency to the second one

MoreMoney::Money.get_exchange_rate(starting_currency, destination_currency)


54
55
56
57
# File 'lib/more_money/more_money.rb', line 54

def self.get_exchange_rate(starting_currency, destination_currency)
  rate = EXCHANGE_RATES[[starting_currency, destination_currency]]
  return rate.respond_to?(:call) ? rate.call : rate
end

.load_std_currenciesObject

loads some currencies, see the code to know which one



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

def self.load_std_currencies
  add_currency({:code => 'USD', :symbol => '$', :description => 'us_dollar'})
  add_currency({:code => 'GBP', :symbol => '£', :description => 'gb_pound'})
  add_currency({:code => 'EUR', :symbol => '€', :description => 'euro'})
  add_currency({:code => 'AUD', :symbol => '$', :description => 'au_dollar'})
  add_currency({:code => 'CAD', :symbol => '$', :description => 'ca_dollar'})
  add_currency({:code => 'CHF', :symbol => 'CHF', :description => 'ch_franc'})
  add_currency({:code => 'JPY', :symbol => '¥', :description => 'jp_yen'})
end

.set_default_format(cents, default_format) ⇒ Object

set a formatting default which will be used for any currency which has no formatting defaults otherwise specified

MoreMoney::Money.set_default_format(0, 'free')


46
47
48
# File 'lib/more_money/more_money.rb', line 46

def self.set_default_format(cents, default_format)
  DEFAULT_FORMATS[cents] = default_format
end

.set_exchange_rate(starting_currency, destination_currency, rate) ⇒ Object

set the exchange rate from a currency to anothe one

MoreMoney::Money.set_exchange_rate('USD', 'GBP', 0.51)

the rate can be specified as a callable object which will be called at the moment of the conversion



37
38
39
# File 'lib/more_money/more_money.rb', line 37

def self.set_exchange_rate(starting_currency, destination_currency, rate)
  EXCHANGE_RATES[[starting_currency, destination_currency]] = rate
end

Instance Method Details

#*(fixnum) ⇒ Object

multiply money by fixnum



181
182
183
184
# File 'lib/more_money/more_money.rb', line 181

def *(fixnum)
  return self.dup if self.cents.nil?
  Money.new(cents * fixnum, currency)
end

#+(other_money) ⇒ Object

sums two money objects



155
156
157
158
159
160
161
162
163
164
# File 'lib/more_money/more_money.rb', line 155

def +(other_money)
  return other_money.dup if cents.nil? || cents.zero?
  return dup if other_money.cents.nil? || other_money.cents.zero?
  
  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

subtracts a money object from another one



167
168
169
170
171
172
173
174
175
176
177
# File 'lib/more_money/more_money.rb', line 167

def -(other_money)

  return Money.new(0 - other_money.cents, other_money.currency) if self.cents.nil? || self.cents.zero?
  return self.dup if other_money.cents.nil? || other_money.cents.zero?
  
  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



187
188
189
190
# File 'lib/more_money/more_money.rb', line 187

def /(fixnum)
  return self.dup if self.cents.nil?
  Money.new(cents / fixnum, currency)
end

#<=>(other_money) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
# File 'lib/more_money/more_money.rb', line 142

def <=>(other_money)
  if cents == nil
    return 0 if other_money.cents == nil
    return -1
  elsif currency == other_money.currency
    return 1 if other_money.cents == nil
    cents <=> other_money.cents
  else
    cents <=> other_money.exchange_to(currency).cents
  end
end

#centsObject

get the cents value of the object



199
200
201
# File 'lib/more_money/more_money.rb', line 199

def cents
  @cents.nil? ? nil : @cents.to_i
end

#eql?(other_money) ⇒ Boolean

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

Returns:

  • (Boolean)


138
139
140
# File 'lib/more_money/more_money.rb', line 138

def eql?(other_money)
  cents == other_money.cents && currency == other_money.currency
end

#exchange_to(other_currency) ⇒ Object

Recieve the amount of this money object in another currency



272
273
274
275
276
# File 'lib/more_money/more_money.rb', line 272

def exchange_to(other_currency)
  return self if other_currency == currency
  raise MoneyMissingExchangeRate if Money.get_exchange_rate(currency, other_currency).nil?
  Money.new(cents * Money.get_exchange_rate(currency, other_currency), other_currency)
end

#format(*rules) ⇒ Object

Format the price according rules Currently supported are :with_currency, :with_thousands, :no_cents and :html

with_currency:

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

with_thousands:

Money.us_dollar(100000).format() => "$ 1000.00"
Money.us_dollar(100000).format(:with_thousands) => "$ 1,000.00"

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"

html:

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


228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/more_money/more_money.rb', line 228

def format(*rules)
  return CURRENCIES[currency][:format_defaults][cents] if CURRENCIES[currency][:format_defaults] && CURRENCIES[currency][:format_defaults][cents]
  rules = rules.flatten
  return CURRENCIES[currency][:format].call(cents, currency, CURRENCIES[currency][:symbol], rules) if CURRENCIES[currency][:format]
  return DEFAULT_FORMATS[cents] if DEFAULT_FORMATS[cents]
  return '' if cents.nil?


  if rules.include?(:no_cents)
    formatted = sprintf("%d", cents.to_f / 100  )          
  else
    formatted = sprintf("%.2f", cents.to_f / 100  )      
  end
  
  if rules.include?(:with_thousands)
    formatted = formatted.reverse!.split('')
    newstr = []
    3.times { newstr << formatted.shift } unless rules.include?(:no_cents)
    formatted.each_with_index do |num, index|
      newstr << ',' if index !=0 && num != '-' && index % 3 == 0
      newstr << num
    end
    formatted = newstr.to_s.reverse!
  end

  #if rules.include?(:with_symbol)
  formatted = "#{CURRENCIES[currency][:symbol]} #{formatted}"
  #end
 
  if rules.include?(:with_currency)
    formatted << " "
    formatted << '<span class="currency">' if rules.include?(:html)
    formatted << currency
    formatted << '</span>' if rules.include?(:html)
  end
  formatted
end

#to_moneyObject

Conversation to self



283
284
285
# File 'lib/more_money/more_money.rb', line 283

def to_money
  self
end

#to_sObject

Money.new(100, ‘USD’).to_s => “1.00”



267
268
269
# File 'lib/more_money/more_money.rb', line 267

def to_s
  cents.nil? ? '' : sprintf("%.2f", cents.to_f / 100  )
end

#zero?Boolean

Test if the money amount is zero

Returns:

  • (Boolean)


193
194
195
196
# File 'lib/more_money/more_money.rb', line 193

def zero?
  return false if cents.nil?
  cents == 0
end