money 2.1.5 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/{MIT-LICENSE → LICENSE} +21 -21
- data/README.rdoc +97 -97
- data/Rakefile +44 -18
- data/VERSION +1 -0
- data/lib/money.rb +26 -26
- data/lib/money/core_extensions.rb +138 -138
- data/lib/money/{symbols.rb → defaults.rb} +31 -19
- data/lib/money/errors.rb +4 -4
- data/lib/money/money.rb +388 -299
- data/lib/money/variable_exchange_bank.rb +72 -72
- data/money.gemspec +65 -24
- data/test/core_extensions_spec.rb +73 -73
- data/test/exchange_bank_spec.rb +45 -45
- data/test/money_spec.rb +413 -263
- metadata +39 -13
@@ -1,19 +1,31 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
# Add more from http://www.xe.com/symbols.php
|
4
|
-
Money::SYMBOLS = {
|
5
|
-
"GBP" => "£",
|
6
|
-
"JPY" => "¥",
|
7
|
-
"EUR" => "€",
|
8
|
-
"ZWD" => "Z$",
|
9
|
-
"CNY" => "¥",
|
10
|
-
"INR" => "₨",
|
11
|
-
"NPR" => "₨",
|
12
|
-
"SCR" => "₨",
|
13
|
-
"LKR" => "₨",
|
14
|
-
"SEK" => "kr",
|
15
|
-
"GHC" => "¢",
|
16
|
-
"BRL" => "R$"
|
17
|
-
|
18
|
-
# Everything else defaults to $
|
19
|
-
}
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# Add more from http://www.xe.com/symbols.php
|
4
|
+
Money::SYMBOLS = {
|
5
|
+
"GBP" => "£",
|
6
|
+
"JPY" => "¥",
|
7
|
+
"EUR" => "€",
|
8
|
+
"ZWD" => "Z$",
|
9
|
+
"CNY" => "¥",
|
10
|
+
"INR" => "₨",
|
11
|
+
"NPR" => "₨",
|
12
|
+
"SCR" => "₨",
|
13
|
+
"LKR" => "₨",
|
14
|
+
"SEK" => "kr",
|
15
|
+
"GHC" => "¢",
|
16
|
+
"BRL" => "R$ ",
|
17
|
+
|
18
|
+
# Everything else defaults to '$'
|
19
|
+
}
|
20
|
+
|
21
|
+
Money::SEPARATORS = {
|
22
|
+
"BRL" => ",",
|
23
|
+
|
24
|
+
# Everything else defaults to '.'
|
25
|
+
}
|
26
|
+
|
27
|
+
Money::DELIMITERS = {
|
28
|
+
"BRL" => ".",
|
29
|
+
|
30
|
+
# Everything else defaults to ","
|
31
|
+
}
|
data/lib/money/errors.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
class Money
|
2
|
-
class UnknownRate < StandardError
|
3
|
-
end
|
4
|
-
end
|
1
|
+
class Money
|
2
|
+
class UnknownRate < StandardError
|
3
|
+
end
|
4
|
+
end
|
data/lib/money/money.rb
CHANGED
@@ -1,299 +1,388 @@
|
|
1
|
-
require 'money/variable_exchange_bank'
|
2
|
-
|
3
|
-
# Represents an amount of money in a certain currency.
|
4
|
-
class Money
|
5
|
-
include Comparable
|
6
|
-
|
7
|
-
attr_reader :cents, :currency, :bank
|
8
|
-
|
9
|
-
class << self
|
10
|
-
# Each Money object is associated to a bank object, which is responsible
|
11
|
-
# for currency exchange. This property allows one to specify the default
|
12
|
-
# bank object.
|
13
|
-
#
|
14
|
-
# bank1 = MyBank.new
|
15
|
-
# bank2 = MyOtherBank.new
|
16
|
-
#
|
17
|
-
# Money.default_bank = bank1
|
18
|
-
# money1 = Money.new(10)
|
19
|
-
# money1.bank # => bank1
|
20
|
-
#
|
21
|
-
# Money.default_bank = bank2
|
22
|
-
# money2 = Money.new(10)
|
23
|
-
# money2.bank # => bank2
|
24
|
-
# money1.bank # => bank1
|
25
|
-
#
|
26
|
-
# The default value for this property is an instance if VariableExchangeBank.
|
27
|
-
# It allows one to specify custom exchange rates:
|
28
|
-
#
|
29
|
-
# Money.default_bank.add_rate("USD", "CAD", 1.24515)
|
30
|
-
# Money.default_bank.add_rate("CAD", "USD", 0.803115)
|
31
|
-
# Money.us_dollar(100).exchange_to("CAD") # => Money.ca_dollar(124)
|
32
|
-
# Money.ca_dollar(100).exchange_to("USD") # => Money.us_dollar(80)
|
33
|
-
attr_accessor :default_bank
|
34
|
-
|
35
|
-
# The default currency, which is used when <tt>Money.new</tt> is called
|
36
|
-
# without an explicit currency argument. The default value is "USD".
|
37
|
-
attr_accessor :default_currency
|
38
|
-
end
|
39
|
-
|
40
|
-
self.default_bank = VariableExchangeBank.instance
|
41
|
-
self.default_currency = "USD"
|
42
|
-
|
43
|
-
|
44
|
-
# Create a new money object with value 0.
|
45
|
-
def self.empty(currency = default_currency)
|
46
|
-
Money.new(0, currency)
|
47
|
-
end
|
48
|
-
|
49
|
-
# Creates a new Money object of the given value, using the Canadian dollar currency.
|
50
|
-
def self.ca_dollar(cents)
|
51
|
-
Money.new(cents, "CAD")
|
52
|
-
end
|
53
|
-
|
54
|
-
# Creates a new Money object of the given value, using the American dollar currency.
|
55
|
-
def self.us_dollar(cents)
|
56
|
-
Money.new(cents, "USD")
|
57
|
-
end
|
58
|
-
|
59
|
-
# Creates a new Money object of the given value, using the Euro currency.
|
60
|
-
def self.euro(cents)
|
61
|
-
Money.new(cents, "EUR")
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.add_rate(from_currency, to_currency, rate)
|
65
|
-
Money.default_bank.add_rate(from_currency, to_currency, rate)
|
66
|
-
end
|
67
|
-
|
68
|
-
|
69
|
-
# Creates a new money object.
|
70
|
-
# Money.new(100)
|
71
|
-
#
|
72
|
-
# Alternativly you can use the convinience methods like
|
73
|
-
# Money.ca_dollar and Money.us_dollar
|
74
|
-
def initialize(cents, currency = Money.default_currency, bank = Money.default_bank)
|
75
|
-
@cents = cents.round
|
76
|
-
if currency.is_a?(Hash)
|
77
|
-
# Earlier versions of Money wrongly documented the constructor as being able
|
78
|
-
# to accept something like this:
|
79
|
-
#
|
80
|
-
# Money.new(50, :currency => "USD")
|
81
|
-
#
|
82
|
-
# We retain compatibility here.
|
83
|
-
@currency = currency[:currency] || Money.default_currency
|
84
|
-
else
|
85
|
-
@currency = currency
|
86
|
-
end
|
87
|
-
@bank = bank
|
88
|
-
end
|
89
|
-
|
90
|
-
#
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
end
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
#
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
#
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
#
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
#
|
169
|
-
#
|
170
|
-
#
|
171
|
-
#
|
172
|
-
#
|
173
|
-
#
|
174
|
-
#
|
175
|
-
#
|
176
|
-
#
|
177
|
-
# Money.
|
178
|
-
# Money.
|
179
|
-
#
|
180
|
-
#
|
181
|
-
#
|
182
|
-
#
|
183
|
-
#
|
184
|
-
#
|
185
|
-
#
|
186
|
-
#
|
187
|
-
#
|
188
|
-
#
|
189
|
-
#
|
190
|
-
#
|
191
|
-
#
|
192
|
-
#
|
193
|
-
#
|
194
|
-
#
|
195
|
-
#
|
196
|
-
# Money.
|
197
|
-
#
|
198
|
-
#
|
199
|
-
#
|
200
|
-
#
|
201
|
-
#
|
202
|
-
#
|
203
|
-
#
|
204
|
-
#
|
205
|
-
#
|
206
|
-
# Money.
|
207
|
-
#
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
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
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
end
|
297
|
-
|
298
|
-
|
299
|
-
|
1
|
+
require 'money/variable_exchange_bank'
|
2
|
+
|
3
|
+
# Represents an amount of money in a certain currency.
|
4
|
+
class Money
|
5
|
+
include Comparable
|
6
|
+
|
7
|
+
attr_reader :cents, :currency, :bank
|
8
|
+
|
9
|
+
class << self
|
10
|
+
# Each Money object is associated to a bank object, which is responsible
|
11
|
+
# for currency exchange. This property allows one to specify the default
|
12
|
+
# bank object.
|
13
|
+
#
|
14
|
+
# bank1 = MyBank.new
|
15
|
+
# bank2 = MyOtherBank.new
|
16
|
+
#
|
17
|
+
# Money.default_bank = bank1
|
18
|
+
# money1 = Money.new(10)
|
19
|
+
# money1.bank # => bank1
|
20
|
+
#
|
21
|
+
# Money.default_bank = bank2
|
22
|
+
# money2 = Money.new(10)
|
23
|
+
# money2.bank # => bank2
|
24
|
+
# money1.bank # => bank1
|
25
|
+
#
|
26
|
+
# The default value for this property is an instance if VariableExchangeBank.
|
27
|
+
# It allows one to specify custom exchange rates:
|
28
|
+
#
|
29
|
+
# Money.default_bank.add_rate("USD", "CAD", 1.24515)
|
30
|
+
# Money.default_bank.add_rate("CAD", "USD", 0.803115)
|
31
|
+
# Money.us_dollar(100).exchange_to("CAD") # => Money.ca_dollar(124)
|
32
|
+
# Money.ca_dollar(100).exchange_to("USD") # => Money.us_dollar(80)
|
33
|
+
attr_accessor :default_bank
|
34
|
+
|
35
|
+
# The default currency, which is used when <tt>Money.new</tt> is called
|
36
|
+
# without an explicit currency argument. The default value is "USD".
|
37
|
+
attr_accessor :default_currency
|
38
|
+
end
|
39
|
+
|
40
|
+
self.default_bank = VariableExchangeBank.instance
|
41
|
+
self.default_currency = "USD"
|
42
|
+
|
43
|
+
|
44
|
+
# Create a new money object with value 0.
|
45
|
+
def self.empty(currency = default_currency)
|
46
|
+
Money.new(0, currency)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Creates a new Money object of the given value, using the Canadian dollar currency.
|
50
|
+
def self.ca_dollar(cents)
|
51
|
+
Money.new(cents, "CAD")
|
52
|
+
end
|
53
|
+
|
54
|
+
# Creates a new Money object of the given value, using the American dollar currency.
|
55
|
+
def self.us_dollar(cents)
|
56
|
+
Money.new(cents, "USD")
|
57
|
+
end
|
58
|
+
|
59
|
+
# Creates a new Money object of the given value, using the Euro currency.
|
60
|
+
def self.euro(cents)
|
61
|
+
Money.new(cents, "EUR")
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.add_rate(from_currency, to_currency, rate)
|
65
|
+
Money.default_bank.add_rate(from_currency, to_currency, rate)
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
# Creates a new money object.
|
70
|
+
# Money.new(100)
|
71
|
+
#
|
72
|
+
# Alternativly you can use the convinience methods like
|
73
|
+
# Money.ca_dollar and Money.us_dollar
|
74
|
+
def initialize(cents, currency = Money.default_currency, bank = Money.default_bank)
|
75
|
+
@cents = cents.round
|
76
|
+
if currency.is_a?(Hash)
|
77
|
+
# Earlier versions of Money wrongly documented the constructor as being able
|
78
|
+
# to accept something like this:
|
79
|
+
#
|
80
|
+
# Money.new(50, :currency => "USD")
|
81
|
+
#
|
82
|
+
# We retain compatibility here.
|
83
|
+
@currency = currency[:currency] || Money.default_currency
|
84
|
+
else
|
85
|
+
@currency = currency
|
86
|
+
end
|
87
|
+
@bank = bank
|
88
|
+
end
|
89
|
+
|
90
|
+
# Checks whether two money objects have the same currency and the same amount.
|
91
|
+
# Checks against money objects with a different currency and checks against
|
92
|
+
# objects that do not respond to #to_money will always return false.
|
93
|
+
def ==(other_money)
|
94
|
+
if other_money.respond_to?(:to_money)
|
95
|
+
other_money = other_money.to_money
|
96
|
+
cents == other_money.cents && bank.same_currency?(currency, other_money.currency)
|
97
|
+
else
|
98
|
+
false
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Compares this money object against another object. +other_money+ must respond
|
103
|
+
# to #to_money.
|
104
|
+
#
|
105
|
+
# If +other_money+ is of a different currency, then +other_money+ will first be
|
106
|
+
# converted into this money object's currency by calling +other_money.exchange+.
|
107
|
+
#
|
108
|
+
# Comparisons against objects that do not respond to #to_money will cause an
|
109
|
+
# ArgumentError to be raised.
|
110
|
+
def <=>(other_money)
|
111
|
+
if other_money.respond_to?(:to_money)
|
112
|
+
other_money = other_money.to_money
|
113
|
+
if bank.same_currency?(currency, other_money.currency)
|
114
|
+
cents <=> other_money.cents
|
115
|
+
else
|
116
|
+
cents <=> other_money.exchange_to(currency).cents
|
117
|
+
end
|
118
|
+
else
|
119
|
+
raise ArgumentError, "comparison of #{self.class} with #{other_money.inspect} failed"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def +(other_money)
|
124
|
+
if currency == other_money.currency
|
125
|
+
Money.new(cents + other_money.cents, other_money.currency)
|
126
|
+
else
|
127
|
+
Money.new(cents + other_money.exchange_to(currency).cents, currency)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def -(other_money)
|
132
|
+
if currency == other_money.currency
|
133
|
+
Money.new(cents - other_money.cents, other_money.currency)
|
134
|
+
else
|
135
|
+
Money.new(cents - other_money.exchange_to(currency).cents, currency)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# get the cents value of the object
|
140
|
+
def cents
|
141
|
+
@cents
|
142
|
+
end
|
143
|
+
|
144
|
+
# multiply money by fixnum
|
145
|
+
def *(fixnum)
|
146
|
+
Money.new(cents * fixnum, currency)
|
147
|
+
end
|
148
|
+
|
149
|
+
# divide money by money or fixnum
|
150
|
+
def /(val)
|
151
|
+
if val.is_a?(Money)
|
152
|
+
if currency == val.currency
|
153
|
+
cents / val.cents.to_f
|
154
|
+
else
|
155
|
+
cents / val.exchange_to(currency).cents.to_f
|
156
|
+
end
|
157
|
+
else
|
158
|
+
Money.new(cents / val, currency)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Test if the money amount is zero
|
163
|
+
def zero?
|
164
|
+
cents == 0
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
# Creates a formatted price string according to several rules. The following
|
169
|
+
# options are supported: :display_free, :with_currency, :no_cents, :symbol,
|
170
|
+
# :separator, :delimiter and :html.
|
171
|
+
#
|
172
|
+
# === +:display_free+
|
173
|
+
#
|
174
|
+
# Whether a zero amount of money should be formatted of "free" or as the
|
175
|
+
# supplied string.
|
176
|
+
#
|
177
|
+
# Money.us_dollar(0).format(:display_free => true) => "free"
|
178
|
+
# Money.us_dollar(0).format(:display_free => "gratis") => "gratis"
|
179
|
+
# Money.us_dollar(0).format => "$0.00"
|
180
|
+
#
|
181
|
+
# === +:with_currency+
|
182
|
+
#
|
183
|
+
# Whether the currency name should be appended to the result string.
|
184
|
+
#
|
185
|
+
# Money.ca_dollar(100).format => "$1.00"
|
186
|
+
# Money.ca_dollar(100).format(:with_currency => true) => "$1.00 CAD"
|
187
|
+
# Money.us_dollar(85).format(:with_currency => true) => "$0.85 USD"
|
188
|
+
#
|
189
|
+
# === +:no_cents+
|
190
|
+
#
|
191
|
+
# Whether cents should be omitted.
|
192
|
+
#
|
193
|
+
# Money.ca_dollar(100).format(:no_cents => true) => "$1"
|
194
|
+
# Money.ca_dollar(599).format(:no_cents => true) => "$5"
|
195
|
+
#
|
196
|
+
# Money.ca_dollar(570).format(:no_cents => true, :with_currency => true) => "$5 CAD"
|
197
|
+
# Money.ca_dollar(39000).format(:no_cents => true) => "$390"
|
198
|
+
#
|
199
|
+
# === +:symbol+
|
200
|
+
#
|
201
|
+
# Whether a money symbol should be prepended to the result string. The default is true.
|
202
|
+
# This method attempts to pick a symbol that's suitable for the given currency.
|
203
|
+
#
|
204
|
+
# Money.new(100, "USD") => "$1.00"
|
205
|
+
# Money.new(100, "GBP") => "£1.00"
|
206
|
+
# Money.new(100, "EUR") => "€1.00"
|
207
|
+
#
|
208
|
+
# # Same thing.
|
209
|
+
# Money.new(100, "USD").format(:symbol => true) => "$1.00"
|
210
|
+
# Money.new(100, "GBP").format(:symbol => true) => "£1.00"
|
211
|
+
# Money.new(100, "EUR").format(:symbol => true) => "€1.00"
|
212
|
+
#
|
213
|
+
# You can specify a false expression or an empty string to disable prepending
|
214
|
+
# a money symbol:
|
215
|
+
#
|
216
|
+
# Money.new(100, "USD").format(:symbol => false) => "1.00"
|
217
|
+
# Money.new(100, "GBP").format(:symbol => nil) => "1.00"
|
218
|
+
# Money.new(100, "EUR").format(:symbol => "") => "1.00"
|
219
|
+
#
|
220
|
+
#
|
221
|
+
# If the symbol for the given currency isn't known, then it will default
|
222
|
+
# to "$" as symbol:
|
223
|
+
#
|
224
|
+
# Money.new(100, "AWG").format(:symbol => true) => "$1.00"
|
225
|
+
#
|
226
|
+
# You can specify a string as value to enforce using a particular symbol:
|
227
|
+
#
|
228
|
+
# Money.new(100, "AWG").format(:symbol => "ƒ") => "ƒ1.00"
|
229
|
+
#
|
230
|
+
# === +:separator+
|
231
|
+
#
|
232
|
+
# Whether the currency should be separated by the specified character or '.'
|
233
|
+
#
|
234
|
+
# If a string is specified, it's value is used:
|
235
|
+
#
|
236
|
+
# Money.new(100, "USD").format(:separator => ",") => "$1,00"
|
237
|
+
#
|
238
|
+
# If the separator for a given currency isn't known, then it will default to
|
239
|
+
# "." as separator:
|
240
|
+
#
|
241
|
+
# Money.new(100, "FOO").format => "$1.00"
|
242
|
+
#
|
243
|
+
# === +:delimiter+
|
244
|
+
#
|
245
|
+
# Whether the currency should be delimited by the specified character or ','
|
246
|
+
#
|
247
|
+
# If false is specified, no delimiter is used:
|
248
|
+
#
|
249
|
+
# Money.new(100000, "USD").format(:delimiter => false) => "1000.00"
|
250
|
+
# Money.new(100000, "USD").format(:delimiter => nil) => "1000.00"
|
251
|
+
# Money.new(100000, "USD").format(:delimiter => "") => "1000.00"
|
252
|
+
#
|
253
|
+
# If a string is specified, it's value is used:
|
254
|
+
#
|
255
|
+
# Money.new(100000, "USD").format(:delimiter => ".") => "$1.000.00"
|
256
|
+
#
|
257
|
+
# If the delimiter for a given currency isn't known, then it will default to
|
258
|
+
# "," as delimiter:
|
259
|
+
#
|
260
|
+
# Money.new(100000, "FOO").format => "$1,000.00"
|
261
|
+
#
|
262
|
+
# === +:html+
|
263
|
+
#
|
264
|
+
# Whether the currency should be HTML-formatted. Only useful in combination with +:with_currency+.
|
265
|
+
#
|
266
|
+
# Money.ca_dollar(570).format(:html => true, :with_currency => true)
|
267
|
+
# => "$5.70 <span class=\"currency\">CAD</span>"
|
268
|
+
def format(*rules)
|
269
|
+
# support for old format parameters
|
270
|
+
rules = normalize_formatting_rules(rules)
|
271
|
+
|
272
|
+
if cents == 0
|
273
|
+
if rules[:display_free].respond_to?(:to_str)
|
274
|
+
return rules[:display_free]
|
275
|
+
elsif rules[:display_free]
|
276
|
+
return "free"
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
if rules.has_key?(:symbol)
|
281
|
+
if rules[:symbol] === true
|
282
|
+
symbol = SYMBOLS[currency] || "$"
|
283
|
+
elsif rules[:symbol]
|
284
|
+
symbol = rules[:symbol]
|
285
|
+
else
|
286
|
+
symbol = ""
|
287
|
+
end
|
288
|
+
else
|
289
|
+
symbol = SYMBOLS[currency] || "$"
|
290
|
+
end
|
291
|
+
|
292
|
+
if rules[:no_cents]
|
293
|
+
formatted = sprintf("#{symbol}%d", cents.to_f / 100)
|
294
|
+
else
|
295
|
+
formatted = sprintf("#{symbol}%.2f", cents.to_f / 100)
|
296
|
+
end
|
297
|
+
|
298
|
+
delimiter = DELIMITERS[currency] || ","
|
299
|
+
# Determine delimiter
|
300
|
+
if rules.has_key?(:delimiter)
|
301
|
+
if rules[:delimiter] === false or rules[:delimiter].nil?
|
302
|
+
delimiter = ""
|
303
|
+
elsif rules[:delimiter]
|
304
|
+
delimiter = rules[:delimiter]
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
# Apply delimiter
|
309
|
+
formatted.gsub!(/(\d)(?=\d{3}+(?:\.|$))(\d{3}\..*)?/, "\\1#{delimiter}\\2")
|
310
|
+
|
311
|
+
separator = SEPARATORS[currency] || "."
|
312
|
+
# Determine separator
|
313
|
+
if rules.has_key?(:separator) and rules[:separator]
|
314
|
+
separator = rules[:separator]
|
315
|
+
end
|
316
|
+
|
317
|
+
# Apply separator
|
318
|
+
formatted.sub!(/\.(\d{2})$/, "#{separator}\\1")
|
319
|
+
|
320
|
+
if rules[:with_currency]
|
321
|
+
formatted << " "
|
322
|
+
formatted << '<span class="currency">' if rules[:html]
|
323
|
+
formatted << currency
|
324
|
+
formatted << '</span>' if rules[:html]
|
325
|
+
end
|
326
|
+
formatted
|
327
|
+
end
|
328
|
+
|
329
|
+
# Returns the amount of money as a string.
|
330
|
+
#
|
331
|
+
# Money.ca_dollar(100).to_s => "1.00"
|
332
|
+
def to_s
|
333
|
+
sprintf("%.2f", cents / 100.00)
|
334
|
+
end
|
335
|
+
|
336
|
+
# Return the amount of money as a float. Floating points cannot guarantee
|
337
|
+
# precision. Therefore, this function should only be used when you no longer
|
338
|
+
# need to represent currency or working with another system that requires
|
339
|
+
# decimals.
|
340
|
+
#
|
341
|
+
# Money.us_dollar(100).to_f => 1.0
|
342
|
+
def to_f
|
343
|
+
cents / 100.0
|
344
|
+
end
|
345
|
+
|
346
|
+
# Recieve the amount of this money object in another currency.
|
347
|
+
def exchange_to(other_currency)
|
348
|
+
Money.new(@bank.exchange(self.cents, currency, other_currency), other_currency)
|
349
|
+
end
|
350
|
+
|
351
|
+
# Recieve a money object with the same amount as the current Money object
|
352
|
+
# in american dollar
|
353
|
+
def as_us_dollar
|
354
|
+
exchange_to("USD")
|
355
|
+
end
|
356
|
+
|
357
|
+
# Recieve a money object with the same amount as the current Money object
|
358
|
+
# in canadian dollar
|
359
|
+
def as_ca_dollar
|
360
|
+
exchange_to("CAD")
|
361
|
+
end
|
362
|
+
|
363
|
+
# Recieve a money object with the same amount as the current Money object
|
364
|
+
# in euro
|
365
|
+
def as_euro
|
366
|
+
exchange_to("EUR")
|
367
|
+
end
|
368
|
+
|
369
|
+
# Conversation to self
|
370
|
+
def to_money
|
371
|
+
self
|
372
|
+
end
|
373
|
+
|
374
|
+
private
|
375
|
+
|
376
|
+
def normalize_formatting_rules(rules)
|
377
|
+
if rules.size == 1
|
378
|
+
rules = rules.pop
|
379
|
+
rules = { rules => true } if rules.is_a?(Symbol)
|
380
|
+
else
|
381
|
+
rules = rules.inject({}) do |h,s|
|
382
|
+
h[s] = true
|
383
|
+
h
|
384
|
+
end
|
385
|
+
end
|
386
|
+
rules
|
387
|
+
end
|
388
|
+
end
|