papercavalier-money 3.7.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,35 @@
1
+ # -*- encoding: utf-8 -*-
2
+ Gem::Specification.new do |s|
3
+ s.name = "papercavalier-money"
4
+ s.version = "3.7.1"
5
+ s.platform = Gem::Platform::RUBY
6
+ s.authors = ["Tobias Luetke", "Hongli Lai", "Jeremy McNevin",
7
+ "Shane Emmons", "Simone Carletti", "Jean-Louis Giordano",
8
+ "Joshua Clayton", "Bodaniel Jeanes", "Tobias Schmidt",
9
+ "Chris Kampmeier", "Romain Gérard", "Eloy", "Josh Delsman",
10
+ "Pelle Braendgaard", "Tom Lianza", "James Cotterill",
11
+ "François Beausoleil", "Abhay Kumar", "pconnor",
12
+ "Christian Billen", "Ilia Lobsanov", "Andrew White",
13
+ ]
14
+ s.email = ["hongli@phusion.nl", "semmons99+RubyMoney@gmail.com"]
15
+ s.homepage = "http://money.rubyforge.org"
16
+ s.summary = "Money and currency exchange support library."
17
+ s.description = "This library aids one in handling money and different currencies."
18
+
19
+ s.required_rubygems_version = ">= 1.3.6"
20
+ s.rubyforge_project = "papercavalier-money"
21
+
22
+ s.add_dependency "i18n", "~> 0.4"
23
+
24
+ s.add_development_dependency "rspec", ">= 2.0.0"
25
+ s.add_development_dependency "yard"
26
+ s.add_development_dependency "json"
27
+
28
+ s.requirements << "json if you plan to import/export rates formatted as json"
29
+
30
+ s.files = Dir.glob("{lib,spec}/**/*")
31
+ s.files += %w(CHANGELOG.md LICENSE README.md)
32
+ s.files += %w(Rakefile .gemtest money.gemspec)
33
+
34
+ s.require_path = "lib"
35
+ end
@@ -0,0 +1,72 @@
1
+ require "spec_helper"
2
+
3
+ describe Money::Bank::Base do
4
+ before :each do
5
+ @bank = Money::Bank::Base.new
6
+ end
7
+
8
+ describe '#new with &block' do
9
+ it 'should store @rounding_method' do
10
+ proc = Proc.new{|n| n.ceil}
11
+ bank = Money::Bank::Base.new(&proc)
12
+ bank.rounding_method.should == proc
13
+ end
14
+ end
15
+
16
+ describe '#setup' do
17
+ it 'should call #setup after #initialize' do
18
+ class MyBank < Money::Bank::Base
19
+ attr_reader :setup_called
20
+
21
+ def setup
22
+ @setup_called = true
23
+ end
24
+ end
25
+
26
+ bank = MyBank.new
27
+ bank.setup_called.should == true
28
+ end
29
+ end
30
+
31
+ describe '#exchange_with' do
32
+ it 'should raise NotImplementedError' do
33
+ lambda { @bank.exchange_with(Money.new(100, 'USD'), 'EUR') }.should raise_exception(NotImplementedError)
34
+ end
35
+ end
36
+
37
+ describe '#same_currency?' do
38
+ it 'should accept str/str' do
39
+ lambda{@bank.send(:same_currency?, 'USD', 'EUR')}.should_not raise_exception
40
+ end
41
+
42
+ it 'should accept currency/str' do
43
+ lambda{@bank.send(:same_currency?, Money::Currency.wrap('USD'), 'EUR')}.should_not raise_exception
44
+ end
45
+
46
+ it 'should accept str/currency' do
47
+ lambda{@bank.send(:same_currency?, 'USD', Money::Currency.wrap('EUR'))}.should_not raise_exception
48
+ end
49
+
50
+ it 'should accept currency/currency' do
51
+ lambda{@bank.send(:same_currency?, Money::Currency.wrap('USD'), Money::Currency.wrap('EUR'))}.should_not raise_exception
52
+ end
53
+
54
+ it 'should return `true` when currencies match' do
55
+ @bank.send(:same_currency?, 'USD', 'USD').should == true
56
+ @bank.send(:same_currency?, Money::Currency.wrap('USD'), 'USD').should == true
57
+ @bank.send(:same_currency?, 'USD', Money::Currency.wrap('USD')).should == true
58
+ @bank.send(:same_currency?, Money::Currency.wrap('USD'), Money::Currency.wrap('USD')).should == true
59
+ end
60
+
61
+ it 'should return `false` when currencies do not match' do
62
+ @bank.send(:same_currency?, 'USD', 'EUR').should == false
63
+ @bank.send(:same_currency?, Money::Currency.wrap('USD'), 'EUR').should == false
64
+ @bank.send(:same_currency?, 'USD', Money::Currency.wrap('EUR')).should == false
65
+ @bank.send(:same_currency?, Money::Currency.wrap('USD'), Money::Currency.wrap('EUR')).should == false
66
+ end
67
+
68
+ it 'should raise an UnknownCurrency exception when an unknown currency is passed' do
69
+ lambda{@bank.send(:same_currency?, 'AAA', 'BBB')}.should raise_exception(Money::Currency::UnknownCurrency)
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,238 @@
1
+ require "spec_helper"
2
+ require "json"
3
+ require "yaml"
4
+
5
+ describe Money::Bank::VariableExchange do
6
+
7
+ describe '#new without block' do
8
+ before :each do
9
+ @bank = Money::Bank::VariableExchange.new
10
+ end
11
+
12
+ describe '#exchange_with' do
13
+ before :each do
14
+ @bank.send(:set_rate, 'USD', 'EUR', 1.33)
15
+ end
16
+
17
+ it 'should accept str' do
18
+ lambda{@bank.exchange_with(Money.new(100, 'USD'), 'EUR')}.should_not raise_exception
19
+ end
20
+
21
+ it 'should accept currency' do
22
+ lambda{@bank.exchange_with(Money.new(100, 'USD'), Money::Currency.wrap('EUR'))}.should_not raise_exception
23
+ end
24
+
25
+ it 'should exchange one currency to another' do
26
+ @bank.exchange_with(Money.new(100, 'USD'), 'EUR').should == Money.new(133, 'EUR')
27
+ end
28
+
29
+ it 'should truncate extra digits' do
30
+ @bank.exchange_with(Money.new(10, 'USD'), 'EUR').should == Money.new(13, 'EUR')
31
+ end
32
+
33
+ it 'should raise an UnknownCurrency exception when an unknown currency is requested' do
34
+ lambda{@bank.exchange_with(Money.new(100, 'USD'), 'BBB')}.should raise_exception(Money::Currency::UnknownCurrency)
35
+ end
36
+
37
+ it 'should raise an UnknownRate exception when an unknown rate is requested' do
38
+ lambda{@bank.exchange_with(Money.new(100, 'USD'), 'JPY')}.should raise_exception(Money::Bank::UnknownRate)
39
+ end
40
+
41
+ #it 'should round the exchanged result down' do
42
+ # @bank.add_rate("USD", "EUR", 0.788332676)
43
+ # @bank.add_rate("EUR", "YEN", 122.631477)
44
+ # @bank.exchange_with(Money.new(10_00, "USD"), "EUR").should == Money.new(788, "EUR")
45
+ # @bank.exchange_with(Money.new(500_00, "EUR"), "YEN").should == Money.new(6131573, "YEN")
46
+ #end
47
+
48
+ it 'should accept a custom truncation method' do
49
+ proc = Proc.new { |n| n.ceil }
50
+ @bank.exchange_with(Money.new(10, 'USD'), 'EUR', &proc).should == Money.new(14, 'EUR')
51
+ end
52
+ end
53
+
54
+ describe "#add_rate" do
55
+ it "should add rates correctly" do
56
+ @bank.add_rate("USD", "EUR", 0.788332676)
57
+ @bank.add_rate("EUR", "YEN", 122.631477)
58
+
59
+ @bank.instance_variable_get(:@rates)['USD_TO_EUR'].should == 0.788332676
60
+ @bank.instance_variable_get(:@rates)['EUR_TO_JPY'].should == 122.631477
61
+ end
62
+
63
+ it "should treat currency names case-insensitively" do
64
+ @bank.add_rate("usd", "eur", 1)
65
+ @bank.instance_variable_get(:@rates)['USD_TO_EUR'].should == 1
66
+ end
67
+ end
68
+
69
+ describe '#set_rate' do
70
+ it 'should set a rate' do
71
+ @bank.set_rate('USD', 'EUR', 1.25)
72
+ @bank.instance_variable_get(:@rates)['USD_TO_EUR'].should == 1.25
73
+ end
74
+
75
+ it 'should raise an UnknownCurrency exception when an unknown currency is passed' do
76
+ lambda{ @bank.set_rate('AAA', 'BBB', 1.25) }.should raise_exception(Money::Currency::UnknownCurrency)
77
+ end
78
+ end
79
+
80
+ describe '#get_rate' do
81
+ it 'should return a rate' do
82
+ @bank.set_rate('USD', 'EUR', 1.25)
83
+ @bank.get_rate('USD', 'EUR').should == 1.25
84
+ end
85
+
86
+ it 'should raise an UnknownCurrency exception when an unknown currency is requested' do
87
+ lambda{ @bank.get_rate('AAA', 'BBB') }.should raise_exception(Money::Currency::UnknownCurrency)
88
+ end
89
+ end
90
+
91
+ describe '#export_rates' do
92
+ before :each do
93
+ @bank.set_rate('USD', 'EUR', 1.25)
94
+ @bank.set_rate('USD', 'JPY', 2.55)
95
+
96
+ @rates = {"USD_TO_EUR"=>1.25,"USD_TO_JPY"=>2.55}
97
+ end
98
+
99
+ describe 'with format == :json' do
100
+ it 'should return rates formatted as json' do
101
+ json = @bank.export_rates(:json)
102
+ JSON.load(json).should == @rates
103
+ end
104
+ end
105
+
106
+ describe 'with format == :ruby' do
107
+ it 'should return rates formatted as ruby objects' do
108
+ Marshal.load(@bank.export_rates(:ruby)).should == @rates
109
+ end
110
+ end
111
+
112
+ describe 'with format == :yaml' do
113
+ it 'should return rates formatted as yaml' do
114
+ yaml = @bank.export_rates(:yaml)
115
+ YAML.load(yaml).should == @rates
116
+ end
117
+ end
118
+
119
+ describe 'with unknown format' do
120
+ it 'should raise `UnknownRateFormat`' do
121
+ lambda{@bank.export_rates(:foo)}.should raise_error Money::Bank::UnknownRateFormat
122
+ end
123
+ end
124
+
125
+ describe 'with :file provided' do
126
+ it 'should write rates to file' do
127
+ f = mock('IO')
128
+ File.should_receive(:open).with('null', 'w').and_return(f)
129
+ f.should_receive(:write).with(@rates.to_json)
130
+
131
+ @bank.export_rates(:json, 'null')
132
+ end
133
+ end
134
+ end
135
+
136
+ describe '#import_rates' do
137
+ describe 'with format == :json' do
138
+ it 'should load the rates provided' do
139
+ s = '{"USD_TO_EUR":1.25,"USD_TO_JPY":2.55}'
140
+ @bank.import_rates(:json, s)
141
+ @bank.get_rate('USD', 'EUR').should == 1.25
142
+ @bank.get_rate('USD', 'JPY').should == 2.55
143
+ end
144
+ end
145
+
146
+ describe 'with format == :ruby' do
147
+ it 'should load the rates provided' do
148
+ s = Marshal.dump({"USD_TO_EUR"=>1.25,"USD_TO_JPY"=>2.55})
149
+ @bank.import_rates(:ruby, s)
150
+ @bank.get_rate('USD', 'EUR').should == 1.25
151
+ @bank.get_rate('USD', 'JPY').should == 2.55
152
+ end
153
+ end
154
+
155
+ describe 'with format == :yaml' do
156
+ it 'should load the rates provided' do
157
+ s = "--- \nUSD_TO_EUR: 1.25\nUSD_TO_JPY: 2.55\n"
158
+ @bank.import_rates(:yaml, s)
159
+ @bank.get_rate('USD', 'EUR').should == 1.25
160
+ @bank.get_rate('USD', 'JPY').should == 2.55
161
+ end
162
+ end
163
+
164
+ describe 'with unknown format' do
165
+ it 'should raise `UnknownRateFormat`' do
166
+ lambda{@bank.import_rates(:foo, "")}.should raise_error Money::Bank::UnknownRateFormat
167
+ end
168
+ end
169
+ end
170
+
171
+ describe '#rate_key_for' do
172
+ it 'should accept str/str' do
173
+ lambda{@bank.send(:rate_key_for, 'USD', 'EUR')}.should_not raise_exception
174
+ end
175
+
176
+ it 'should accept currency/str' do
177
+ lambda{@bank.send(:rate_key_for, Money::Currency.wrap('USD'), 'EUR')}.should_not raise_exception
178
+ end
179
+
180
+ it 'should accept str/currency' do
181
+ lambda{@bank.send(:rate_key_for, 'USD', Money::Currency.wrap('EUR'))}.should_not raise_exception
182
+ end
183
+
184
+ it 'should accept currency/currency' do
185
+ lambda{@bank.send(:rate_key_for, Money::Currency.wrap('USD'), Money::Currency.wrap('EUR'))}.should_not raise_exception
186
+ end
187
+
188
+ it 'should return a hashkey based on the passed arguments' do
189
+ @bank.send(:rate_key_for, 'USD', 'EUR').should == 'USD_TO_EUR'
190
+ @bank.send(:rate_key_for, Money::Currency.wrap('USD'), 'EUR').should == 'USD_TO_EUR'
191
+ @bank.send(:rate_key_for, 'USD', Money::Currency.wrap('EUR')).should == 'USD_TO_EUR'
192
+ @bank.send(:rate_key_for, Money::Currency.wrap('USD'), Money::Currency.wrap('EUR')).should == 'USD_TO_EUR'
193
+ end
194
+
195
+ it 'should raise an UnknownCurrency exception when an unknown currency is passed' do
196
+ lambda{@bank.send(:rate_key_for, 'AAA', 'BBB')}.should raise_exception(Money::Currency::UnknownCurrency)
197
+ end
198
+ end
199
+
200
+ end
201
+
202
+
203
+ describe '#new with &block' do
204
+ before :each do
205
+ proc = Proc.new { |n| n.ceil }
206
+ @bank = Money::Bank::VariableExchange.new(&proc)
207
+ @bank.add_rate('USD', 'EUR', 1.33)
208
+ end
209
+
210
+ describe '#exchange_with' do
211
+ it 'should use a stored truncation method' do
212
+ @bank.exchange_with(Money.new(10, 'USD'), 'EUR').should == Money.new(14, 'EUR')
213
+ end
214
+
215
+ it 'should use a custom truncation method over a stored one' do
216
+ proc = Proc.new { |n| n.ceil + 1 }
217
+ @bank.exchange_with(Money.new(10, 'USD'), 'EUR', &proc).should == Money.new(15, 'EUR')
218
+ end
219
+ end
220
+ end
221
+
222
+ describe "#marshal_dump" do
223
+ before :each do
224
+ @bank = Money::Bank::VariableExchange.new
225
+ end
226
+
227
+ it 'should not raise an error' do
228
+ lambda{Marshal.dump(@bank)}.should_not raise_error
229
+ end
230
+
231
+ it 'should work with Marshal.load' do
232
+ b = Marshal.load(Marshal.dump(@bank))
233
+
234
+ b.rates.should == @bank.rates
235
+ b.rounding_method.should == @bank.rounding_method
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,158 @@
1
+ require "spec_helper"
2
+
3
+ describe "Money core extensions" do
4
+
5
+ describe Numeric do
6
+ describe "#to_money" do
7
+ it "should work" do
8
+ money = 1234.to_money
9
+ money.cents.should == 1234_00
10
+ money.currency.should == Money.default_currency
11
+
12
+ money = 100.37.to_money
13
+ money.cents.should == 100_37
14
+ money.currency.should == Money.default_currency
15
+
16
+ money = BigDecimal.new('1234').to_money
17
+ money.cents.should == 1234_00
18
+ money.currency.should == Money.default_currency
19
+ end
20
+
21
+ it "should accept 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
+ it "should respect :subunit_to_unit currency property" 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
31
+
32
+ specify "#issue/15" do
33
+ amount = 555.55.to_money
34
+ amount.should == Money.new(55555)
35
+ end
36
+ end
37
+ end
38
+
39
+ describe String do
40
+ describe "#to_money" do
41
+
42
+ StringToMoney = {
43
+ "20.15" => Money.new(20_15) ,
44
+ "100" => Money.new(100_00) ,
45
+ "100.37" => Money.new(100_37) ,
46
+ "100,37" => Money.new(100_37) ,
47
+ "100 000" => Money.new(100_000_00) ,
48
+ "100,000.00" => Money.new(100_000_00) ,
49
+ "1,000" => Money.new(1_000_00) ,
50
+ "-1,000" => Money.new(-1_000_00) ,
51
+ "1,000.5" => Money.new(1_000_50) ,
52
+ "1,000.51" => Money.new(1_000_51) ,
53
+ "1,000.505" => Money.new(1_000_51) ,
54
+ "1,000.504" => Money.new(1_000_50) ,
55
+ "1,000.0000" => Money.new(1_000_00) ,
56
+ "1,000.5000" => Money.new(1_000_50) ,
57
+ "1,000.5099" => Money.new(1_000_51) ,
58
+ "1.550" => Money.new(1_55) ,
59
+ "25." => Money.new(25_00) ,
60
+ ".75" => Money.new(75) ,
61
+
62
+ "100 USD" => Money.new(100_00, "USD") ,
63
+ "-100 USD" => Money.new(-100_00, "USD") ,
64
+ "100 EUR" => Money.new(100_00, "EUR") ,
65
+ "100.37 EUR" => Money.new(100_37, "EUR") ,
66
+ "100,37 EUR" => Money.new(100_37, "EUR") ,
67
+ "100,000.00 USD" => Money.new(100_000_00, "USD") ,
68
+ "100.000,00 EUR" => Money.new(100_000_00, "EUR") ,
69
+ "1,000 USD" => Money.new(1_000_00, "USD") ,
70
+ "-1,000 USD" => Money.new(-1_000_00, "USD") ,
71
+ "1,000.5500 USD" => Money.new(1_000_55, "USD") ,
72
+ "-1,000.6500 USD" => Money.new(-1_000_65, "USD") ,
73
+ "1.550 USD" => Money.new(1_55, "USD") ,
74
+
75
+ "USD 100" => Money.new(100_00, "USD") ,
76
+ "EUR 100" => Money.new(100_00, "EUR") ,
77
+ "EUR 100.37" => Money.new(100_37, "EUR") ,
78
+ "CAD -100.37" => Money.new(-100_37, "CAD") ,
79
+ "EUR 100,37" => Money.new(100_37, "EUR") ,
80
+ "EUR -100,37" => Money.new(-100_37, "EUR") ,
81
+ "USD 100,000.00" => Money.new(100_000_00, "USD") ,
82
+ "EUR 100.000,00" => Money.new(100_000_00, "EUR") ,
83
+ "USD 1,000" => Money.new(1_000_00, "USD") ,
84
+ "USD -1,000" => Money.new(-1_000_00, "USD") ,
85
+ "USD 1,000.9000" => Money.new(1_000_90, "USD") ,
86
+ "USD -1,000.090" => Money.new(-1_000_09, "USD") ,
87
+ "USD 1.5500" => Money.new(1_55, "USD") ,
88
+
89
+ "$100 USD" => Money.new(100_00, "USD") ,
90
+ "$1,194.59 USD" => Money.new(1_194_59, "USD") ,
91
+ "$-1,955 USD" => Money.new(-1_955_00, "USD") ,
92
+ "$1,194.5900 USD" => Money.new(1_194_59, "USD") ,
93
+ "$-1,955.000 USD" => Money.new(-1_955_00, "USD") ,
94
+ "$1.99000 USD" => Money.new(1_99, "USD") ,
95
+ }
96
+
97
+ specify "it should work" do
98
+ StringToMoney.each do |string, money|
99
+ string.to_money.should == money
100
+ end
101
+ end
102
+
103
+ it "should coerce input to string" do
104
+ Money.parse(20, "USD").should == Money.new(20_00, "USD")
105
+ end
106
+
107
+ it "should accept optional currency" do
108
+ "10.10".to_money('USD').should == Money.new(1010, 'USD')
109
+ "10.10".to_money('EUR').should == Money.new(1010, 'EUR')
110
+ "10.10 USD".to_money('USD').should == Money.new(1010, 'USD')
111
+ end
112
+
113
+ it "should raise error if optional currency doesn't match string currency" do
114
+ lambda{ "10.10 USD".to_money('EUR') }.should raise_error(/Mismatching Currencies/)
115
+ end
116
+
117
+ it "should ignore unrecognized data" do
118
+ "hello 2000 world".to_money.should == Money.new(2000_00)
119
+ end
120
+
121
+ it "should respect :subunit_to_unit currency property" do
122
+ "1".to_money("USD").should == Money.new(1_00, "USD")
123
+ "1".to_money("TND").should == Money.new(1_000, "TND")
124
+ "1".to_money("CLP").should == Money.new(1, "CLP")
125
+ "1.5".to_money("KWD").cents.should == 1500
126
+ end
127
+ end
128
+
129
+ describe "#to_currency" do
130
+ it "should convert string to Currency" do
131
+ "USD".to_currency.should == Money::Currency.new(:usd)
132
+ "EUR".to_currency.should == Money::Currency.new(:eur)
133
+ end
134
+
135
+ it "should raise Money::Currency::UnknownCurrency with unknown Currency" do
136
+ lambda { "XXX".to_currency }.should raise_error(Money::Currency::UnknownCurrency)
137
+ lambda { " ".to_currency }.should raise_error(Money::Currency::UnknownCurrency)
138
+ end
139
+ end
140
+ end
141
+
142
+ describe Symbol do
143
+ describe "#to_currency" do
144
+ it "should convert symbol to Currency" do
145
+ :usd.to_currency.should == Money::Currency.new(:usd)
146
+ :ars.to_currency.should == Money::Currency.new(:ars)
147
+ end
148
+ it "should work case-insensitive" do
149
+ :EUR.to_currency.should == Money::Currency.new(:eur)
150
+ end
151
+ it "should raise Money::Currency::UnknownCurrency with unknown Currency" do
152
+ lambda { :XXX.to_currency }.should raise_error(Money::Currency::UnknownCurrency)
153
+ lambda { :" ".to_currency }.should raise_error(Money::Currency::UnknownCurrency)
154
+ end
155
+ end
156
+ end
157
+
158
+ end