money 2.2.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +9 -0
- data/README.rdoc +92 -10
- data/Rakefile +7 -2
- data/VERSION +1 -1
- data/lib/money/core_extensions.rb +7 -1
- data/lib/money/currency.rb +289 -0
- data/lib/money/defaults.rb +55 -29
- data/lib/money/money.rb +58 -24
- data/lib/money/variable_exchange_bank.rb +1 -1
- data/money.gemspec +9 -4
- data/test/core_extensions_spec.rb +18 -6
- data/test/currency_spec.rb +113 -0
- data/test/money_spec.rb +80 -19
- metadata +33 -13
data/lib/money/defaults.rb
CHANGED
@@ -1,31 +1,57 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
}
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
#
|
31
|
-
|
3
|
+
class Money
|
4
|
+
|
5
|
+
class DeprecatedHash < Hash
|
6
|
+
|
7
|
+
def initialize(hash, message)
|
8
|
+
@message = message
|
9
|
+
replace(hash)
|
10
|
+
end
|
11
|
+
|
12
|
+
def [](key)
|
13
|
+
deprecate
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
def []=(value)
|
18
|
+
deprecate
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def deprecate
|
25
|
+
warn "DEPRECATION MESSAGE: #{@message}"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
# @deprecated See Money::Currency#symbol
|
31
|
+
SYMBOLS = DeprecatedHash.new({
|
32
|
+
"GBP" => "£",
|
33
|
+
"JPY" => "¥",
|
34
|
+
"EUR" => "€",
|
35
|
+
"ZWD" => "Z$",
|
36
|
+
"CNY" => "¥",
|
37
|
+
"INR" => "₨",
|
38
|
+
"NPR" => "₨",
|
39
|
+
"SCR" => "₨",
|
40
|
+
"LKR" => "₨",
|
41
|
+
"SEK" => "kr",
|
42
|
+
"GHC" => "¢",
|
43
|
+
"BRL" => "R$ ",
|
44
|
+
# Everything else defaults to '$'
|
45
|
+
}, "Money::SYMBOLS has no longer effect. See Money::Currency#symbol.")
|
46
|
+
|
47
|
+
SEPARATORS = {
|
48
|
+
"BRL" => ",",
|
49
|
+
# Everything else defaults to '.'
|
50
|
+
}
|
51
|
+
|
52
|
+
DELIMITERS = {
|
53
|
+
"BRL" => ".",
|
54
|
+
# Everything else defaults to ","
|
55
|
+
}
|
56
|
+
|
57
|
+
end
|
data/lib/money/money.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'money/currency'
|
1
3
|
require 'money/variable_exchange_bank'
|
2
4
|
|
3
5
|
# Represents an amount of money in a certain currency.
|
@@ -5,7 +7,7 @@ class Money
|
|
5
7
|
include Comparable
|
6
8
|
|
7
9
|
attr_reader :cents, :currency, :bank
|
8
|
-
|
10
|
+
|
9
11
|
class << self
|
10
12
|
# Each Money object is associated to a bank object, which is responsible
|
11
13
|
# for currency exchange. This property allows one to specify the default
|
@@ -33,12 +35,13 @@ class Money
|
|
33
35
|
attr_accessor :default_bank
|
34
36
|
|
35
37
|
# The default currency, which is used when <tt>Money.new</tt> is called
|
36
|
-
# without an explicit currency argument. The default value is "USD".
|
38
|
+
# without an explicit currency argument. The default value is Currency.new("USD").
|
39
|
+
# The value must be a valid <tt>Money::Currency</tt> instance.
|
37
40
|
attr_accessor :default_currency
|
38
41
|
end
|
39
42
|
|
40
43
|
self.default_bank = VariableExchangeBank.instance
|
41
|
-
self.default_currency = "USD"
|
44
|
+
self.default_currency = Currency.new("USD")
|
42
45
|
|
43
46
|
|
44
47
|
# Create a new money object with value 0.
|
@@ -80,9 +83,9 @@ class Money
|
|
80
83
|
# Money.new(50, :currency => "USD")
|
81
84
|
#
|
82
85
|
# We retain compatibility here.
|
83
|
-
@currency = currency[:currency] || Money.default_currency
|
86
|
+
@currency = Currency.wrap(currency[:currency] || Money.default_currency)
|
84
87
|
else
|
85
|
-
@currency = currency
|
88
|
+
@currency = Currency.wrap(currency)
|
86
89
|
end
|
87
90
|
@bank = bank
|
88
91
|
end
|
@@ -165,6 +168,30 @@ class Money
|
|
165
168
|
end
|
166
169
|
|
167
170
|
|
171
|
+
# Attempts to pick a symbol that's suitable for the given currency
|
172
|
+
# looking up the Currency::TABLE hashtable.
|
173
|
+
# If the symbol for the given currency isn't known,
|
174
|
+
# then it will default to "$".
|
175
|
+
def symbol
|
176
|
+
currency.symbol || "$"
|
177
|
+
end
|
178
|
+
|
179
|
+
# Attempts to pick a delimiter that's suitable for the given currency
|
180
|
+
# looking up the Money::DELIMITERS hashtable.
|
181
|
+
# If the symbol for the given currency isn't known,
|
182
|
+
# then it will default to ",".
|
183
|
+
def delimiter
|
184
|
+
DELIMITERS[currency.to_s] || ","
|
185
|
+
end
|
186
|
+
|
187
|
+
# Attempts to pick a separator for <tt>cents</tt> that's suitable for the given currency
|
188
|
+
# looking up the Money::DELIMITERS hashtable.
|
189
|
+
# If the separator for the given currency isn't known,
|
190
|
+
# then it will default to ".".
|
191
|
+
def separator
|
192
|
+
SEPARATORS[currency.to_s] || "."
|
193
|
+
end
|
194
|
+
|
168
195
|
# Creates a formatted price string according to several rules. The following
|
169
196
|
# options are supported: :display_free, :with_currency, :no_cents, :symbol,
|
170
197
|
# :separator, :delimiter and :html.
|
@@ -279,52 +306,52 @@ class Money
|
|
279
306
|
|
280
307
|
if rules.has_key?(:symbol)
|
281
308
|
if rules[:symbol] === true
|
282
|
-
|
309
|
+
symbol_value = symbol
|
283
310
|
elsif rules[:symbol]
|
284
|
-
|
311
|
+
symbol_value = rules[:symbol]
|
285
312
|
else
|
286
|
-
|
313
|
+
symbol_value = ""
|
287
314
|
end
|
288
315
|
else
|
289
|
-
|
316
|
+
symbol_value = symbol
|
290
317
|
end
|
291
318
|
|
292
319
|
if rules[:no_cents]
|
293
|
-
formatted = sprintf("#{
|
320
|
+
formatted = sprintf("#{symbol_value}%d", cents.to_f / 100)
|
294
321
|
else
|
295
|
-
formatted = sprintf("#{
|
322
|
+
formatted = sprintf("#{symbol_value}%.2f", cents.to_f / 100)
|
296
323
|
end
|
297
324
|
|
298
|
-
|
325
|
+
delimiter_value = delimiter
|
299
326
|
# Determine delimiter
|
300
327
|
if rules.has_key?(:delimiter)
|
301
328
|
if rules[:delimiter] === false or rules[:delimiter].nil?
|
302
|
-
|
329
|
+
delimiter_value = ""
|
303
330
|
elsif rules[:delimiter]
|
304
|
-
|
331
|
+
delimiter_value = rules[:delimiter]
|
305
332
|
end
|
306
333
|
end
|
307
334
|
|
308
335
|
# Apply delimiter
|
309
|
-
formatted.gsub!(/(\d)(?=\d{3}+(?:\.|$))(\d{3}\..*)?/, "\\1#{
|
336
|
+
formatted.gsub!(/(\d)(?=\d{3}+(?:\.|$))(\d{3}\..*)?/, "\\1#{delimiter_value}\\2")
|
310
337
|
|
311
|
-
|
338
|
+
separator_value = separator
|
312
339
|
# Determine separator
|
313
340
|
if rules.has_key?(:separator) and rules[:separator]
|
314
|
-
|
341
|
+
separator_value = rules[:separator]
|
315
342
|
end
|
316
343
|
|
317
344
|
# Apply separator
|
318
|
-
formatted.sub!(/\.(\d{2})$/, "#{
|
345
|
+
formatted.sub!(/\.(\d{2})$/, "#{separator_value}\\1")
|
319
346
|
|
320
347
|
if rules[:with_currency]
|
321
348
|
formatted << " "
|
322
349
|
formatted << '<span class="currency">' if rules[:html]
|
323
|
-
formatted << currency
|
350
|
+
formatted << currency.to_s
|
324
351
|
formatted << '</span>' if rules[:html]
|
325
352
|
end
|
326
353
|
formatted
|
327
|
-
end
|
354
|
+
end
|
328
355
|
|
329
356
|
# Returns the amount of money as a string.
|
330
357
|
#
|
@@ -342,12 +369,19 @@ class Money
|
|
342
369
|
def to_f
|
343
370
|
cents / 100.0
|
344
371
|
end
|
345
|
-
|
346
|
-
# Recieve the amount of this money object in another
|
372
|
+
|
373
|
+
# Recieve the amount of this money object in another Currency.
|
374
|
+
# <tt>other_currency</tt> can be either a <tt>String</tt>
|
375
|
+
# or a <tt>Currency</tt> instance.
|
376
|
+
#
|
377
|
+
# Money.new(2000, "USD").exchange_to("EUR")
|
378
|
+
# Money.new(2000, "USD").exchange_to(Currency.new("EUR"))
|
379
|
+
#
|
347
380
|
def exchange_to(other_currency)
|
381
|
+
other_currency = Currency.wrap(other_currency)
|
348
382
|
Money.new(@bank.exchange(self.cents, currency, other_currency), other_currency)
|
349
|
-
end
|
350
|
-
|
383
|
+
end
|
384
|
+
|
351
385
|
# Recieve a money object with the same amount as the current Money object
|
352
386
|
# in american dollar
|
353
387
|
def as_us_dollar
|
@@ -52,7 +52,7 @@ class Money
|
|
52
52
|
# bank.same_currency?("usd", "USD") # => true
|
53
53
|
# bank.same_currency?("usd", "EUR") # => false
|
54
54
|
def same_currency?(currency1, currency2)
|
55
|
-
currency1
|
55
|
+
Currency.wrap(currency1) == Currency.wrap(currency2)
|
56
56
|
end
|
57
57
|
|
58
58
|
# Exchange the given amount of cents in +from_currency+ to +to_currency+.
|
data/money.gemspec
CHANGED
@@ -5,32 +5,36 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{money}
|
8
|
-
s.version = "2.
|
8
|
+
s.version = "2.3.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-04-16}
|
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 = [
|
16
|
-
"
|
16
|
+
"CHANGELOG.rdoc",
|
17
|
+
"LICENSE",
|
17
18
|
"README.rdoc"
|
18
19
|
]
|
19
20
|
s.files = [
|
20
21
|
".document",
|
21
22
|
".gitignore",
|
23
|
+
"CHANGELOG.rdoc",
|
22
24
|
"LICENSE",
|
23
25
|
"README.rdoc",
|
24
26
|
"Rakefile",
|
25
27
|
"VERSION",
|
26
28
|
"lib/money.rb",
|
27
29
|
"lib/money/core_extensions.rb",
|
30
|
+
"lib/money/currency.rb",
|
28
31
|
"lib/money/defaults.rb",
|
29
32
|
"lib/money/errors.rb",
|
30
33
|
"lib/money/money.rb",
|
31
34
|
"lib/money/variable_exchange_bank.rb",
|
32
35
|
"money.gemspec",
|
33
36
|
"test/core_extensions_spec.rb",
|
37
|
+
"test/currency_spec.rb",
|
34
38
|
"test/exchange_bank_spec.rb",
|
35
39
|
"test/money_spec.rb"
|
36
40
|
]
|
@@ -38,10 +42,11 @@ Gem::Specification.new do |s|
|
|
38
42
|
s.rdoc_options = ["--charset=UTF-8"]
|
39
43
|
s.require_paths = ["lib"]
|
40
44
|
s.rubyforge_project = %q{money}
|
41
|
-
s.rubygems_version = %q{1.3.
|
45
|
+
s.rubygems_version = %q{1.3.6}
|
42
46
|
s.summary = %q{Money and currency exchange support library}
|
43
47
|
s.test_files = [
|
44
48
|
"test/core_extensions_spec.rb",
|
49
|
+
"test/currency_spec.rb",
|
45
50
|
"test/exchange_bank_spec.rb",
|
46
51
|
"test/money_spec.rb"
|
47
52
|
]
|
@@ -1,4 +1,5 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
|
2
|
+
|
2
3
|
require 'money/core_extensions'
|
3
4
|
|
4
5
|
describe "Money core extensions" do
|
@@ -6,12 +7,12 @@ describe "Money core extensions" do
|
|
6
7
|
money = 1234.to_money
|
7
8
|
money.cents.should == 1234_00
|
8
9
|
money.currency.should == Money.default_currency
|
9
|
-
|
10
|
+
|
10
11
|
money = 100.37.to_money
|
11
12
|
money.cents.should == 100_37
|
12
13
|
money.currency.should == Money.default_currency
|
13
14
|
end
|
14
|
-
|
15
|
+
|
15
16
|
specify "String#to_money works" do
|
16
17
|
"20.15".to_money.should == Money.new(20_15)
|
17
18
|
"100".to_money.should == Money.new(100_00)
|
@@ -31,7 +32,7 @@ describe "Money core extensions" do
|
|
31
32
|
"1.550".to_money.should == Money.new(1_55)
|
32
33
|
"25.".to_money.should == Money.new(25_00)
|
33
34
|
".75".to_money.should == Money.new(75)
|
34
|
-
|
35
|
+
|
35
36
|
"100 USD".to_money.should == Money.new(100_00, "USD")
|
36
37
|
"-100 USD".to_money.should == Money.new(-100_00, "USD")
|
37
38
|
"100 EUR".to_money.should == Money.new(100_00, "EUR")
|
@@ -44,7 +45,7 @@ describe "Money core extensions" do
|
|
44
45
|
"1,000.5500 USD".to_money.should == Money.new(1_000_55, "USD")
|
45
46
|
"-1,000.6500 USD".to_money.should == Money.new(-1_000_65, "USD")
|
46
47
|
"1.550 USD".to_money.should == Money.new(1_55, "USD")
|
47
|
-
|
48
|
+
|
48
49
|
"USD 100".to_money.should == Money.new(100_00, "USD")
|
49
50
|
"EUR 100".to_money.should == Money.new(100_00, "EUR")
|
50
51
|
"EUR 100.37".to_money.should == Money.new(100_37, "EUR")
|
@@ -58,7 +59,7 @@ describe "Money core extensions" do
|
|
58
59
|
"USD 1,000.9000".to_money.should == Money.new(1_000_90, "USD")
|
59
60
|
"USD -1,000.090".to_money.should == Money.new(-1_000_09, "USD")
|
60
61
|
"USD 1.5500".to_money.should == Money.new(1_55, "USD")
|
61
|
-
|
62
|
+
|
62
63
|
"$100 USD".to_money.should == Money.new(100_00, "USD")
|
63
64
|
"$1,194.59 USD".to_money.should == Money.new(1_194_59, "USD")
|
64
65
|
"$-1,955 USD".to_money.should == Money.new(-1_955_00, "USD")
|
@@ -66,8 +67,19 @@ describe "Money core extensions" do
|
|
66
67
|
"$-1,955.000 USD".to_money.should == Money.new(-1_955_00, "USD")
|
67
68
|
"$1.99000 USD".to_money.should == Money.new(1_99, "USD")
|
68
69
|
end
|
69
|
-
|
70
|
+
|
70
71
|
specify "String#to_money ignores unrecognized data" do
|
71
72
|
"hello 2000 world".to_money.should == Money.new(2000_00)
|
72
73
|
end
|
74
|
+
|
75
|
+
specify "String#to_currency convert string to Currency" do
|
76
|
+
"USD".to_currency.should == Money::Currency.new(:usd)
|
77
|
+
"EUR".to_currency.should == Money::Currency.new(:eur)
|
78
|
+
end
|
79
|
+
|
80
|
+
specify "String#to_currency should raise Currency::UnknownCurrency with unkwnown Currency" do
|
81
|
+
lambda { "XXX".to_currency }.should raise_error(Money::Currency::UnknownCurrency)
|
82
|
+
lambda { " ".to_currency }.should raise_error(Money::Currency::UnknownCurrency)
|
83
|
+
end
|
84
|
+
|
73
85
|
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
|
4
|
+
|
5
|
+
require 'money/money'
|
6
|
+
require 'money/currency'
|
7
|
+
require 'money/defaults'
|
8
|
+
|
9
|
+
describe Money::Currency do
|
10
|
+
|
11
|
+
specify "#initialize should lookup data from TABLE" do
|
12
|
+
with_custom_definitions do
|
13
|
+
Money::Currency::TABLE[:usd] = { :priority => 1, :iso_code => "USD", :name => "United States Dollar", :symbol => "$", :subunit => "Cent", :subunit_to_unit => "100" }
|
14
|
+
Money::Currency::TABLE[:eur] = { :priority => 2, :iso_code => "EUR", :name => "Euro", :symbol => "€", :subunit => "Cent", :subunit_to_unit => "100" }
|
15
|
+
|
16
|
+
currency = Money::Currency.new("USD")
|
17
|
+
currency.id.should == :usd
|
18
|
+
currency.priority.should == 1
|
19
|
+
currency.iso_code.should == "USD"
|
20
|
+
currency.name.should == "United States Dollar"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
specify "#initialize should raise UnknownMoney::Currency with unknown currency" do
|
25
|
+
lambda { Money::Currency.new("xxx") }.should raise_error(Money::Currency::UnknownCurrency, /xxx/)
|
26
|
+
end
|
27
|
+
|
28
|
+
specify "#== should return true if self === other" do
|
29
|
+
currency = Money::Currency.new(:eur)
|
30
|
+
currency.should == currency
|
31
|
+
end
|
32
|
+
|
33
|
+
specify "#== should return true if the id is equal" do
|
34
|
+
Money::Currency.new(:eur).should == Money::Currency.new(:eur)
|
35
|
+
Money::Currency.new(:eur).should_not == Money::Currency.new(:usd)
|
36
|
+
end
|
37
|
+
|
38
|
+
specify "#<=> should compare objects by priority" do
|
39
|
+
Money::Currency.new(:cad).should > Money::Currency.new(:usd)
|
40
|
+
Money::Currency.new(:usd).should < Money::Currency.new(:eur)
|
41
|
+
end
|
42
|
+
|
43
|
+
specify "#to_s" do
|
44
|
+
Money::Currency.new(:usd).to_s.should == "USD"
|
45
|
+
Money::Currency.new(:eur).to_s.should == "EUR"
|
46
|
+
end
|
47
|
+
|
48
|
+
specify "#inspect" do
|
49
|
+
Money::Currency.new(:usd).inspect.should ==
|
50
|
+
%Q{#<Money::Currency id: usd priority: 1, iso_code: USD, name: United States Dollar, symbol: $, subunit: Cent, subunit_to_unit: 100>}
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
specify "#self.find should return currency matching given id" do
|
55
|
+
with_custom_definitions do
|
56
|
+
Money::Currency::TABLE[:usd] = { :priority => 1, :iso_code => "USD", :name => "United States Dollar", :symbol => "$", :subunit => "Cent", :subunit_to_unit => "100" }
|
57
|
+
Money::Currency::TABLE[:eur] = { :priority => 2, :iso_code => "EUR", :name => "Euro", :symbol => "€", :subunit => "Cent", :subunit_to_unit => "100" }
|
58
|
+
|
59
|
+
expected = Money::Currency.new(:eur)
|
60
|
+
Money::Currency.find(:eur).should == expected
|
61
|
+
Money::Currency.find(:EUR).should == expected
|
62
|
+
Money::Currency.find("eur").should == expected
|
63
|
+
Money::Currency.find("EUR").should == expected
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
specify "#self.find should return nil unless currency matching given id" do
|
68
|
+
with_custom_definitions do
|
69
|
+
Money::Currency::TABLE[:usd] = { :position => 1, :iso_code => "USD", :name => "United States Dollar", :symbol => "$", :subunit => "Cent", :subunit_to_unit => "100" }
|
70
|
+
Money::Currency::TABLE[:eur] = { :position => 2, :iso_code => "EUR", :name => "Euro", :symbol => "€", :subunit => "Cent", :subunit_to_unit => "100" }
|
71
|
+
|
72
|
+
expected = Money::Currency.new(:eur)
|
73
|
+
Money::Currency.find(:eur).should == expected
|
74
|
+
Money::Currency.find(:EUR).should == expected
|
75
|
+
Money::Currency.find("eur").should == expected
|
76
|
+
Money::Currency.find("EUR").should == expected
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
specify "#self.wrap should return nil if object is nil" do
|
81
|
+
Money::Currency.wrap(nil).should == nil
|
82
|
+
Money::Currency.wrap(Money::Currency.new(:usd)).should == Money::Currency.new(:usd)
|
83
|
+
Money::Currency.wrap(:usd).should == Money::Currency.new(:usd)
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
def with_custom_definitions(&block)
|
88
|
+
begin
|
89
|
+
old = Money::Currency::TABLE.dup
|
90
|
+
Money::Currency::TABLE.clear
|
91
|
+
yield
|
92
|
+
ensure
|
93
|
+
silence_warnings do
|
94
|
+
Money::Currency.const_set("TABLE", old)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Sets $VERBOSE to nil for the duration of the block and back to its original value afterwards.
|
100
|
+
#
|
101
|
+
# silence_warnings do
|
102
|
+
# value = noisy_call # no warning voiced
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
# noisy_call # warning voiced
|
106
|
+
def silence_warnings
|
107
|
+
old_verbose, $VERBOSE = $VERBOSE, nil
|
108
|
+
yield
|
109
|
+
ensure
|
110
|
+
$VERBOSE = old_verbose
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|