money 2.3.0 → 3.0.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/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
|