money 2.3.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +5 -0
- data/README.rdoc +49 -17
- data/VERSION +1 -1
- data/lib/money/core_extensions.rb +15 -15
- data/lib/money/currency.rb +1 -1
- data/lib/money/money.rb +74 -67
- data/lib/money/variable_exchange_bank.rb +16 -15
- data/money.gemspec +2 -2
- data/test/currency_spec.rb +3 -3
- data/test/exchange_bank_spec.rb +5 -5
- data/test/money_spec.rb +83 -68
- metadata +3 -3
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
== Money 3.0.0
|
2
|
+
* Version Bump due to compatibility changes with ActiveRecord. See
|
3
|
+
http://github.com/FooBarWidget/money/issues#issue/4/comment/224880 for more
|
4
|
+
information.
|
5
|
+
|
1
6
|
== Money 2.3.0
|
2
7
|
* Currency is now represented by a Currency Object instead of a string.
|
3
8
|
|
data/README.rdoc
CHANGED
@@ -2,13 +2,13 @@
|
|
2
2
|
|
3
3
|
This library aids one in handling money and different currencies. Features:
|
4
4
|
|
5
|
-
- Provides a Money class which encapsulates all information about an certain
|
5
|
+
- Provides a <tt>Money</tt> class which encapsulates all information about an certain
|
6
6
|
amount of money, such as its value and its currency.
|
7
|
-
- Provies a Currency class which encapsulates all information about
|
7
|
+
- Provies a <tt>Money::Currency</tt> class which encapsulates all information about
|
8
8
|
a monerary unit.
|
9
9
|
- Represents monetary values as integers, in cents. This avoids floating point
|
10
10
|
rounding errors.
|
11
|
-
- Represents currency as Currency instances providing an high level of flexibility.
|
11
|
+
- Represents currency as <tt>Money::Currency</tt> instances providing an high level of flexibility.
|
12
12
|
- Provides APIs for exchanging money from one currency to another.
|
13
13
|
- Has the ability to parse a money and currency strings
|
14
14
|
into the corresponding Money/Currency object.
|
@@ -48,13 +48,13 @@ The development version (hosted on Github) can be installed with:
|
|
48
48
|
|
49
49
|
=== Currency
|
50
50
|
|
51
|
-
Currencies are consistently represented as instances of Money::Currency
|
52
|
-
The most part of Money APIs allows you to supply either a String or a Currency
|
51
|
+
Currencies are consistently represented as instances of <tt>Money::Currency</tt>.
|
52
|
+
The most part of <tt>Money</tt> APIs allows you to supply either a <tt>String</tt> or a <tt>Money::Currency</tt>.
|
53
53
|
|
54
54
|
Money.new(1000, "USD") == Money.new(900, Currency.new("USD"))
|
55
55
|
Money.new(1000, "EUR").currency == Currency.new("EUR")
|
56
56
|
|
57
|
-
A Money::Currency instance holds all the information about the currency,
|
57
|
+
A <tt>Money::Currency</tt> instance holds all the information about the currency,
|
58
58
|
including the currency symbol, name and much more.
|
59
59
|
|
60
60
|
currency = Money.new(1000, "USD")
|
@@ -63,8 +63,8 @@ including the currency symbol, name and much more.
|
|
63
63
|
currency.name
|
64
64
|
# => "United States Dollar"
|
65
65
|
|
66
|
-
To define a new Money::Currency simply add a new item to the Money::Currency::TABLE hash,
|
67
|
-
where the key is the identifier for the
|
66
|
+
To define a new <tt>Money::Currency</tt> simply add a new item to the <tt>Money::Currency::TABLE</tt> hash,
|
67
|
+
where the key is the identifier for the currency object and the value is a hash
|
68
68
|
containing all the currency attributes.
|
69
69
|
|
70
70
|
Money::Currency::TABLE[:usd] = {
|
@@ -85,13 +85,13 @@ The pre-defined set of attributes includes:
|
|
85
85
|
* subunit: the name of the fractional monetary unit
|
86
86
|
* subunit_to_unit: the proportion between the unit and the subunit
|
87
87
|
|
88
|
-
All attributes are optional. Some attributes, such as
|
89
|
-
to print out a representation of the object. Other attributes, such as
|
88
|
+
All attributes are optional. Some attributes, such as <tt>:symbol</tt>, are used by the Money class
|
89
|
+
to print out a representation of the object. Other attributes, such as <tt>:name</tt> or <tt>:priority</tt>,
|
90
90
|
exist to provide a basic API you can take advantage of to build your application.
|
91
91
|
|
92
92
|
==== priority
|
93
93
|
|
94
|
-
The priority attribute is an arbitrary numerical value you can assign to the Currency
|
94
|
+
The priority attribute is an arbitrary numerical value you can assign to the <tt>Money::Currency</tt>
|
95
95
|
and use in sorting/grouping operation.
|
96
96
|
|
97
97
|
For instance, let's assume your Rails application needs to a currency selector
|
@@ -126,11 +126,11 @@ and all_currencies as follows:
|
|
126
126
|
|
127
127
|
=== Default Currency
|
128
128
|
|
129
|
-
By default Money defaults to USD as its currency. This can be overwritten using
|
129
|
+
By default <tt>Money</tt> defaults to USD as its currency. This can be overwritten using
|
130
130
|
|
131
131
|
Money.default_currency = Money::Currency.new("CAD")
|
132
132
|
|
133
|
-
If you use Rails, then environment.rb is a very good place to put this.
|
133
|
+
If you use Rails, then <tt>environment.rb</tt> is a very good place to put this.
|
134
134
|
|
135
135
|
=== Currency Exchange
|
136
136
|
|
@@ -157,6 +157,13 @@ www.xe.com for the current rates or just returns <tt>rand(2)</tt>:
|
|
157
157
|
|
158
158
|
Money.default_bank = ExchangeBankWhichScrapesXeDotCom.new
|
159
159
|
|
160
|
+
=== Currency Exchange Implementations
|
161
|
+
|
162
|
+
The following is a list of Money.gem compatible currency exchange rate
|
163
|
+
implementations.
|
164
|
+
|
165
|
+
* eu_central_bank.gem: http://github.com/liangzan/eu_central_bank
|
166
|
+
|
160
167
|
=== Ruby on Rails
|
161
168
|
|
162
169
|
Use the +compose_of+ helper to let Active Record deal with embedding the money
|
@@ -165,15 +172,40 @@ field.
|
|
165
172
|
|
166
173
|
class ProductUnit < ActiveRecord::Base
|
167
174
|
belongs_to :product
|
168
|
-
composed_of :price, :class_name => "Money", :mapping => [%w(cents cents), %w(currency
|
175
|
+
composed_of :price, :class_name => "Money", :mapping => [%w(cents cents), %w(currency currency_as_string)]
|
169
176
|
|
170
|
-
private
|
177
|
+
private
|
171
178
|
validate :cents_not_zero
|
172
|
-
|
179
|
+
|
173
180
|
def cents_not_zero
|
174
181
|
errors.add("cents", "cannot be zero or less") unless cents > 0
|
175
182
|
end
|
176
183
|
|
177
184
|
validates_presence_of :sku, :currency
|
178
|
-
validates_uniqueness_of :sku
|
185
|
+
validates_uniqueness_of :sku
|
186
|
+
end
|
187
|
+
|
188
|
+
Also, because the <tt>currency</tt> attribute is not a simple <tt>String</tt>
|
189
|
+
but a <tt>Money::Currency</tt> object, you need a small tweak to make it work.
|
190
|
+
|
191
|
+
Extend/hack the <tt>Money</tt> class with two additional methods:
|
192
|
+
|
193
|
+
# You can put this file in the config/initializers/ folder
|
194
|
+
class Money
|
195
|
+
def currency_as_string
|
196
|
+
currency.to_s
|
197
|
+
end
|
198
|
+
|
199
|
+
def currency_as_string=(value)
|
200
|
+
# WARNING: this method might cause data inconsistency.
|
201
|
+
# See http://github.com/FooBarWidget/money/issues/4#issue/4/comment/224930
|
202
|
+
# currency = Currency.wrap(value)
|
203
|
+
end
|
179
204
|
end
|
205
|
+
|
206
|
+
The hack is not required for Money 2.2.x and previous versions.
|
207
|
+
In this case, simply use the following <tt>composed_of</tt> definition:
|
208
|
+
|
209
|
+
composed_of :price, :class_name => "Money", :mapping => [%w(cents cents), %w(currency currency)]
|
210
|
+
|
211
|
+
For further details read the full discussion at http://github.com/FooBarWidget/money/issues/4#comment_224880
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
3.0.0
|
@@ -34,20 +34,20 @@ class String
|
|
34
34
|
end
|
35
35
|
|
36
36
|
private
|
37
|
-
|
37
|
+
|
38
38
|
def calculate_cents(number)
|
39
39
|
# remove anything that's not a number, potential delimiter, or minus sign
|
40
40
|
num = number.gsub(/[^\d|\.|,|\'|\s|\-]/, '').strip
|
41
|
-
|
41
|
+
|
42
42
|
# set a boolean flag for if the number is negative or not
|
43
43
|
negative = num.split(//).first == "-"
|
44
|
-
|
44
|
+
|
45
45
|
# if negative, remove the minus sign from the number
|
46
46
|
num = num.gsub(/^-/, '') if negative
|
47
|
-
|
47
|
+
|
48
48
|
# gather all separators within the result number
|
49
49
|
used_separators = num.scan /[^\d]/
|
50
|
-
|
50
|
+
|
51
51
|
# determine the number of unique separators within the number
|
52
52
|
#
|
53
53
|
# e.g.
|
@@ -58,8 +58,8 @@ class String
|
|
58
58
|
case used_separators.uniq.length
|
59
59
|
# no separator or delimiter; major (dollars) is the number, and minor (cents) is 0
|
60
60
|
when 0 then major, minor = num, 0
|
61
|
-
|
62
|
-
# two separators, so we know the last item in this array is the
|
61
|
+
|
62
|
+
# two separators, so we know the last item in this array is the
|
63
63
|
# major/minor delimiter and the rest are separators
|
64
64
|
when 2
|
65
65
|
separator, delimiter = used_separators.uniq
|
@@ -75,10 +75,10 @@ class String
|
|
75
75
|
# 1,000,000 - comma is a separator
|
76
76
|
# 10000,00 - comma is a delimiter
|
77
77
|
# 1000,000 - comma is a delimiter
|
78
|
-
|
78
|
+
|
79
79
|
# assign first separator for reusability
|
80
80
|
separator = used_separators.first
|
81
|
-
|
81
|
+
|
82
82
|
# separator is used as a separator when there are multiple instances, always
|
83
83
|
if num.scan(separator).length > 1 # multiple matches; treat as separator
|
84
84
|
major, minor = num.gsub(separator, ''), 0
|
@@ -88,7 +88,7 @@ class String
|
|
88
88
|
possible_major, possible_minor = num.split(separator)
|
89
89
|
possible_major ||= "0"
|
90
90
|
possible_minor ||= "00"
|
91
|
-
|
91
|
+
|
92
92
|
# if the minor (cents) length isn't 3, assign major/minor from the possibles
|
93
93
|
# e.g.
|
94
94
|
# 1,00 => 1.00
|
@@ -99,8 +99,8 @@ class String
|
|
99
99
|
else
|
100
100
|
# minor length is three
|
101
101
|
# let's try to figure out intent of the delimiter
|
102
|
-
|
103
|
-
# the major length is greater than three, which means
|
102
|
+
|
103
|
+
# the major length is greater than three, which means
|
104
104
|
# the comma or period is used as a delimiter
|
105
105
|
# e.g.
|
106
106
|
# 1000,000
|
@@ -121,7 +121,7 @@ class String
|
|
121
121
|
else
|
122
122
|
raise ArgumentError, "Invalid currency amount"
|
123
123
|
end
|
124
|
-
|
124
|
+
|
125
125
|
# build the string based on major/minor since separator/delimiters have been removed
|
126
126
|
# avoiding floating point arithmetic here to ensure accuracy
|
127
127
|
cents = (major.to_i * 100)
|
@@ -136,9 +136,9 @@ class String
|
|
136
136
|
if minor.size >= 3 && minor[2..2].to_i >= 5
|
137
137
|
cents += 1
|
138
138
|
end
|
139
|
-
|
139
|
+
|
140
140
|
# if negative, multiply by -1; otherwise, return positive cents
|
141
141
|
negative ? cents * -1 : cents
|
142
142
|
end
|
143
|
-
|
143
|
+
|
144
144
|
end
|
data/lib/money/currency.rb
CHANGED
data/lib/money/money.rb
CHANGED
@@ -15,11 +15,11 @@ class Money
|
|
15
15
|
#
|
16
16
|
# bank1 = MyBank.new
|
17
17
|
# bank2 = MyOtherBank.new
|
18
|
-
#
|
18
|
+
#
|
19
19
|
# Money.default_bank = bank1
|
20
20
|
# money1 = Money.new(10)
|
21
21
|
# money1.bank # => bank1
|
22
|
-
#
|
22
|
+
#
|
23
23
|
# Money.default_bank = bank2
|
24
24
|
# money2 = Money.new(10)
|
25
25
|
# money2.bank # => bank2
|
@@ -33,17 +33,17 @@ class Money
|
|
33
33
|
# Money.us_dollar(100).exchange_to("CAD") # => Money.ca_dollar(124)
|
34
34
|
# Money.ca_dollar(100).exchange_to("USD") # => Money.us_dollar(80)
|
35
35
|
attr_accessor :default_bank
|
36
|
-
|
36
|
+
|
37
37
|
# The default currency, which is used when <tt>Money.new</tt> is called
|
38
38
|
# without an explicit currency argument. The default value is Currency.new("USD").
|
39
39
|
# The value must be a valid <tt>Money::Currency</tt> instance.
|
40
40
|
attr_accessor :default_currency
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
self.default_bank = VariableExchangeBank.instance
|
44
44
|
self.default_currency = Currency.new("USD")
|
45
|
-
|
46
|
-
|
45
|
+
|
46
|
+
|
47
47
|
# Create a new money object with value 0.
|
48
48
|
def self.empty(currency = default_currency)
|
49
49
|
Money.new(0, currency)
|
@@ -58,22 +58,22 @@ class Money
|
|
58
58
|
def self.us_dollar(cents)
|
59
59
|
Money.new(cents, "USD")
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
# Creates a new Money object of the given value, using the Euro currency.
|
63
63
|
def self.euro(cents)
|
64
64
|
Money.new(cents, "EUR")
|
65
65
|
end
|
66
|
-
|
66
|
+
|
67
67
|
def self.add_rate(from_currency, to_currency, rate)
|
68
68
|
Money.default_bank.add_rate(from_currency, to_currency, rate)
|
69
69
|
end
|
70
|
-
|
71
|
-
|
72
|
-
# Creates a new money object.
|
73
|
-
# Money.new(100)
|
74
|
-
#
|
75
|
-
#
|
76
|
-
# Money.ca_dollar and Money.us_dollar
|
70
|
+
|
71
|
+
|
72
|
+
# Creates a new money object.
|
73
|
+
# Money.new(100)
|
74
|
+
#
|
75
|
+
# Alternatively you can use the convinience methods like
|
76
|
+
# Money.ca_dollar and Money.us_dollar
|
77
77
|
def initialize(cents, currency = Money.default_currency, bank = Money.default_bank)
|
78
78
|
@cents = cents.round
|
79
79
|
if currency.is_a?(Hash)
|
@@ -101,7 +101,7 @@ class Money
|
|
101
101
|
false
|
102
102
|
end
|
103
103
|
end
|
104
|
-
|
104
|
+
|
105
105
|
# Compares this money object against another object. +other_money+ must respond
|
106
106
|
# to #to_money.
|
107
107
|
#
|
@@ -161,12 +161,17 @@ class Money
|
|
161
161
|
Money.new(cents / val, currency)
|
162
162
|
end
|
163
163
|
end
|
164
|
-
|
164
|
+
|
165
165
|
# Test if the money amount is zero
|
166
166
|
def zero?
|
167
167
|
cents == 0
|
168
168
|
end
|
169
169
|
|
170
|
+
# Test if the money amount is non-zero. Returns this money object if it is
|
171
|
+
# non-zero, or nil otherwise, like <tt>Numeric#nonzero?</tt>.
|
172
|
+
def nonzero?
|
173
|
+
cents != 0 ? self : nil
|
174
|
+
end
|
170
175
|
|
171
176
|
# Attempts to pick a symbol that's suitable for the given currency
|
172
177
|
# looking up the Currency::TABLE hashtable.
|
@@ -201,58 +206,58 @@ class Money
|
|
201
206
|
# Whether a zero amount of money should be formatted of "free" or as the
|
202
207
|
# supplied string.
|
203
208
|
#
|
204
|
-
#
|
205
|
-
#
|
206
|
-
#
|
209
|
+
# Money.us_dollar(0).format(:display_free => true) => "free"
|
210
|
+
# Money.us_dollar(0).format(:display_free => "gratis") => "gratis"
|
211
|
+
# Money.us_dollar(0).format => "$0.00"
|
207
212
|
#
|
208
213
|
# === +:with_currency+
|
209
214
|
#
|
210
215
|
# Whether the currency name should be appended to the result string.
|
211
216
|
#
|
212
|
-
#
|
213
|
-
#
|
214
|
-
#
|
217
|
+
# Money.ca_dollar(100).format => "$1.00"
|
218
|
+
# Money.ca_dollar(100).format(:with_currency => true) => "$1.00 CAD"
|
219
|
+
# Money.us_dollar(85).format(:with_currency => true) => "$0.85 USD"
|
215
220
|
#
|
216
221
|
# === +:no_cents+
|
217
222
|
#
|
218
223
|
# Whether cents should be omitted.
|
219
224
|
#
|
220
|
-
#
|
221
|
-
#
|
222
|
-
#
|
223
|
-
#
|
224
|
-
#
|
225
|
+
# Money.ca_dollar(100).format(:no_cents => true) => "$1"
|
226
|
+
# Money.ca_dollar(599).format(:no_cents => true) => "$5"
|
227
|
+
#
|
228
|
+
# Money.ca_dollar(570).format(:no_cents => true, :with_currency => true) => "$5 CAD"
|
229
|
+
# Money.ca_dollar(39000).format(:no_cents => true) => "$390"
|
225
230
|
#
|
226
231
|
# === +:symbol+
|
227
232
|
#
|
228
233
|
# Whether a money symbol should be prepended to the result string. The default is true.
|
229
234
|
# This method attempts to pick a symbol that's suitable for the given currency.
|
230
235
|
#
|
231
|
-
#
|
232
|
-
#
|
233
|
-
#
|
234
|
-
#
|
235
|
-
#
|
236
|
-
#
|
237
|
-
#
|
238
|
-
#
|
236
|
+
# Money.new(100, "USD") => "$1.00"
|
237
|
+
# Money.new(100, "GBP") => "£1.00"
|
238
|
+
# Money.new(100, "EUR") => "€1.00"
|
239
|
+
#
|
240
|
+
# # Same thing.
|
241
|
+
# Money.new(100, "USD").format(:symbol => true) => "$1.00"
|
242
|
+
# Money.new(100, "GBP").format(:symbol => true) => "£1.00"
|
243
|
+
# Money.new(100, "EUR").format(:symbol => true) => "€1.00"
|
239
244
|
#
|
240
245
|
# You can specify a false expression or an empty string to disable prepending
|
241
246
|
# a money symbol:
|
242
247
|
#
|
243
|
-
#
|
244
|
-
#
|
245
|
-
#
|
248
|
+
# Money.new(100, "USD").format(:symbol => false) => "1.00"
|
249
|
+
# Money.new(100, "GBP").format(:symbol => nil) => "1.00"
|
250
|
+
# Money.new(100, "EUR").format(:symbol => "") => "1.00"
|
251
|
+
#
|
246
252
|
#
|
247
|
-
#
|
248
253
|
# If the symbol for the given currency isn't known, then it will default
|
249
254
|
# to "$" as symbol:
|
250
255
|
#
|
251
|
-
#
|
256
|
+
# Money.new(100, "AWG").format(:symbol => true) => "$1.00"
|
252
257
|
#
|
253
258
|
# You can specify a string as value to enforce using a particular symbol:
|
254
259
|
#
|
255
|
-
#
|
260
|
+
# Money.new(100, "AWG").format(:symbol => "ƒ") => "ƒ1.00"
|
256
261
|
#
|
257
262
|
# === +:separator+
|
258
263
|
#
|
@@ -260,42 +265,42 @@ class Money
|
|
260
265
|
#
|
261
266
|
# If a string is specified, it's value is used:
|
262
267
|
#
|
263
|
-
#
|
268
|
+
# Money.new(100, "USD").format(:separator => ",") => "$1,00"
|
264
269
|
#
|
265
270
|
# If the separator for a given currency isn't known, then it will default to
|
266
271
|
# "." as separator:
|
267
272
|
#
|
268
|
-
#
|
273
|
+
# Money.new(100, "FOO").format => "$1.00"
|
269
274
|
#
|
270
275
|
# === +:delimiter+
|
271
276
|
#
|
272
277
|
# Whether the currency should be delimited by the specified character or ','
|
273
278
|
#
|
274
279
|
# If false is specified, no delimiter is used:
|
275
|
-
#
|
276
|
-
#
|
277
|
-
#
|
278
|
-
#
|
280
|
+
#
|
281
|
+
# Money.new(100000, "USD").format(:delimiter => false) => "1000.00"
|
282
|
+
# Money.new(100000, "USD").format(:delimiter => nil) => "1000.00"
|
283
|
+
# Money.new(100000, "USD").format(:delimiter => "") => "1000.00"
|
279
284
|
#
|
280
285
|
# If a string is specified, it's value is used:
|
281
286
|
#
|
282
|
-
#
|
287
|
+
# Money.new(100000, "USD").format(:delimiter => ".") => "$1.000.00"
|
283
288
|
#
|
284
289
|
# If the delimiter for a given currency isn't known, then it will default to
|
285
290
|
# "," as delimiter:
|
286
291
|
#
|
287
|
-
#
|
292
|
+
# Money.new(100000, "FOO").format => "$1,000.00"
|
288
293
|
#
|
289
294
|
# === +:html+
|
290
295
|
#
|
291
296
|
# Whether the currency should be HTML-formatted. Only useful in combination with +:with_currency+.
|
292
297
|
#
|
293
|
-
#
|
294
|
-
#
|
298
|
+
# Money.ca_dollar(570).format(:html => true, :with_currency => true)
|
299
|
+
# # => "$5.70 <span class=\"currency\">CAD</span>"
|
295
300
|
def format(*rules)
|
296
301
|
# support for old format parameters
|
297
302
|
rules = normalize_formatting_rules(rules)
|
298
|
-
|
303
|
+
|
299
304
|
if cents == 0
|
300
305
|
if rules[:display_free].respond_to?(:to_str)
|
301
306
|
return rules[:display_free]
|
@@ -352,10 +357,11 @@ class Money
|
|
352
357
|
end
|
353
358
|
formatted
|
354
359
|
end
|
355
|
-
|
360
|
+
|
356
361
|
# Returns the amount of money as a string.
|
357
362
|
#
|
358
|
-
#
|
363
|
+
# Money.ca_dollar(100).to_s => "1.00"
|
364
|
+
#
|
359
365
|
def to_s
|
360
366
|
sprintf("%.2f", cents / 100.00)
|
361
367
|
end
|
@@ -365,12 +371,13 @@ class Money
|
|
365
371
|
# need to represent currency or working with another system that requires
|
366
372
|
# decimals.
|
367
373
|
#
|
368
|
-
#
|
374
|
+
# Money.us_dollar(100).to_f => 1.0
|
375
|
+
#
|
369
376
|
def to_f
|
370
377
|
cents / 100.0
|
371
378
|
end
|
372
379
|
|
373
|
-
#
|
380
|
+
# Receive the amount of this money object in another Currency.
|
374
381
|
# <tt>other_currency</tt> can be either a <tt>String</tt>
|
375
382
|
# or a <tt>Currency</tt> instance.
|
376
383
|
#
|
@@ -382,31 +389,31 @@ class Money
|
|
382
389
|
Money.new(@bank.exchange(self.cents, currency, other_currency), other_currency)
|
383
390
|
end
|
384
391
|
|
385
|
-
#
|
386
|
-
# in american dollar
|
392
|
+
# Receive a money object with the same amount as the current Money object
|
393
|
+
# in american dollar
|
387
394
|
def as_us_dollar
|
388
395
|
exchange_to("USD")
|
389
396
|
end
|
390
|
-
|
391
|
-
#
|
392
|
-
# in canadian dollar
|
397
|
+
|
398
|
+
# Receive a money object with the same amount as the current Money object
|
399
|
+
# in canadian dollar
|
393
400
|
def as_ca_dollar
|
394
401
|
exchange_to("CAD")
|
395
402
|
end
|
396
|
-
|
397
|
-
#
|
403
|
+
|
404
|
+
# Receive a money object with the same amount as the current Money object
|
398
405
|
# in euro
|
399
406
|
def as_euro
|
400
407
|
exchange_to("EUR")
|
401
408
|
end
|
402
|
-
|
409
|
+
|
403
410
|
# Conversation to self
|
404
411
|
def to_money
|
405
412
|
self
|
406
413
|
end
|
407
|
-
|
414
|
+
|
408
415
|
private
|
409
|
-
|
416
|
+
|
410
417
|
def normalize_formatting_rules(rules)
|
411
418
|
if rules.size == 1
|
412
419
|
rules = rules.pop
|
@@ -9,14 +9,15 @@ require 'money/errors'
|
|
9
9
|
# One must manually specify them with +add_rate+, after which one can perform
|
10
10
|
# exchanges with +exchange+. For example:
|
11
11
|
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
12
|
+
# bank = Money::VariableExchangeBank.new
|
13
|
+
# bank.add_rate("USD", "CAD", 1.24515)
|
14
|
+
# bank.add_rate("CAD", "USD", 0.803115)
|
15
|
+
#
|
16
|
+
# # Exchange 100 CAD to USD:
|
17
|
+
# bank.exchange(100_00, "CAD", "USD") # => 124
|
18
|
+
# # Exchange 100 USD to CAD:
|
19
|
+
# bank.exchange(100_00, "USD", "CAD") # => 80
|
20
|
+
#
|
20
21
|
class Money
|
21
22
|
class VariableExchangeBank
|
22
23
|
# Returns the singleton instance of VariableExchangeBank.
|
@@ -25,27 +26,27 @@ class Money
|
|
25
26
|
def self.instance
|
26
27
|
@@singleton
|
27
28
|
end
|
28
|
-
|
29
|
+
|
29
30
|
def initialize
|
30
31
|
@rates = {}
|
31
32
|
@mutex = Mutex.new
|
32
33
|
end
|
33
|
-
|
34
|
+
|
34
35
|
# Registers a conversion rate. +from+ and +to+ are both currency names.
|
35
36
|
def add_rate(from, to, rate)
|
36
37
|
@mutex.synchronize do
|
37
38
|
@rates["#{from}_TO_#{to}".upcase] = rate
|
38
39
|
end
|
39
40
|
end
|
40
|
-
|
41
|
+
|
41
42
|
# Gets the rate for exchanging the currency named +from+ to the currency
|
42
43
|
# named +to+. Returns nil if the rate is unknown.
|
43
44
|
def get_rate(from, to)
|
44
45
|
@mutex.synchronize do
|
45
|
-
@rates["#{from}_TO_#{to}".upcase]
|
46
|
+
@rates["#{from}_TO_#{to}".upcase]
|
46
47
|
end
|
47
48
|
end
|
48
|
-
|
49
|
+
|
49
50
|
# Given two currency names, checks whether they're both the same currency.
|
50
51
|
#
|
51
52
|
# bank = VariableExchangeBank.new
|
@@ -54,7 +55,7 @@ class Money
|
|
54
55
|
def same_currency?(currency1, currency2)
|
55
56
|
Currency.wrap(currency1) == Currency.wrap(currency2)
|
56
57
|
end
|
57
|
-
|
58
|
+
|
58
59
|
# Exchange the given amount of cents in +from_currency+ to +to_currency+.
|
59
60
|
# Returns the amount of cents in +to_currency+ as an integer, rounded down.
|
60
61
|
#
|
@@ -66,7 +67,7 @@ class Money
|
|
66
67
|
end
|
67
68
|
(cents * rate).floor
|
68
69
|
end
|
69
|
-
|
70
|
+
|
70
71
|
@@singleton = VariableExchangeBank.new
|
71
72
|
end
|
72
73
|
end
|
data/money.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{money}
|
8
|
-
s.version = "
|
8
|
+
s.version = "3.0.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Tobias Luetke", "Hongli Lai", "Jeremy McNevin", "Shane Emmons"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-05-07}
|
13
13
|
s.description = %q{Money and currency exchange support library.}
|
14
14
|
s.email = %q{hongli@phusion.nl}
|
15
15
|
s.extra_rdoc_files = [
|
data/test/currency_spec.rb
CHANGED
@@ -55,7 +55,7 @@ describe Money::Currency do
|
|
55
55
|
with_custom_definitions do
|
56
56
|
Money::Currency::TABLE[:usd] = { :priority => 1, :iso_code => "USD", :name => "United States Dollar", :symbol => "$", :subunit => "Cent", :subunit_to_unit => "100" }
|
57
57
|
Money::Currency::TABLE[:eur] = { :priority => 2, :iso_code => "EUR", :name => "Euro", :symbol => "€", :subunit => "Cent", :subunit_to_unit => "100" }
|
58
|
-
|
58
|
+
|
59
59
|
expected = Money::Currency.new(:eur)
|
60
60
|
Money::Currency.find(:eur).should == expected
|
61
61
|
Money::Currency.find(:EUR).should == expected
|
@@ -63,12 +63,12 @@ describe Money::Currency do
|
|
63
63
|
Money::Currency.find("EUR").should == expected
|
64
64
|
end
|
65
65
|
end
|
66
|
-
|
66
|
+
|
67
67
|
specify "#self.find should return nil unless currency matching given id" do
|
68
68
|
with_custom_definitions do
|
69
69
|
Money::Currency::TABLE[:usd] = { :position => 1, :iso_code => "USD", :name => "United States Dollar", :symbol => "$", :subunit => "Cent", :subunit_to_unit => "100" }
|
70
70
|
Money::Currency::TABLE[:eur] = { :position => 2, :iso_code => "EUR", :name => "Euro", :symbol => "€", :subunit => "Cent", :subunit_to_unit => "100" }
|
71
|
-
|
71
|
+
|
72
72
|
expected = Money::Currency.new(:eur)
|
73
73
|
Money::Currency.find(:eur).should == expected
|
74
74
|
Money::Currency.find(:EUR).should == expected
|
data/test/exchange_bank_spec.rb
CHANGED
@@ -5,14 +5,14 @@ describe Money::VariableExchangeBank do
|
|
5
5
|
before :each do
|
6
6
|
@bank = Money::VariableExchangeBank.new
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
it "returns the previously specified conversion rate" do
|
10
10
|
@bank.add_rate("USD", "EUR", 0.788332676)
|
11
11
|
@bank.add_rate("EUR", "YEN", 122.631477)
|
12
12
|
@bank.get_rate("USD", "EUR").should == 0.788332676
|
13
13
|
@bank.get_rate("EUR", "YEN").should == 122.631477
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
it "treats currency names case-insensitively" do
|
17
17
|
@bank.add_rate("usd", "eur", 1)
|
18
18
|
@bank.get_rate("USD", "EUR").should == 1
|
@@ -23,21 +23,21 @@ describe Money::VariableExchangeBank do
|
|
23
23
|
it "returns nil if the conversion rate is unknown" do
|
24
24
|
@bank.get_rate("American Pesos", "EUR").should be_nil
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
it "exchanges money from one currency to another according to the specified conversion rates" do
|
28
28
|
@bank.add_rate("USD", "EUR", 0.5)
|
29
29
|
@bank.add_rate("EUR", "YEN", 10)
|
30
30
|
@bank.exchange(10_00, "USD", "EUR").should == 5_00
|
31
31
|
@bank.exchange(500_00, "EUR", "YEN").should == 5000_00
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
it "rounds the exchanged result down" do
|
35
35
|
@bank.add_rate("USD", "EUR", 0.788332676)
|
36
36
|
@bank.add_rate("EUR", "YEN", 122.631477)
|
37
37
|
@bank.exchange(10_00, "USD", "EUR").should == 788
|
38
38
|
@bank.exchange(500_00, "EUR", "YEN").should == 6131573
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
it "raises Money::UnknownRate upon conversion if the conversion rate is unknown" do
|
42
42
|
block = lambda { @bank.exchange(10, "USD", "EUR") }
|
43
43
|
block.should raise_error(Money::UnknownRate)
|
data/test/money_spec.rb
CHANGED
@@ -7,11 +7,11 @@ describe Money do
|
|
7
7
|
it "is associated to the singleton instance of VariableExchangeBank by default" do
|
8
8
|
Money.new(0).bank.object_id.should == Money::VariableExchangeBank.instance.object_id
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
specify "#cents returns the amount of cents passed to the constructor" do
|
12
12
|
Money.new(200_00, "USD").cents.should == 200_00
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
it "rounds the given cents to an integer" do
|
16
16
|
Money.new(1.00, "USD").cents.should == 1
|
17
17
|
Money.new(1.01, "USD").cents.should == 1
|
@@ -21,7 +21,7 @@ describe Money do
|
|
21
21
|
specify "#currency returns the currency passed to the constructor" do
|
22
22
|
Money.new(200_00, "USD").currency.should == Money::Currency.new("USD")
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
specify "#zero? returns whether the amount is 0" do
|
26
26
|
Money.new(0, "USD").should be_zero
|
27
27
|
Money.new(0, "EUR").should be_zero
|
@@ -29,56 +29,71 @@ describe Money do
|
|
29
29
|
Money.new(10, "YEN").should_not be_zero
|
30
30
|
Money.new(-1, "EUR").should_not be_zero
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
|
+
specify "#nonzero? returns whether the amount is not 0" do
|
34
|
+
Money.new(0, "USD").should_not be_nonzero
|
35
|
+
Money.new(0, "EUR").should_not be_nonzero
|
36
|
+
Money.new(1, "USD").should be_nonzero
|
37
|
+
Money.new(10, "YEN").should be_nonzero
|
38
|
+
Money.new(-1, "EUR").should be_nonzero
|
39
|
+
end
|
40
|
+
|
41
|
+
specify "#nonzero? has the same return-value semantics as Numeric#nonzero?" do
|
42
|
+
Money.new(0, "USD").nonzero?.should be_nil
|
43
|
+
|
44
|
+
money = Money.new(1, "USD")
|
45
|
+
money.nonzero?.should be_equal(money)
|
46
|
+
end
|
47
|
+
|
33
48
|
specify "#exchange_to exchanges the amount via its exchange bank" do
|
34
49
|
money = Money.new(100_00, "USD")
|
35
50
|
money.bank.should_receive(:exchange).with(100_00, Money::Currency.new("USD"), Money::Currency.new("EUR")).and_return(200_00)
|
36
51
|
money.exchange_to("EUR")
|
37
52
|
end
|
38
|
-
|
53
|
+
|
39
54
|
specify "#exchange_to exchanges the amount properly" do
|
40
55
|
money = Money.new(100_00, "USD")
|
41
56
|
money.bank.should_receive(:exchange).with(100_00, Money::Currency.new("USD"), Money::Currency.new("EUR")).and_return(200_00)
|
42
57
|
money.exchange_to("EUR").should == Money.new(200_00, "EUR")
|
43
58
|
end
|
44
|
-
|
59
|
+
|
45
60
|
specify "#== returns true if and only if their amount and currency are equal" do
|
46
61
|
Money.new(1_00, "USD").should == Money.new(1_00, "USD")
|
47
62
|
Money.new(1_00, "USD").should_not == Money.new(1_00, "EUR")
|
48
63
|
Money.new(1_00, "USD").should_not == Money.new(2_00, "USD")
|
49
64
|
Money.new(1_00, "USD").should_not == Money.new(99_00, "EUR")
|
50
65
|
end
|
51
|
-
|
66
|
+
|
52
67
|
specify "#== can be used to compare with a String money value" do
|
53
68
|
Money.new(1_00, "USD").should == "1.00"
|
54
69
|
Money.new(1_00, "USD").should_not == "2.00"
|
55
70
|
Money.new(1_00, "GBP").should_not == "1.00"
|
56
71
|
end
|
57
|
-
|
72
|
+
|
58
73
|
specify "#== can be used to compare with a Numeric money value" do
|
59
74
|
Money.new(1_00, "USD").should == 1
|
60
75
|
Money.new(1_57, "USD").should == 1.57
|
61
76
|
Money.new(1_00, "USD").should_not == 2
|
62
77
|
Money.new(1_00, "GBP").should_not == 1
|
63
78
|
end
|
64
|
-
|
79
|
+
|
65
80
|
specify "#== can be used to compare with an object that responds to #to_money" do
|
66
81
|
klass = Class.new do
|
67
82
|
def initialize(money)
|
68
83
|
@money = money
|
69
84
|
end
|
70
|
-
|
85
|
+
|
71
86
|
def to_money
|
72
87
|
@money
|
73
88
|
end
|
74
89
|
end
|
75
|
-
|
90
|
+
|
76
91
|
Money.new(1_00, "USD").should == klass.new(Money.new(1_00, "USD"))
|
77
92
|
Money.new(2_50, "USD").should == klass.new(Money.new(2_50, "USD"))
|
78
93
|
Money.new(2_50, "USD").should_not == klass.new(Money.new(3_00, "USD"))
|
79
94
|
Money.new(1_00, "GBP").should_not == klass.new(Money.new(1_00, "USD"))
|
80
95
|
end
|
81
|
-
|
96
|
+
|
82
97
|
specify "#== returns false if used to compare with an object that doesn't respond to #to_money" do
|
83
98
|
Money.new(1_00, "USD").should_not == Object.new
|
84
99
|
Money.new(1_00, "USD").should_not == Class
|
@@ -86,35 +101,35 @@ describe Money do
|
|
86
101
|
Money.new(1_00, "USD").should_not == /foo/
|
87
102
|
Money.new(1_00, "USD").should_not == nil
|
88
103
|
end
|
89
|
-
|
104
|
+
|
90
105
|
specify "#<=> can be used to compare with a String money value" do
|
91
106
|
(Money.new(1_00) <=> "1.00").should == 0
|
92
107
|
(Money.new(1_00) <=> ".99").should > 0
|
93
108
|
(Money.new(1_00) <=> "2.00").should < 0
|
94
109
|
end
|
95
|
-
|
110
|
+
|
96
111
|
specify "#<=> can be used to compare with a Numeric money value" do
|
97
112
|
(Money.new(1_00) <=> 1).should == 0
|
98
113
|
(Money.new(1_00) <=> 0.99).should > 0
|
99
114
|
(Money.new(1_00) <=> 2.00).should < 0
|
100
115
|
end
|
101
|
-
|
116
|
+
|
102
117
|
specify "#<=> can be used to compare with an object that responds to #to_money" do
|
103
118
|
klass = Class.new do
|
104
119
|
def initialize(money)
|
105
120
|
@money = money
|
106
121
|
end
|
107
|
-
|
122
|
+
|
108
123
|
def to_money
|
109
124
|
@money
|
110
125
|
end
|
111
126
|
end
|
112
|
-
|
127
|
+
|
113
128
|
(Money.new(1_00) <=> klass.new(Money.new(1_00))).should == 0
|
114
129
|
(Money.new(1_00) <=> klass.new(Money.new(99))).should > 0
|
115
130
|
(Money.new(1_00) <=> klass.new(Money.new(2_00))).should < 0
|
116
131
|
end
|
117
|
-
|
132
|
+
|
118
133
|
specify "#<=> raises ArgumentError when used to compare with an object that doesn't respond to #to_money" do
|
119
134
|
expected_message = /comparison .+ failed/
|
120
135
|
lambda{ Money.new(1_00) <=> Object.new }.should raise_error(ArgumentError, expected_message)
|
@@ -122,39 +137,39 @@ describe Money do
|
|
122
137
|
lambda{ Money.new(1_00) <=> Kernel }.should raise_error(ArgumentError, expected_message)
|
123
138
|
lambda{ Money.new(1_00) <=> /foo/ }.should raise_error(ArgumentError, expected_message)
|
124
139
|
end
|
125
|
-
|
140
|
+
|
126
141
|
specify "#* multiplies the money's amount by the multiplier while retaining the currency" do
|
127
142
|
(Money.new(1_00, "USD") * 10).should == Money.new(10_00, "USD")
|
128
143
|
end
|
129
|
-
|
144
|
+
|
130
145
|
specify "#/ divides the money's amount by the divisor while retaining the currency" do
|
131
146
|
(Money.new(10_00, "USD") / 10).should == Money.new(1_00, "USD")
|
132
147
|
end
|
133
|
-
|
148
|
+
|
134
149
|
specify "Money.empty creates a new Money object of 0 cents" do
|
135
150
|
Money.empty.should == Money.new(0)
|
136
151
|
end
|
137
|
-
|
152
|
+
|
138
153
|
specify "Money.ca_dollar creates a new Money object of the given value in CAD" do
|
139
154
|
Money.ca_dollar(50).should == Money.new(50, "CAD")
|
140
155
|
end
|
141
|
-
|
156
|
+
|
142
157
|
specify "Money.ca_dollar creates a new Money object of the given value in USD" do
|
143
158
|
Money.us_dollar(50).should == Money.new(50, "USD")
|
144
159
|
end
|
145
|
-
|
160
|
+
|
146
161
|
specify "Money.ca_dollar creates a new Money object of the given value in EUR" do
|
147
162
|
Money.euro(50).should == Money.new(50, "EUR")
|
148
163
|
end
|
149
|
-
|
164
|
+
|
150
165
|
specify "Money.new accepts { :currency => 'foo' } as the value for the 'currency' argument" do
|
151
166
|
money = Money.new(20, :currency => "EUR")
|
152
167
|
money.currency.should == Money::Currency.new("EUR")
|
153
|
-
|
168
|
+
|
154
169
|
money = Money.new(20, :currency => nil)
|
155
170
|
money.currency.should == Money.default_currency
|
156
171
|
end
|
157
|
-
|
172
|
+
|
158
173
|
specify "Money.add_rate works" do
|
159
174
|
Money.add_rate("EUR", "USD", 10)
|
160
175
|
Money.new(10_00, "EUR").exchange_to("USD").should == Money.new(100_00, "USD")
|
@@ -167,7 +182,7 @@ describe Money do
|
|
167
182
|
specify "Money.to_f works" do
|
168
183
|
Money.new(10_00).to_f.should == 10.0
|
169
184
|
end
|
170
|
-
|
185
|
+
|
171
186
|
describe "#format" do
|
172
187
|
it "returns the monetary value as a string" do
|
173
188
|
Money.ca_dollar(100).format.should == "$1.00"
|
@@ -180,50 +195,50 @@ describe Money do
|
|
180
195
|
|
181
196
|
# Pounds
|
182
197
|
one_thousand["GBP"].should == "£1,000.00"
|
183
|
-
|
198
|
+
|
184
199
|
# Dollars
|
185
200
|
one_thousand["USD"].should == "$1,000.00"
|
186
201
|
one_thousand["CAD"].should == "$1,000.00"
|
187
202
|
one_thousand["AUD"].should == "$1,000.00"
|
188
203
|
one_thousand["NZD"].should == "$1,000.00"
|
189
204
|
one_thousand["ZWD"].should == "$1,000.00"
|
190
|
-
|
205
|
+
|
191
206
|
# Yen
|
192
|
-
one_thousand["JPY"].should == "¥1,000.00"
|
193
|
-
one_thousand["CNY"].should == "¥1,000.00"
|
194
|
-
|
207
|
+
one_thousand["JPY"].should == "¥1,000.00"
|
208
|
+
one_thousand["CNY"].should == "¥1,000.00"
|
209
|
+
|
195
210
|
# Euro
|
196
211
|
one_thousand["EUR"].should == "€1,000.00"
|
197
|
-
|
212
|
+
|
198
213
|
# Rupees
|
199
214
|
one_thousand["INR"].should == "₨1,000.00"
|
200
215
|
one_thousand["NPR"].should == "₨1,000.00"
|
201
216
|
one_thousand["SCR"].should == "₨1,000.00"
|
202
217
|
one_thousand["LKR"].should == "₨1,000.00"
|
203
|
-
|
218
|
+
|
204
219
|
# Brazilian Real
|
205
220
|
one_thousand["BRL"].should == "R$ 1.000,00"
|
206
|
-
|
221
|
+
|
207
222
|
# Other
|
208
223
|
one_thousand["SEK"].should == "kr1,000.00"
|
209
224
|
one_thousand["GHC"].should == "₵1,000.00"
|
210
225
|
end
|
211
|
-
|
226
|
+
|
212
227
|
describe "if the monetary value is 0" do
|
213
228
|
before :each do
|
214
229
|
@money = Money.us_dollar(0)
|
215
230
|
end
|
216
|
-
|
231
|
+
|
217
232
|
it "returns 'free' when :display_free is true" do
|
218
233
|
@money.format(:display_free => true).should == 'free'
|
219
234
|
end
|
220
|
-
|
235
|
+
|
221
236
|
it "returns '$0.00' when :display_free is false or not given" do
|
222
237
|
@money.format.should == '$0.00'
|
223
238
|
@money.format(:display_free => false).should == '$0.00'
|
224
239
|
@money.format(:display_free => nil).should == '$0.00'
|
225
240
|
end
|
226
|
-
|
241
|
+
|
227
242
|
it "returns the value specified by :display_free if it's a string-like object" do
|
228
243
|
@money.format(:display_free => 'gratis').should == 'gratis'
|
229
244
|
end
|
@@ -255,7 +270,7 @@ describe Money do
|
|
255
270
|
end
|
256
271
|
end
|
257
272
|
end
|
258
|
-
|
273
|
+
|
259
274
|
specify "#separator works as documented" do
|
260
275
|
begin
|
261
276
|
old = Money::SEPARATORS.dup
|
@@ -277,12 +292,12 @@ describe Money do
|
|
277
292
|
Money.us_dollar(85).format(:with_currency => true).should == "$0.85 USD"
|
278
293
|
Money.us_dollar(85).format(:with_currency).should == "$0.85 USD"
|
279
294
|
end
|
280
|
-
|
295
|
+
|
281
296
|
specify "#format(:with_currency) works as documented" do
|
282
297
|
Money.ca_dollar(100).format(:with_currency).should == "$1.00 CAD"
|
283
298
|
Money.us_dollar(85).format(:with_currency).should == "$0.85 USD"
|
284
299
|
end
|
285
|
-
|
300
|
+
|
286
301
|
specify "#format(:no_cents => true) works as documented" do
|
287
302
|
Money.ca_dollar(100).format(:no_cents => true).should == "$1"
|
288
303
|
Money.ca_dollar(599).format(:no_cents => true).should == "$5"
|
@@ -296,11 +311,11 @@ describe Money do
|
|
296
311
|
Money.ca_dollar(570).format(:no_cents, :with_currency).should == "$5 CAD"
|
297
312
|
Money.ca_dollar(39000).format(:no_cents).should == "$390"
|
298
313
|
end
|
299
|
-
|
314
|
+
|
300
315
|
specify "#format(:symbol => a symbol string) uses the given value as the money symbol" do
|
301
316
|
Money.new(100, "GBP").format(:symbol => "£").should == "£1.00"
|
302
317
|
end
|
303
|
-
|
318
|
+
|
304
319
|
specify "#format(:symbol => true) returns symbol based on the given currency code" do
|
305
320
|
one = Proc.new do |currency|
|
306
321
|
Money.new(100, currency).format(:symbol => true)
|
@@ -308,61 +323,61 @@ describe Money do
|
|
308
323
|
|
309
324
|
# Pounds
|
310
325
|
one["GBP"].should == "£1.00"
|
311
|
-
|
326
|
+
|
312
327
|
# Dollars
|
313
328
|
one["USD"].should == "$1.00"
|
314
329
|
one["CAD"].should == "$1.00"
|
315
330
|
one["AUD"].should == "$1.00"
|
316
331
|
one["NZD"].should == "$1.00"
|
317
332
|
one["ZWD"].should == "$1.00"
|
318
|
-
|
333
|
+
|
319
334
|
# Yen
|
320
|
-
one["JPY"].should == "¥1.00"
|
321
|
-
one["CNY"].should == "¥1.00"
|
322
|
-
|
335
|
+
one["JPY"].should == "¥1.00"
|
336
|
+
one["CNY"].should == "¥1.00"
|
337
|
+
|
323
338
|
# Euro
|
324
339
|
one["EUR"].should == "€1.00"
|
325
|
-
|
340
|
+
|
326
341
|
# Rupees
|
327
342
|
one["INR"].should == "₨1.00"
|
328
343
|
one["NPR"].should == "₨1.00"
|
329
344
|
one["SCR"].should == "₨1.00"
|
330
345
|
one["LKR"].should == "₨1.00"
|
331
|
-
|
346
|
+
|
332
347
|
# Brazilian Real
|
333
348
|
one["BRL"].should == "R$ 1,00"
|
334
|
-
|
349
|
+
|
335
350
|
# Other
|
336
351
|
one["SEK"].should == "kr1.00"
|
337
352
|
one["GHC"].should == "₵1.00"
|
338
353
|
end
|
339
|
-
|
354
|
+
|
340
355
|
specify "#format(:symbol => true) returns $ when currency code is not recognized" do
|
341
356
|
currency = Money::Currency.new("EUR")
|
342
357
|
currency.should_receive(:symbol).and_return(nil)
|
343
358
|
Money.new(100, currency).format(:symbol => true).should == "$1.00"
|
344
359
|
end
|
345
|
-
|
360
|
+
|
346
361
|
specify "#format(:symbol => some non-Boolean value that evaluates to true) returs symbol based on the given currency code" do
|
347
362
|
Money.new(100, "GBP").format(:symbol => true).should == "£1.00"
|
348
363
|
Money.new(100, "EUR").format(:symbol => true).should == "€1.00"
|
349
364
|
Money.new(100, "SEK").format(:symbol => true).should == "kr1.00"
|
350
365
|
end
|
351
|
-
|
366
|
+
|
352
367
|
specify "#format with :symbol == "", nil or false returns the amount without a symbol" do
|
353
368
|
money = Money.new(100, "GBP")
|
354
369
|
money.format(:symbol => "").should == "1.00"
|
355
370
|
money.format(:symbol => nil).should == "1.00"
|
356
371
|
money.format(:symbol => false).should == "1.00"
|
357
372
|
end
|
358
|
-
|
373
|
+
|
359
374
|
specify "#format without :symbol assumes that :symbol is set to true" do
|
360
375
|
money = Money.new(100)
|
361
376
|
money.format.should == "$1.00"
|
362
|
-
|
377
|
+
|
363
378
|
money = Money.new(100, "GBP")
|
364
379
|
money.format.should == "£1.00"
|
365
|
-
|
380
|
+
|
366
381
|
money = Money.new(100, "EUR")
|
367
382
|
money.format.should == "€1.00"
|
368
383
|
end
|
@@ -388,12 +403,12 @@ describe Money do
|
|
388
403
|
specify "#format will default delimiter to ',' if currency isn't recognized" do
|
389
404
|
Money.new(100000, "ZWD").format.should == "$1,000.00"
|
390
405
|
end
|
391
|
-
|
406
|
+
|
392
407
|
specify "#format(:html => true) works as documented" do
|
393
408
|
string = Money.ca_dollar(570).format(:html => true, :with_currency => true)
|
394
409
|
string.should == "$5.70 <span class=\"currency\">CAD</span>"
|
395
410
|
end
|
396
|
-
|
411
|
+
|
397
412
|
it "should insert commas into the result if the amount is sufficiently large" do
|
398
413
|
Money.us_dollar(1_000_000_000_12).format.should == "$1,000,000,000.12"
|
399
414
|
Money.us_dollar(1_000_000_000_12).format(:no_cents => true).should == "$1,000,000,000"
|
@@ -424,11 +439,11 @@ describe "Actions involving two Money objects" do
|
|
424
439
|
(Money.new(1_00, "USD") <=> Money.new(99, "USD")).should > 0
|
425
440
|
(Money.new(1_00, "USD") <=> Money.new(2_00, "USD")).should < 0
|
426
441
|
end
|
427
|
-
|
442
|
+
|
428
443
|
specify "#+ adds the other object's amount to the current object's amount while retaining the currency" do
|
429
444
|
(Money.new(10_00, "USD") + Money.new(90, "USD")).should == Money.new(10_90, "USD")
|
430
445
|
end
|
431
|
-
|
446
|
+
|
432
447
|
specify "#- substracts the other object's amount from the current object's amount while retaining the currency" do
|
433
448
|
(Money.new(10_00, "USD") - Money.new(90, "USD")).should == Money.new(9_10, "USD")
|
434
449
|
end
|
@@ -437,28 +452,28 @@ describe "Actions involving two Money objects" do
|
|
437
452
|
(Money.new(10_00, "USD") / Money.new(100_00, "USD")).should == 0.1
|
438
453
|
end
|
439
454
|
end
|
440
|
-
|
455
|
+
|
441
456
|
describe "if the other Money object has a different currency" do
|
442
457
|
specify "#<=> compares the two objects' amount after converting the other object's amount to its own currency" do
|
443
458
|
target = Money.new(200_00, "EUR")
|
444
459
|
target.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(300_00, "USD"))
|
445
460
|
(Money.new(100_00, "USD") <=> target).should < 0
|
446
|
-
|
461
|
+
|
447
462
|
target = Money.new(200_00, "EUR")
|
448
463
|
target.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(100_00, "USD"))
|
449
464
|
(Money.new(100_00, "USD") <=> target).should == 0
|
450
|
-
|
465
|
+
|
451
466
|
target = Money.new(200_00, "EUR")
|
452
467
|
target.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(99_00, "USD"))
|
453
468
|
(Money.new(100_00, "USD") <=> target).should > 0
|
454
469
|
end
|
455
|
-
|
470
|
+
|
456
471
|
specify "#+ adds the other object's amount, converted to this object's currency, to this object's amount while retaining its currency" do
|
457
472
|
other = Money.new(90, "EUR")
|
458
473
|
other.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(9_00, "USD"))
|
459
474
|
(Money.new(10_00, "USD") + other).should == Money.new(19_00, "USD")
|
460
475
|
end
|
461
|
-
|
476
|
+
|
462
477
|
specify "#- substracts the other object's amount, converted to this object's currency, from this object's amount while retaining its currency" do
|
463
478
|
other = Money.new(90, "EUR")
|
464
479
|
other.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(9_00, "USD"))
|
metadata
CHANGED
@@ -3,10 +3,10 @@ name: money
|
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
|
-
- 2
|
7
6
|
- 3
|
8
7
|
- 0
|
9
|
-
|
8
|
+
- 0
|
9
|
+
version: 3.0.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Tobias Luetke
|
@@ -17,7 +17,7 @@ autorequire:
|
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
19
|
|
20
|
-
date: 2010-
|
20
|
+
date: 2010-05-07 00:00:00 -04:00
|
21
21
|
default_executable:
|
22
22
|
dependencies:
|
23
23
|
- !ruby/object:Gem::Dependency
|