money 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,31 +1,57 @@
1
1
  # encoding: utf-8
2
2
 
3
- # Add more from http://www.xe.com/symbols.php
4
- Money::SYMBOLS = {
5
- "GBP" => "£",
6
- "JPY" => "¥",
7
- "EUR" => "€",
8
- "ZWD" => "Z$",
9
- "CNY" => "¥",
10
- "INR" => "₨",
11
- "NPR" => "₨",
12
- "SCR" => "₨",
13
- "LKR" => "₨",
14
- "SEK" => "kr",
15
- "GHC" => "¢",
16
- "BRL" => "R$ ",
17
-
18
- # Everything else defaults to '$'
19
- }
20
-
21
- Money::SEPARATORS = {
22
- "BRL" => ",",
23
-
24
- # Everything else defaults to '.'
25
- }
26
-
27
- Money::DELIMITERS = {
28
- "BRL" => ".",
29
-
30
- # Everything else defaults to ","
31
- }
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
- symbol = SYMBOLS[currency] || "$"
309
+ symbol_value = symbol
283
310
  elsif rules[:symbol]
284
- symbol = rules[:symbol]
311
+ symbol_value = rules[:symbol]
285
312
  else
286
- symbol = ""
313
+ symbol_value = ""
287
314
  end
288
315
  else
289
- symbol = SYMBOLS[currency] || "$"
316
+ symbol_value = symbol
290
317
  end
291
318
 
292
319
  if rules[:no_cents]
293
- formatted = sprintf("#{symbol}%d", cents.to_f / 100)
320
+ formatted = sprintf("#{symbol_value}%d", cents.to_f / 100)
294
321
  else
295
- formatted = sprintf("#{symbol}%.2f", cents.to_f / 100)
322
+ formatted = sprintf("#{symbol_value}%.2f", cents.to_f / 100)
296
323
  end
297
324
 
298
- delimiter = DELIMITERS[currency] || ","
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
- delimiter = ""
329
+ delimiter_value = ""
303
330
  elsif rules[:delimiter]
304
- delimiter = rules[:delimiter]
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#{delimiter}\\2")
336
+ formatted.gsub!(/(\d)(?=\d{3}+(?:\.|$))(\d{3}\..*)?/, "\\1#{delimiter_value}\\2")
310
337
 
311
- separator = SEPARATORS[currency] || "."
338
+ separator_value = separator
312
339
  # Determine separator
313
340
  if rules.has_key?(:separator) and rules[:separator]
314
- separator = rules[:separator]
341
+ separator_value = rules[:separator]
315
342
  end
316
343
 
317
344
  # Apply separator
318
- formatted.sub!(/\.(\d{2})$/, "#{separator}\\1")
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 currency.
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.upcase == currency2.upcase
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.2.0"
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-02-17}
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
- "LICENSE",
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.5}
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