money 6.13.0 → 6.13.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +49 -2
  3. data/README.md +93 -3
  4. data/config/currency_backwards_compatible.json +31 -0
  5. data/config/currency_iso.json +18 -18
  6. data/lib/money/bank/variable_exchange.rb +14 -6
  7. data/lib/money/currency.rb +4 -4
  8. data/lib/money/currency/loader.rb +15 -13
  9. data/lib/money/locale_backend/currency.rb +11 -0
  10. data/lib/money/locale_backend/i18n.rb +2 -1
  11. data/lib/money/locale_backend/legacy.rb +2 -2
  12. data/lib/money/money.rb +100 -52
  13. data/lib/money/money/allocation.rb +8 -5
  14. data/lib/money/money/arithmetic.rb +20 -10
  15. data/lib/money/money/formatter.rb +3 -0
  16. data/lib/money/money/formatting_rules.rb +15 -5
  17. data/lib/money/money/locale_backend.rb +3 -1
  18. data/lib/money/rates_store/memory.rb +24 -23
  19. data/lib/money/version.rb +1 -1
  20. data/money.gemspec +4 -4
  21. metadata +11 -51
  22. data/.coveralls.yml +0 -1
  23. data/.gitignore +0 -23
  24. data/.rspec +0 -2
  25. data/.travis.yml +0 -32
  26. data/AUTHORS +0 -131
  27. data/CONTRIBUTING.md +0 -17
  28. data/Gemfile +0 -16
  29. data/Rakefile +0 -17
  30. data/spec/bank/base_spec.rb +0 -79
  31. data/spec/bank/single_currency_spec.rb +0 -13
  32. data/spec/bank/variable_exchange_spec.rb +0 -265
  33. data/spec/currency/heuristics_spec.rb +0 -11
  34. data/spec/currency/loader_spec.rb +0 -19
  35. data/spec/currency_spec.rb +0 -400
  36. data/spec/locale_backend/i18n_spec.rb +0 -62
  37. data/spec/locale_backend/legacy_spec.rb +0 -74
  38. data/spec/money/allocation_spec.rb +0 -130
  39. data/spec/money/arithmetic_spec.rb +0 -756
  40. data/spec/money/constructors_spec.rb +0 -91
  41. data/spec/money/formatting_spec.rb +0 -855
  42. data/spec/money/locale_backend_spec.rb +0 -14
  43. data/spec/money_spec.rb +0 -880
  44. data/spec/rates_store/memory_spec.rb +0 -80
  45. data/spec/spec_helper.rb +0 -30
  46. data/spec/support/shared_examples/money_examples.rb +0 -14
@@ -1,17 +0,0 @@
1
- # Contribution Guidelines
2
-
3
- ## Steps
4
-
5
- 1. Fork [the repo](https://github.com/RubyMoney/money)
6
- 2. Grab dependencies: `bundle install`
7
- 3. Make sure everything is working: `bundle exec rake spec`
8
- 4. Make your changes
9
- 5. Test your changes
10
- 5. Create a Pull Request
11
- 6. Celebrate!!!!!
12
-
13
- ## Notes
14
-
15
- When contributing, please make sure to update the CHANGELOG and AUTHORS files
16
- when you submit your pull request. Upon merging of your first pull request,
17
- you will be given commit access to the repository.
data/Gemfile DELETED
@@ -1,16 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'coveralls', '>= 0.8.17', require: false
4
- gem 'pry', require: false
5
-
6
- # JSON gem no longer supports ruby < 2.0.0
7
- if defined?(JRUBY_VERSION)
8
- gem 'json'
9
- elsif RUBY_VERSION =~ /^1/
10
- # Legacy gem locks for ruby 1.9.x
11
- gem 'json', '~> 1.8.3'
12
- gem 'tins', '~> 1.6.0'
13
- gem 'term-ansicolor', '< 1.4'
14
- end
15
-
16
- gemspec
data/Rakefile DELETED
@@ -1,17 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rake/clean"
3
- require "rspec/core/rake_task"
4
-
5
- CLOBBER.include('doc', '.yardoc')
6
-
7
- require "yard"
8
-
9
- YARD::Rake::YardocTask.new do |t|
10
- t.options << "--files" << "CHANGELOG.md,LICENSE"
11
- end
12
-
13
- RSpec::Core::RakeTask.new(:spec) do |t|
14
- t.fail_on_error = false
15
- end
16
-
17
- task default: :spec
@@ -1,79 +0,0 @@
1
- class Money
2
- module Bank
3
- describe Base do
4
-
5
- describe ".instance" do
6
- it "is local to one class" do
7
- klass = Base
8
- subclass = Class.new(Base)
9
- expect(klass.instance).not_to eq subclass.instance
10
- end
11
- end
12
-
13
- describe "#initialize" do
14
- it "accepts a block and stores @rounding_method" do
15
- proc = Proc.new { |n| n.ceil }
16
- bank = Base.new(&proc)
17
- expect(bank.rounding_method).to eq proc
18
- end
19
- end
20
-
21
- describe "#setup" do
22
- it "calls #setup after #initialize" do
23
- class MyBank < Base
24
- attr_reader :setup_called
25
-
26
- def setup
27
- @setup_called = true
28
- end
29
- end
30
-
31
- bank = MyBank.new
32
- expect(bank.setup_called).to eq true
33
- end
34
- end
35
-
36
- describe "#exchange_with" do
37
- it "is not implemented" do
38
- expect { subject.exchange_with(Money.new(100, 'USD'), 'EUR') }.to raise_exception(NotImplementedError)
39
- end
40
- end
41
-
42
- describe "#same_currency?" do
43
- it "accepts str/str" do
44
- expect { subject.send(:same_currency?, 'USD', 'EUR') }.to_not raise_exception
45
- end
46
-
47
- it "accepts currency/str" do
48
- expect { subject.send(:same_currency?, Currency.wrap('USD'), 'EUR') }.to_not raise_exception
49
- end
50
-
51
- it "accepts str/currency" do
52
- expect { subject.send(:same_currency?, 'USD', Currency.wrap('EUR')) }.to_not raise_exception
53
- end
54
-
55
- it "accepts currency/currency" do
56
- expect { subject.send(:same_currency?, Currency.wrap('USD'), Currency.wrap('EUR')) }.to_not raise_exception
57
- end
58
-
59
- it "returns true when currencies match" do
60
- expect(subject.send(:same_currency?, 'USD', 'USD')).to be true
61
- expect(subject.send(:same_currency?, Currency.wrap('USD'), 'USD')).to be true
62
- expect(subject.send(:same_currency?, 'USD', Currency.wrap('USD'))).to be true
63
- expect(subject.send(:same_currency?, Currency.wrap('USD'), Currency.wrap('USD'))).to be true
64
- end
65
-
66
- it "returns false when currencies do not match" do
67
- expect(subject.send(:same_currency?, 'USD', 'EUR')).to be false
68
- expect(subject.send(:same_currency?, Currency.wrap('USD'), 'EUR')).to be false
69
- expect(subject.send(:same_currency?, 'USD', Currency.wrap('EUR'))).to be false
70
- expect(subject.send(:same_currency?, Currency.wrap('USD'), Currency.wrap('EUR'))).to be false
71
- end
72
-
73
- it "raises an UnknownCurrency exception when an unknown currency is passed" do
74
- expect { subject.send(:same_currency?, 'AAA', 'BBB') }.to raise_exception(Currency::UnknownCurrency)
75
- end
76
- end
77
- end
78
- end
79
- end
@@ -1,13 +0,0 @@
1
- class Money
2
- module Bank
3
- describe SingleCurrency do
4
- describe "#exchange_with" do
5
- it "raises when called" do
6
- expect {
7
- subject.exchange_with(Money.new(100, 'USD'), 'EUR')
8
- }.to raise_exception(DifferentCurrencyError, "No exchanging of currencies allowed: 1.00 USD to EUR")
9
- end
10
- end
11
- end
12
- end
13
- end
@@ -1,265 +0,0 @@
1
- require 'json'
2
- require 'yaml'
3
-
4
- class Money
5
- module Bank
6
- describe VariableExchange do
7
-
8
- describe "#initialize" do
9
- context "without &block" do
10
- let(:bank) {
11
- VariableExchange.new.tap do |bank|
12
- bank.add_rate('USD', 'EUR', 1.33)
13
- end
14
- }
15
-
16
- describe '#store' do
17
- it 'defaults to Memory store' do
18
- expect(bank.store).to be_a(Money::RatesStore::Memory)
19
- end
20
- end
21
-
22
- describe 'custom store' do
23
- let(:custom_store) { Object.new }
24
-
25
- let(:bank) { VariableExchange.new(custom_store) }
26
-
27
- it 'sets #store to be custom store' do
28
- expect(bank.store).to eql(custom_store)
29
- end
30
- end
31
-
32
- describe "#exchange_with" do
33
- it "accepts str" do
34
- expect { bank.exchange_with(Money.new(100, 'USD'), 'EUR') }.to_not raise_exception
35
- end
36
-
37
- it "accepts currency" do
38
- expect { bank.exchange_with(Money.new(100, 'USD'), Currency.wrap('EUR')) }.to_not raise_exception
39
- end
40
-
41
- it "exchanges one currency to another" do
42
- expect(bank.exchange_with(Money.new(100, 'USD'), 'EUR')).to eq Money.new(133, 'EUR')
43
- end
44
-
45
- it "truncates extra digits" do
46
- expect(bank.exchange_with(Money.new(10, 'USD'), 'EUR')).to eq Money.new(13, 'EUR')
47
- end
48
-
49
- it "raises an UnknownCurrency exception when an unknown currency is requested" do
50
- expect { bank.exchange_with(Money.new(100, 'USD'), 'BBB') }.to raise_exception(Currency::UnknownCurrency)
51
- end
52
-
53
- it "raises an UnknownRate exception when an unknown rate is requested" do
54
- expect { bank.exchange_with(Money.new(100, 'USD'), 'JPY') }.to raise_exception(UnknownRate)
55
- end
56
-
57
- #it "rounds the exchanged result down" do
58
- # bank.add_rate("USD", "EUR", 0.788332676)
59
- # bank.add_rate("EUR", "YEN", 122.631477)
60
- # expect(bank.exchange_with(Money.new(10_00, "USD"), "EUR")).to eq Money.new(788, "EUR")
61
- # expect(bank.exchange_with(Money.new(500_00, "EUR"), "YEN")).to eq Money.new(6131573, "YEN")
62
- #end
63
-
64
- it "accepts a custom truncation method" do
65
- proc = Proc.new { |n| n.ceil }
66
- expect(bank.exchange_with(Money.new(10, 'USD'), 'EUR', &proc)).to eq Money.new(14, 'EUR')
67
- end
68
-
69
- it 'works with big numbers' do
70
- amount = 10**20
71
- expect(bank.exchange_with(Money.usd(amount), :EUR)).to eq Money.eur(1.33 * amount)
72
- end
73
-
74
- it "preserves the class in the result when given a subclass of Money" do
75
- special_money_class = Class.new(Money)
76
- expect(bank.exchange_with(special_money_class.new(100, 'USD'), 'EUR')).to be_a special_money_class
77
- end
78
-
79
- it "doesn't loose precision when handling larger amounts" do
80
- expect(bank.exchange_with(Money.new(100_000_000_000_000_01, 'USD'), 'EUR')).to eq Money.new(133_000_000_000_000_01, 'EUR')
81
- end
82
- end
83
- end
84
-
85
- context "with &block" do
86
- let(:bank) {
87
- proc = Proc.new { |n| n.ceil }
88
- VariableExchange.new(&proc).tap do |bank|
89
- bank.add_rate('USD', 'EUR', 1.33)
90
- end
91
- }
92
-
93
- describe "#exchange_with" do
94
- it "uses the stored truncation method" do
95
- expect(bank.exchange_with(Money.new(10, 'USD'), 'EUR')).to eq Money.new(14, 'EUR')
96
- end
97
-
98
- it "accepts a custom truncation method" do
99
- proc = Proc.new { |n| n.ceil + 1 }
100
- expect(bank.exchange_with(Money.new(10, 'USD'), 'EUR', &proc)).to eq Money.new(15, 'EUR')
101
- end
102
- end
103
- end
104
- end
105
-
106
- describe "#add_rate" do
107
- it 'delegates to store#add_rate' do
108
- expect(subject.store).to receive(:add_rate).with('USD', 'EUR', 1.25).and_return 1.25
109
- expect(subject.add_rate('USD', 'EUR', 1.25)).to eql 1.25
110
- end
111
-
112
- it "adds rates with correct ISO codes" do
113
- expect(subject.store).to receive(:add_rate).with('USD', 'EUR', 0.788332676)
114
- subject.add_rate("USD", "EUR", 0.788332676)
115
-
116
- expect(subject.store).to receive(:add_rate).with('EUR', 'JPY', 122.631477)
117
- subject.add_rate("EUR", "YEN", 122.631477)
118
- end
119
-
120
- it "treats currency names case-insensitively" do
121
- subject.add_rate("usd", "eur", 1)
122
- expect(subject.get_rate('USD', 'EUR')).to eq 1
123
- end
124
- end
125
-
126
- describe "#set_rate" do
127
- it 'delegates to store#add_rate' do
128
- expect(subject.store).to receive(:add_rate).with('USD', 'EUR', 1.25).and_return 1.25
129
- expect(subject.set_rate('USD', 'EUR', 1.25)).to eql 1.25
130
- end
131
-
132
- it "sets a rate" do
133
- subject.set_rate('USD', 'EUR', 1.25)
134
- expect(subject.store.get_rate('USD', 'EUR')).to eq 1.25
135
- end
136
-
137
- it "raises an UnknownCurrency exception when an unknown currency is passed" do
138
- expect { subject.set_rate('AAA', 'BBB', 1.25) }.to raise_exception(Currency::UnknownCurrency)
139
- end
140
- end
141
-
142
- describe "#get_rate" do
143
- it "returns a rate" do
144
- subject.set_rate('USD', 'EUR', 1.25)
145
- expect(subject.get_rate('USD', 'EUR')).to eq 1.25
146
- end
147
-
148
- it "raises an UnknownCurrency exception when an unknown currency is passed" do
149
- expect { subject.get_rate('AAA', 'BBB') }.to raise_exception(Currency::UnknownCurrency)
150
- end
151
-
152
- it "delegates options to store, options are a no-op" do
153
- expect(subject.store).to receive(:get_rate).with('USD', 'EUR')
154
- subject.get_rate('USD', 'EUR', without_mutex: true)
155
- end
156
- end
157
-
158
- describe "#export_rates" do
159
- before :each do
160
- subject.set_rate('USD', 'EUR', 1.25)
161
- subject.set_rate('USD', 'JPY', 2.55)
162
-
163
- @rates = { "USD_TO_EUR" => 1.25, "USD_TO_JPY" => 2.55 }
164
- end
165
-
166
- context "with format == :json" do
167
- it "should return rates formatted as json" do
168
- json = subject.export_rates(:json)
169
- expect(JSON.load(json)).to eq @rates
170
- end
171
- end
172
-
173
- context "with format == :ruby" do
174
- it "should return rates formatted as ruby objects" do
175
- expect(Marshal.load(subject.export_rates(:ruby))).to eq @rates
176
- end
177
- end
178
-
179
- context "with format == :yaml" do
180
- it "should return rates formatted as yaml" do
181
- yaml = subject.export_rates(:yaml)
182
- expect(YAML.load(yaml)).to eq @rates
183
- end
184
- end
185
-
186
- context "with unknown format" do
187
- it "raises Money::Bank::UnknownRateFormat" do
188
- expect { subject.export_rates(:foo)}.to raise_error UnknownRateFormat
189
- end
190
- end
191
-
192
- context "with :file provided" do
193
- it "writes rates to file" do
194
- f = double('IO')
195
- expect(File).to receive(:open).with('null', 'w').and_yield(f)
196
- expect(f).to receive(:write).with(JSON.dump(@rates))
197
-
198
- subject.export_rates(:json, 'null')
199
- end
200
- end
201
-
202
- it "delegates execution to store, options are a no-op" do
203
- expect(subject.store).to receive(:transaction)
204
- subject.export_rates(:yaml, nil, foo: 1)
205
- end
206
-
207
- end
208
-
209
- describe "#import_rates" do
210
- context "with format == :json" do
211
- it "loads the rates provided" do
212
- s = '{"USD_TO_EUR":1.25,"USD_TO_JPY":2.55}'
213
- subject.import_rates(:json, s)
214
- expect(subject.get_rate('USD', 'EUR')).to eq 1.25
215
- expect(subject.get_rate('USD', 'JPY')).to eq 2.55
216
- end
217
- end
218
-
219
- context "with format == :ruby" do
220
- it "loads the rates provided" do
221
- s = Marshal.dump({"USD_TO_EUR"=>1.25,"USD_TO_JPY"=>2.55})
222
- subject.import_rates(:ruby, s)
223
- expect(subject.get_rate('USD', 'EUR')).to eq 1.25
224
- expect(subject.get_rate('USD', 'JPY')).to eq 2.55
225
- end
226
- end
227
-
228
- context "with format == :yaml" do
229
- it "loads the rates provided" do
230
- s = "--- \nUSD_TO_EUR: 1.25\nUSD_TO_JPY: 2.55\n"
231
- subject.import_rates(:yaml, s)
232
- expect(subject.get_rate('USD', 'EUR')).to eq 1.25
233
- expect(subject.get_rate('USD', 'JPY')).to eq 2.55
234
- end
235
- end
236
-
237
- context "with unknown format" do
238
- it "raises Money::Bank::UnknownRateFormat" do
239
- expect { subject.import_rates(:foo, "")}.to raise_error UnknownRateFormat
240
- end
241
- end
242
-
243
- it "delegates execution to store#transaction" do
244
- expect(subject.store).to receive(:transaction)
245
- s = "--- \nUSD_TO_EUR: 1.25\nUSD_TO_JPY: 2.55\n"
246
- subject.import_rates(:yaml, s, foo: 1)
247
- end
248
-
249
- end
250
-
251
- describe "#marshal_dump" do
252
- it "does not raise an error" do
253
- expect { Marshal.dump(subject) }.to_not raise_error
254
- end
255
-
256
- it "works with Marshal.load" do
257
- bank = Marshal.load(Marshal.dump(subject))
258
-
259
- expect(bank.rates).to eq subject.rates
260
- expect(bank.rounding_method).to eq subject.rounding_method
261
- end
262
- end
263
- end
264
- end
265
- end
@@ -1,11 +0,0 @@
1
- # encoding: utf-8
2
-
3
- describe Money::Currency::Heuristics do
4
- describe "#analyze_string" do
5
- let(:it) { Money::Currency }
6
-
7
- it "it raises deprecation error" do
8
- expect{ it.analyze('123') }.to raise_error(StandardError, 'Heuristics deprecated, add `gem "money-heuristics"` to Gemfile')
9
- end
10
- end
11
- end
@@ -1,19 +0,0 @@
1
- # encoding: utf-8
2
-
3
- describe Money::Currency::Loader do
4
- class CurrencyLoader
5
- include Money::Currency::Loader
6
- end
7
-
8
- let(:loader) { CurrencyLoader.new }
9
-
10
- it "returns a currency table hash" do
11
- expect(loader.load_currencies).to be_a Hash
12
- end
13
-
14
- it "parse currency_iso.json & currency_non_iso.json & currency_backwards_compatible.json" do
15
- expect(loader).to receive(:parse_currency_file).exactly(3).times.and_return({})
16
-
17
- loader.load_currencies
18
- end
19
- end
@@ -1,400 +0,0 @@
1
- # encoding: utf-8
2
-
3
- class Money
4
- describe Currency do
5
-
6
- FOO = '{ "priority": 1, "iso_code": "FOO", "iso_numeric": "840", "name": "United States Dollar", "symbol": "$", "subunit": "Cent", "subunit_to_unit": 1000, "symbol_first": true, "html_entity": "$", "decimal_mark": ".", "thousands_separator": ",", "smallest_denomination": 1 }'
7
-
8
- def register_foo(opts={})
9
- foo_attrs = JSON.parse(FOO, symbolize_names: true)
10
- # Pass an array of attribute names to 'skip' to remove them from the 'FOO'
11
- # json before registering foo as a currency.
12
- Array(opts[:skip]).each { |attr| foo_attrs.delete(attr) }
13
- Money::Currency.register(foo_attrs)
14
- end
15
-
16
- def unregister_foo
17
- Currency.unregister(JSON.parse(FOO, symbolize_names: true))
18
- end
19
-
20
- describe "UnknownCurrency" do
21
- it "is a subclass of ArgumentError" do
22
- expect(Currency::UnknownCurrency < ArgumentError).to be true
23
- end
24
- end
25
-
26
- describe ".find" do
27
- before { register_foo }
28
- after { unregister_foo }
29
-
30
- it "returns currency matching given id" do
31
- expected = Currency.new(:foo)
32
- expect(Currency.find(:foo)).to be expected
33
- expect(Currency.find(:FOO)).to be expected
34
- expect(Currency.find("foo")).to be expected
35
- expect(Currency.find("FOO")).to be expected
36
- end
37
-
38
- it "returns nil unless currency matching given id" do
39
- expect(Currency.find("ZZZ")).to be_nil
40
- end
41
- end
42
-
43
- describe ".find_by_iso_numeric" do
44
- it "returns currency matching given numeric code" do
45
- expect(Currency.find_by_iso_numeric(978)).to eq Currency.new(:eur)
46
- expect(Currency.find_by_iso_numeric(208)).not_to eq Currency.new(:eur)
47
- expect(Currency.find_by_iso_numeric('840')).to eq Currency.new(:usd)
48
-
49
- class Mock
50
- def to_s
51
- '208'
52
- end
53
- end
54
- expect(Currency.find_by_iso_numeric(Mock.new)).to eq Currency.new(:dkk)
55
- expect(Currency.find_by_iso_numeric(Mock.new)).not_to eq Currency.new(:usd)
56
- end
57
-
58
- it "returns nil if no currency has the given numeric code" do
59
- expect(Currency.find_by_iso_numeric('non iso 4217 numeric code')).to be_nil
60
- expect(Currency.find_by_iso_numeric(0)).to be_nil
61
- end
62
-
63
- it "returns nil when given empty input" do
64
- expect(Currency.find_by_iso_numeric('')).to be_nil
65
- expect(Currency.find_by_iso_numeric(nil)).to be_nil
66
- end
67
- end
68
-
69
- describe ".wrap" do
70
- it "returns nil if object is nil" do
71
- expect(Currency.wrap(nil)).to be_nil
72
- expect(Currency.wrap(Currency.new(:usd))).to eq Currency.new(:usd)
73
- expect(Currency.wrap(:usd)).to eq Currency.new(:usd)
74
- end
75
- end
76
-
77
- describe ".all" do
78
- it "returns an array of currencies" do
79
- expect(Currency.all).to include Currency.new(:usd)
80
- end
81
- it "includes registered currencies" do
82
- register_foo
83
- expect(Currency.all).to include Currency.new(:foo)
84
- unregister_foo
85
- end
86
- it 'is sorted by priority' do
87
- expect(Currency.all.first.priority).to eq 1
88
- end
89
- it "raises a MissingAttributeError if any currency has no priority" do
90
- register_foo(skip: :priority)
91
-
92
- expect{Money::Currency.all}.to \
93
- raise_error(Money::Currency::MissingAttributeError, /foo.*priority/)
94
- unregister_foo
95
- end
96
- end
97
-
98
-
99
- describe ".register" do
100
- after { Currency.unregister(iso_code: "XXX") if Currency.find("XXX") }
101
-
102
- it "registers a new currency" do
103
- Currency.register(
104
- iso_code: "XXX",
105
- name: "Golden Doubloon",
106
- symbol: "%",
107
- subunit_to_unit: 100
108
- )
109
- new_currency = Currency.find("XXX")
110
- expect(new_currency).not_to be_nil
111
- expect(new_currency.name).to eq "Golden Doubloon"
112
- expect(new_currency.symbol).to eq "%"
113
- end
114
-
115
- specify ":iso_code must be present" do
116
- expect {
117
- Currency.register(name: "New Currency")
118
- }.to raise_error(KeyError)
119
- end
120
- end
121
-
122
-
123
- describe ".inherit" do
124
- after do
125
- Currency.unregister(iso_code: "XXX") if Currency.find("XXX")
126
- Currency.unregister(iso_code: "YYY") if Currency.find("YYY")
127
- end
128
-
129
- it "inherit a new currency" do
130
- Currency.register(
131
- iso_code: "XXX",
132
- name: "Golden Doubloon",
133
- symbol: "%",
134
- subunit_to_unit: 100
135
- )
136
- Currency.inherit("XXX",
137
- iso_code: "YYY",
138
- symbol: "@"
139
- )
140
- new_currency = Currency.find("YYY")
141
- expect(new_currency).not_to be_nil
142
- expect(new_currency.name).to eq "Golden Doubloon"
143
- expect(new_currency.symbol).to eq "@"
144
- expect(new_currency.subunit_to_unit).to eq 100
145
- end
146
- end
147
-
148
-
149
- describe ".unregister" do
150
- it "unregisters a currency" do
151
- Currency.register(iso_code: "XXX")
152
- expect(Currency.find("XXX")).not_to be_nil # Sanity check
153
- Currency.unregister(iso_code: "XXX")
154
- expect(Currency.find("XXX")).to be_nil
155
- end
156
-
157
- it "returns true iff the currency existed" do
158
- Currency.register(iso_code: "XXX")
159
- expect(Currency.unregister(iso_code: "XXX")).to be_truthy
160
- expect(Currency.unregister(iso_code: "XXX")).to be_falsey
161
- end
162
-
163
- it "can be passed an ISO code" do
164
- Currency.register(iso_code: "XXX")
165
- Currency.register(iso_code: "YYZ")
166
- # Test with string:
167
- Currency.unregister("XXX")
168
- expect(Currency.find("XXX")).to be_nil
169
- # Test with symbol:
170
- Currency.unregister(:yyz)
171
- expect(Currency.find(:yyz)).to be_nil
172
- end
173
- end
174
-
175
-
176
- describe ".each" do
177
- it "yields each currency to the block" do
178
- expect(Currency).to respond_to(:each)
179
- currencies = []
180
- Currency.each do |currency|
181
- currencies.push(currency)
182
- end
183
-
184
- # Don't bother testing every single currency
185
- expect(currencies[0]).to eq Currency.all[0]
186
- expect(currencies[1]).to eq Currency.all[1]
187
- expect(currencies[-1]).to eq Currency.all[-1]
188
- end
189
- end
190
-
191
-
192
- it "implements Enumerable" do
193
- expect(Currency).to respond_to(:all?)
194
- expect(Currency).to respond_to(:each_with_index)
195
- expect(Currency).to respond_to(:map)
196
- expect(Currency).to respond_to(:select)
197
- expect(Currency).to respond_to(:reject)
198
- end
199
-
200
-
201
- describe "#initialize" do
202
- before { Currency._instances.clear }
203
-
204
- it "lookups data from loaded config" do
205
- currency = Currency.new("USD")
206
- expect(currency.id).to eq :usd
207
- expect(currency.priority).to eq 1
208
- expect(currency.iso_code).to eq "USD"
209
- expect(currency.iso_numeric).to eq "840"
210
- expect(currency.name).to eq "United States Dollar"
211
- expect(currency.decimal_mark).to eq "."
212
- expect(currency.separator).to eq "."
213
- expect(currency.thousands_separator).to eq ","
214
- expect(currency.delimiter).to eq ","
215
- expect(currency.smallest_denomination).to eq 1
216
- end
217
-
218
- it 'caches instances' do
219
- currency = Currency.new("USD")
220
-
221
- expect(Currency._instances.length).to eq 1
222
- expect(Currency._instances["usd"].object_id).to eq currency.object_id
223
- end
224
-
225
- it "raises UnknownCurrency with unknown currency" do
226
- expect { Currency.new("xxx") }.to raise_error(Currency::UnknownCurrency, /xxx/)
227
- end
228
-
229
- it 'returns old object for the same :key' do
230
- expect(Currency.new("USD")).to be(Currency.new("USD"))
231
- expect(Currency.new("USD")).to be(Currency.new(:usd))
232
- expect(Currency.new("USD")).to be(Currency.new(:USD))
233
- expect(Currency.new("USD")).to be(Currency.new('usd'))
234
- expect(Currency.new("USD")).to be(Currency.new('Usd'))
235
- end
236
-
237
- it 'returns new object for the different :key' do
238
- expect(Currency.new("USD")).to_not be(Currency.new("EUR"))
239
- end
240
-
241
- it 'is thread safe' do
242
- ids = []
243
- 2.times.map{ Thread.new{ ids << Currency.new("USD").object_id }}.each(&:join)
244
- expect(ids.uniq.length).to eq(1)
245
- end
246
- end
247
-
248
- describe "#<=>" do
249
- it "compares objects by priority" do
250
- expect(Currency.new(:cad)).to be > Currency.new(:usd)
251
- expect(Currency.new(:usd)).to be < Currency.new(:eur)
252
- end
253
-
254
- it "compares by id when priority is the same" do
255
- Currency.register(iso_code: "ABD", priority: 15)
256
- Currency.register(iso_code: "ABC", priority: 15)
257
- Currency.register(iso_code: "ABE", priority: 15)
258
- abd = Currency.find("ABD")
259
- abc = Currency.find("ABC")
260
- abe = Currency.find("ABE")
261
- expect(abd).to be > abc
262
- expect(abe).to be > abd
263
- Currency.unregister("ABD")
264
- Currency.unregister("ABC")
265
- Currency.unregister("ABE")
266
- end
267
-
268
- context "when one of the currencies has no 'priority' set" do
269
- it "compares by id" do
270
- Currency.register(iso_code: "ABD") # No priority
271
- abd = Currency.find(:abd)
272
- usd = Currency.find(:usd)
273
- expect(abd).to be < usd
274
- Currency.unregister(iso_code: "ABD")
275
- end
276
- end
277
- end
278
-
279
- describe "#==" do
280
- it "returns true if self === other" do
281
- currency = Currency.new(:eur)
282
- expect(currency).to eq currency
283
- end
284
-
285
- it "returns true if the id is equal ignorning case" do
286
- expect(Currency.new(:eur)).to eq Currency.new(:eur)
287
- expect(Currency.new(:eur)).to eq Currency.new(:EUR)
288
- expect(Currency.new(:eur)).not_to eq Currency.new(:usd)
289
- end
290
-
291
- it "allows direct comparison of currencies and symbols/strings" do
292
- expect(Currency.new(:eur)).to eq 'eur'
293
- expect(Currency.new(:eur)).to eq 'EUR'
294
- expect(Currency.new(:eur)).to eq :eur
295
- expect(Currency.new(:eur)).to eq :EUR
296
- expect(Currency.new(:eur)).not_to eq 'usd'
297
- end
298
-
299
- it "allows comparison with nil and returns false" do
300
- expect(Currency.new(:eur)).not_to be_nil
301
- end
302
- end
303
-
304
- describe "#eql?" do
305
- it "returns true if #== returns true" do
306
- expect(Currency.new(:eur).eql?(Currency.new(:eur))).to be true
307
- expect(Currency.new(:eur).eql?(Currency.new(:usd))).to be false
308
- end
309
- end
310
-
311
- describe "#hash" do
312
- it "returns the same value for equal objects" do
313
- expect(Currency.new(:eur).hash).to eq Currency.new(:eur).hash
314
- expect(Currency.new(:eur).hash).not_to eq Currency.new(:usd).hash
315
- end
316
-
317
- it "can be used to return the intersection of Currency object arrays" do
318
- intersection = [Currency.new(:eur), Currency.new(:usd)] & [Currency.new(:eur)]
319
- expect(intersection).to eq [Currency.new(:eur)]
320
- end
321
- end
322
-
323
- describe "#inspect" do
324
- it "works as documented" do
325
- expect(Currency.new(:usd).inspect).to eq %Q{#<Money::Currency id: usd, priority: 1, symbol_first: true, thousands_separator: ,, html_entity: $, decimal_mark: ., name: United States Dollar, symbol: $, subunit_to_unit: 100, exponent: 2, iso_code: USD, iso_numeric: 840, subunit: Cent, smallest_denomination: 1>}
326
- end
327
- end
328
-
329
- describe "#iso?" do
330
- it "returns true for iso currency" do
331
- expect(Money::Currency.new(:eur).iso?).to be true
332
- end
333
-
334
- it "returns false if the currency is not iso" do
335
- expect(Money::Currency.new(:btc).iso?).to be false
336
- end
337
- end
338
-
339
- describe "#to_s" do
340
- it "works as documented" do
341
- expect(Currency.new(:usd).to_s).to eq("USD")
342
- expect(Currency.new(:eur).to_s).to eq("EUR")
343
- end
344
- end
345
-
346
- describe "#to_str" do
347
- it "works as documented" do
348
- expect(Currency.new(:usd).to_str).to eq("USD")
349
- expect(Currency.new(:eur).to_str).to eq("EUR")
350
- end
351
- end
352
-
353
- describe "#to_sym" do
354
- it "works as documented" do
355
- expect(Currency.new(:usd).to_sym).to eq(:USD)
356
- expect(Currency.new(:eur).to_sym).to eq(:EUR)
357
- end
358
- end
359
-
360
- describe "#to_currency" do
361
- it "works as documented" do
362
- usd = Currency.new(:usd)
363
- expect(usd.to_currency).to eq usd
364
- end
365
-
366
- it "doesn't create new symbols indefinitely" do
367
- expect { Currency.new("bogus") }.to raise_exception(Currency::UnknownCurrency)
368
- expect(Symbol.all_symbols.map{|s| s.to_s}).not_to include("bogus")
369
- end
370
- end
371
-
372
- describe "#code" do
373
- it "works as documented" do
374
- expect(Currency.new(:usd).code).to eq "$"
375
- expect(Currency.new(:azn).code).to eq "\u20BC"
376
- end
377
- end
378
-
379
- describe "#exponent" do
380
- it "conforms to iso 4217" do
381
- expect(Currency.new(:jpy).exponent).to eq 0
382
- expect(Currency.new(:usd).exponent).to eq 2
383
- expect(Currency.new(:iqd).exponent).to eq 3
384
- end
385
- end
386
-
387
- describe "#decimal_places" do
388
- it "proper places for known currency" do
389
- expect(Currency.new(:mro).decimal_places).to eq 1
390
- expect(Currency.new(:usd).decimal_places).to eq 2
391
- end
392
-
393
- it "proper places for custom currency" do
394
- register_foo
395
- expect(Currency.new(:foo).decimal_places).to eq 3
396
- unregister_foo
397
- end
398
- end
399
- end
400
- end