Class: Money

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

Overview

Usage with ActiveRecord

Use the compose_of helper to let active record deal with embedding the money object in your models. The following example requires a cents and a currency field.

class ProductUnit < ActiveRecord::Base
  belongs_to :product
  composed_of :price, :class_name => "Money", :mapping => [ %w(cents cents), %w(currency currency) ]

  private        
    validate :cents_not_zero

    def cents_not_zero
      errors.add("cents", "cannot be zero or less") unless cents > 0
    end

    validates_presence_of :sku, :currency
    validates_uniqueness_of :sku        
end

Defined Under Namespace

Classes: MoneyError

Constant Summary collapse

@@bank =

Bank lets you exchange the object which is responsible for currency exchange. The default implementation just throws an exception. However money ships with a variable exchange bank implementation which supports custom excahnge rates:

Money.bank = VariableExchangeBank.new
Money.bank.add_rate("USD", "CAD", 1.24515)
Money.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)
NoExchangeBank.new
@@default_currency =
"USD"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(cents, currency = default_currency, precision = 2) ⇒ Money

Creates a new money object.

Money.new(100)

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



51
52
53
# File 'lib/money/money.rb', line 51

def initialize(cents, currency = default_currency, precision = 2)
  @cents, @currency, @precision = cents.round, currency, precision
end

Instance Attribute Details

#centsObject (readonly)

get the cents value of the object



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

def cents
  @cents
end

#currencyObject (readonly)

Returns the value of attribute currency.



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

def currency
  @currency
end

#precisionObject (readonly)

Returns the value of attribute precision.



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

def precision
  @precision
end

Class Method Details

.ca_dollar(num) ⇒ Object

Create a new money object using the Canadian dollar currency



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

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

.empty(currency = default_currency) ⇒ Object

Create a new money object with value 0



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

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

.euro(num) ⇒ Object

Create a new money object using the Euro currency



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

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

.us_dollar(num) ⇒ Object

Create a new money object using the American dollar currency



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

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

Instance Method Details

#*(fixnum) ⇒ Object

multiply money by fixnum



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

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

#+(other_money) ⇒ Object



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

def +(other_money)
  other_money = other_money.exchange_to(currency) unless other_money.currency == currency
  
  new_precision = [precision, other_money.precision].max
  Money.new(to_precision(new_precision).cents + other_money.to_precision(new_precision).cents, currency, new_precision)
end

#-(other_money) ⇒ Object



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

def -(other_money)
  other_money = other_money.exchange_to(currency) unless other_money.currency == currency
  
  new_precision = [precision, other_money.precision].max
  Money.new(to_precision(new_precision).cents - other_money.to_precision(new_precision).cents, currency, new_precision)
end

#/(fixnum) ⇒ Object

divide money by fixnum



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

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

#<=>(other_money) ⇒ Object



60
61
62
63
64
65
66
# File 'lib/money/money.rb', line 60

def <=>(other_money)
  if currency == other_money.currency
    cents <=> other_money.cents
  else
    cents <=> other_money.exchange_to(currency).cents
  end
end

#as_ca_dollarObject

Recieve a money object with the same amount as the current Money object in canadian dollar



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

def as_ca_dollar
  exchange_to("CAD")
end

#as_ca_euroObject

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



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

def as_ca_euro
  exchange_to("EUR")
end

#as_us_dollarObject

Recieve a money object with the same amount as the current Money object in american dollar



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

def as_us_dollar
  exchange_to("USD")
end

#eql?(other_money) ⇒ Boolean

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

Returns:

  • (Boolean)


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

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



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

def exchange_to(other_currency)
  self.class.bank.reduce(self, other_currency)
end

#format(*rules) ⇒ Object

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

with_currency:

Money.ca_dollar(0).format => "free"
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"

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>"


124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/money/money.rb', line 124

def format(*rules)
  return "free" if cents == 0

  rules = rules.flatten

  formatted = "$" + to_s(rules.include?(:no_cents) ? 0 : 2)

  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



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

def to_money
  self
end

#to_precision(new_precision) ⇒ Object



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

def to_precision(new_precision)
  difference = new_precision - precision
  new_cents = difference > 0 ? cents * 10**difference : (cents.to_f / 10**difference.abs).round
  Money.new(new_cents, 'USD', new_precision)
end

#to_s(show_precision = precision) ⇒ Object

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



141
142
143
144
145
146
147
# File 'lib/money/money.rb', line 141

def to_s(show_precision = precision)
  if show_precision > 0
    sprintf("%.#{show_precision}f", cents.to_f / 10 ** precision  )
  else
    sprintf("%d", cents.to_f / 10 ** (precision - show_precision)  )
  end
end

#zero?Boolean

Test if the money amount is zero

Returns:

  • (Boolean)


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

def zero?
  cents == 0 
end