money 3.0.4 → 3.0.5

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,3 +1,16 @@
1
+ == Money 3.0.5
2
+ * Added Money#abs
3
+ * Updated Currency#subunit_to_unit documentation (it's an integer not a
4
+ string)
5
+ * Fixed issue when exchanging currencies with different :subunit_to_unit
6
+ values
7
+ * Added ability to pass a block to VariableExchangeBank#new or #exchange,
8
+ specifying a custom truncation method
9
+ * Added optional currency argument to Numeric#to_money
10
+ * Added optional currency argument to String#to_money
11
+ * Numeric#to_money now respects :subunit_to_unit
12
+ * Use '¤' as the default currency symbol
13
+
1
14
  == Money 3.0.4
2
15
  * Updated #exchange to avoid floating point rounding errors
3
16
  * Use :subunit_to_unit in #to_s, #to_f and #format
@@ -19,6 +19,15 @@ Resources:
19
19
  - RDoc API: http://money.rubyforge.org
20
20
  - Git repository: http://github.com/FooBarWidget/money
21
21
 
22
+ == Attention
23
+
24
+ Starting in v3.1.0 we will be making two changes to the exchange process. First
25
+ a new `Bank::Base` class will be available. This will allow users to more
26
+ easily create custom `Bank` classes. Secondly the default `#exchange` method
27
+ will be depreciated and a new `#exchange_with` method will be used. Currently
28
+ `#exchange` passes the `cents` attribute. `#exchange_with` will pass the
29
+ actual `Money` object instead.
30
+
22
31
  == Download
23
32
 
24
33
  Install stable releases with the following command:
@@ -73,9 +82,9 @@ containing all the currency attributes.
73
82
  :name => "United States Dollar",
74
83
  :symbol => "$",
75
84
  :subunit => "Cent"
76
- :subunit_to_unit => "100",
85
+ :subunit_to_unit => 100,
77
86
  :separator => ".",
78
- :delimiter =? ","
87
+ :delimiter => ","
79
88
  }
80
89
 
81
90
  The pre-defined set of attributes includes:
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.0.4
1
+ 3.0.5
@@ -6,8 +6,9 @@ class Numeric
6
6
  # 100.37.to_money => #<Money @cents=10037>
7
7
  # require 'bigdecimal'
8
8
  # BigDecimal.new('100').to_money => #<Money @cents=10000>
9
- def to_money
10
- Money.new((self * 100).to_int)
9
+ def to_money(currency = Money.default_currency)
10
+ currency = Money::Currency.new(currency) unless currency.is_a?(Money::Currency)
11
+ Money.new((self * currency.subunit_to_unit).to_int, currency)
11
12
  end
12
13
  end
13
14
 
@@ -22,10 +23,23 @@ class String
22
23
  # 'USD 100'.to_money # => #<Money @cents=10000, @currency="USD">
23
24
  # '$100 USD'.to_money # => #<Money @cents=10000, @currency="USD">
24
25
  # 'hello 2000 world'.to_money # => #<Money @cents=200000 @currency="USD")>
25
- def to_money
26
+ def to_money(currency = nil)
26
27
  # Get the currency.
27
28
  matches = scan /([A-Z]{2,3})/
28
- currency = matches[0] ? matches[0][0] : Money.default_currency
29
+ _currency_ = matches[0] ? matches[0][0] : nil
30
+
31
+ # check that currency passed and embedded currency are the same, or only
32
+ # one or the other is present.
33
+ if currency.nil? and _currency_.nil?
34
+ currency = Money.default_currency
35
+ elsif currency.nil?
36
+ currency = _currency_
37
+ elsif _currency_.nil?
38
+ currency = currency
39
+ elsif currency != _currency_
40
+ raise "mismatching currencies"
41
+ end
42
+
29
43
  cents = calculate_cents(self)
30
44
  Money.new(cents, currency)
31
45
  end
@@ -41,7 +41,7 @@ class Money
41
41
  "SEK" => "kr",
42
42
  "GHC" => "¢",
43
43
  "BRL" => "R$ ",
44
- # Everything else defaults to '$'
44
+ # Everything else defaults to '¤'
45
45
  }, "Money::SYMBOLS has no longer effect. See Money::Currency#symbol.")
46
46
 
47
47
  SEPARATORS = DeprecatedHash.new({
@@ -218,6 +218,11 @@ class Money
218
218
  a.modulo(b) - (b.is_a?(Money) ? b : Money.new(b, a.currency))
219
219
  end
220
220
 
221
+ # Return absolute value of self as a new Money object
222
+ def abs
223
+ Money.new(self.cents.abs, self.currency)
224
+ end
225
+
221
226
  # Test if the money amount is zero
222
227
  def zero?
223
228
  cents == 0
@@ -232,9 +237,9 @@ class Money
232
237
  # Attempts to pick a symbol that's suitable for the given currency
233
238
  # looking up the Currency::TABLE hashtable.
234
239
  # If the symbol for the given currency isn't known,
235
- # then it will default to "$".
240
+ # then it will default to "¤".
236
241
  def symbol
237
- currency.symbol || "$"
242
+ currency.symbol || "¤"
238
243
  end
239
244
 
240
245
  # Uses :delimiter from the Currency hash. If it is not specified defaults to
@@ -303,9 +308,9 @@ class Money
303
308
  #
304
309
  #
305
310
  # If the symbol for the given currency isn't known, then it will default
306
- # to "$" as symbol:
311
+ # to "¤" as symbol:
307
312
  #
308
- # Money.new(100, "AWG").format(:symbol => true) => "$1.00"
313
+ # Money.new(100, "AWG").format(:symbol => true) => "¤1.00"
309
314
  #
310
315
  # You can specify a string as value to enforce using a particular symbol:
311
316
  #
@@ -27,9 +27,10 @@ class Money
27
27
  @@singleton
28
28
  end
29
29
 
30
- def initialize
30
+ def initialize(&block)
31
31
  @rates = {}
32
32
  @mutex = Mutex.new
33
+ @rounding_method = block
33
34
  end
34
35
 
35
36
  # Registers a conversion rate. +from+ and +to+ are both currency names.
@@ -60,12 +61,20 @@ class Money
60
61
  # Returns the amount of cents in +to_currency+ as an integer, rounded down.
61
62
  #
62
63
  # If the conversion rate is unknown, then Money::UnknownRate will be raised.
63
- def exchange(cents, from_currency, to_currency)
64
+ def exchange(cents, from_currency, to_currency, &block)
64
65
  rate = get_rate(from_currency, to_currency)
65
66
  if !rate
66
67
  raise Money::UnknownRate, "No conversion rate known for '#{from_currency}' -> '#{to_currency}'"
67
68
  end
68
- (cents * rate).to_s.to_i
69
+ _from_currency_ = Currency.wrap(from_currency)
70
+ _to_currency_ = Currency.wrap(to_currency)
71
+
72
+ _cents_ = cents / (_from_currency_.subunit_to_unit.to_f / _to_currency_.subunit_to_unit.to_f)
73
+
74
+ ex = _cents_ * rate
75
+ return block.call(ex) if block_given?
76
+ return @rounding_method.call(ex) unless @rounding_method.nil?
77
+ ex.to_s.to_i
69
78
  end
70
79
 
71
80
  @@singleton = VariableExchangeBank.new
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{money}
8
- s.version = "3.0.4"
8
+ s.version = "3.0.5"
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-06-24}
12
+ s.date = %q{2010-07-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 = [
@@ -17,6 +17,17 @@ describe "Money core extensions" do
17
17
  money.cents.should == 1234_00
18
18
  money.currency.should == Money.default_currency
19
19
  end
20
+
21
+ specify "Numeric#to_money accepts optional currency" do
22
+ 1234.to_money('USD').should == Money.new(123400, 'USD')
23
+ 1234.to_money('EUR').should == Money.new(123400, 'EUR')
24
+ end
25
+
26
+ specify "Numeric#to_money should respect :subunit_to_unit" do
27
+ 10.to_money('USD').should == Money.new(10_00, 'USD')
28
+ 10.to_money('TND').should == Money.new(10_000, 'TND')
29
+ 10.to_money('CLP').should == Money.new(10, 'CLP')
30
+ end
20
31
 
21
32
  specify "String#to_money works" do
22
33
  "20.15".to_money.should == Money.new(20_15)
@@ -73,6 +84,13 @@ describe "Money core extensions" do
73
84
  "$1.99000 USD".to_money.should == Money.new(1_99, "USD")
74
85
  end
75
86
 
87
+ specify "String#to_money should accept optional currency" do
88
+ "10.10".to_money('USD').should == Money.new(1010, 'USD')
89
+ "10.10".to_money('EUR').should == Money.new(1010, 'EUR')
90
+ "10.10 USD".to_money('USD').should == Money.new(1010, 'USD')
91
+ lambda{"10.10 USD".to_money('EUR')}.should raise_error
92
+ end
93
+
76
94
  specify "String#to_money ignores unrecognized data" do
77
95
  "hello 2000 world".to_money.should == Money.new(2000_00)
78
96
  end
@@ -57,5 +57,45 @@ describe Money::VariableExchangeBank do
57
57
  @bank.exchange(10000, 'USD', 'EUR').should == 8600
58
58
  end
59
59
  end
60
+
61
+ context 'TND to USD using a rate of 0.67138' do
62
+ it 'returns the correct amount' do
63
+ @bank.add_rate('TND', 'USD', 0.67138)
64
+ @bank.exchange(1000, 'TND', 'USD').should == 67
65
+ end
66
+ end
67
+
68
+ context 'USD to TND using a rate of 1.32862' do
69
+ it 'returns the correct amount' do
70
+ @bank.add_rate('USD', 'TND', 1.32862)
71
+ @bank.exchange(1000, 'USD', 'TND').should == 13286
72
+ end
73
+ end
74
+ end
75
+
76
+ context 'using custom rounding methods' do
77
+ describe 'passing a rounding method to #new' do
78
+ before :each do
79
+ mth = Proc.new{|ex| ex.ceil }
80
+ @bank = Money::VariableExchangeBank.new(&mth)
81
+ end
82
+
83
+ it 'should use @rounding_method' do
84
+ @bank.add_rate('USD', 'EUR', 0.86)
85
+ @bank.exchange(10, 'USD', 'EUR').should == 9
86
+ end
87
+ end
88
+
89
+ describe 'passing a rounding method to #exchange' do
90
+ it 'should use &block' do
91
+ @bank.add_rate('USD', 'EUR', 0.86)
92
+ @bank.exchange(10, 'USD', 'EUR').should == 8
93
+
94
+ mth = Proc.new{|ex| ex.ceil }
95
+ @bank.exchange(10, 'USD', 'EUR', &mth).should == 9
96
+
97
+ @bank.exchange(10, 'USD', 'EUR'){|ex| ex.ceil }.should == 9
98
+ end
99
+ end
60
100
  end
61
101
  end
@@ -430,6 +430,12 @@ describe Money do
430
430
  end
431
431
  end
432
432
 
433
+ specify "#abs correctly returns the absolute value as a new Money object" do
434
+ n = Money.new(-1, :USD)
435
+ n.abs.should == Money.new( 1, :USD)
436
+ n.should == Money.new(-1, :USD)
437
+ end
438
+
433
439
  specify "Money.empty creates a new Money object of 0 cents" do
434
440
  Money.empty.should == Money.new(0)
435
441
  end
@@ -556,7 +562,7 @@ describe Money do
556
562
 
557
563
  currency = Money::Currency.new("EUR")
558
564
  currency.should_receive(:symbol).and_return(nil)
559
- Money.empty(currency).symbol.should == "$"
565
+ Money.empty(currency).symbol.should == "¤"
560
566
  end
561
567
 
562
568
  specify "#delimiter works as documented" do
@@ -647,7 +653,7 @@ describe Money do
647
653
  specify "#format(:symbol => true) returns $ when currency code is not recognized" do
648
654
  currency = Money::Currency.new("EUR")
649
655
  currency.should_receive(:symbol).and_return(nil)
650
- Money.new(100, currency).format(:symbol => true).should == "$1.00"
656
+ Money.new(100, currency).format(:symbol => true).should == "¤1.00"
651
657
  end
652
658
 
653
659
  specify "#format(:symbol => some non-Boolean value that evaluates to true) returs symbol based on the given currency code" do
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: money
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
4
+ hash: 13
5
5
  prerelease: false
6
6
  segments:
7
7
  - 3
8
8
  - 0
9
- - 4
10
- version: 3.0.4
9
+ - 5
10
+ version: 3.0.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Tobias Luetke
@@ -18,7 +18,7 @@ autorequire:
18
18
  bindir: bin
19
19
  cert_chain: []
20
20
 
21
- date: 2010-06-24 00:00:00 -04:00
21
+ date: 2010-07-16 00:00:00 -04:00
22
22
  default_executable:
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency