money 2.2.0 → 2.3.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.
@@ -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