money 6.7.1 → 6.13.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -1
  3. data/.travis.yml +15 -6
  4. data/AUTHORS +5 -0
  5. data/CHANGELOG.md +98 -3
  6. data/Gemfile +13 -4
  7. data/LICENSE +2 -0
  8. data/README.md +64 -44
  9. data/config/currency_backwards_compatible.json +30 -0
  10. data/config/currency_iso.json +135 -59
  11. data/config/currency_non_iso.json +66 -2
  12. data/lib/money.rb +0 -13
  13. data/lib/money/bank/variable_exchange.rb +9 -22
  14. data/lib/money/currency.rb +33 -39
  15. data/lib/money/currency/heuristics.rb +1 -144
  16. data/lib/money/currency/loader.rb +1 -1
  17. data/lib/money/locale_backend/base.rb +7 -0
  18. data/lib/money/locale_backend/errors.rb +6 -0
  19. data/lib/money/locale_backend/i18n.rb +24 -0
  20. data/lib/money/locale_backend/legacy.rb +28 -0
  21. data/lib/money/money.rb +106 -139
  22. data/lib/money/money/allocation.rb +37 -0
  23. data/lib/money/money/arithmetic.rb +31 -28
  24. data/lib/money/money/constructors.rb +1 -2
  25. data/lib/money/money/formatter.rb +397 -0
  26. data/lib/money/money/formatting_rules.rb +120 -0
  27. data/lib/money/money/locale_backend.rb +20 -0
  28. data/lib/money/rates_store/memory.rb +1 -2
  29. data/lib/money/version.rb +1 -1
  30. data/money.gemspec +10 -16
  31. data/spec/bank/variable_exchange_spec.rb +7 -3
  32. data/spec/currency/heuristics_spec.rb +2 -153
  33. data/spec/currency_spec.rb +44 -3
  34. data/spec/locale_backend/i18n_spec.rb +62 -0
  35. data/spec/locale_backend/legacy_spec.rb +74 -0
  36. data/spec/money/allocation_spec.rb +130 -0
  37. data/spec/money/arithmetic_spec.rb +184 -90
  38. data/spec/money/constructors_spec.rb +0 -12
  39. data/spec/money/formatting_spec.rb +296 -179
  40. data/spec/money/locale_backend_spec.rb +14 -0
  41. data/spec/money_spec.rb +159 -26
  42. data/spec/rates_store/memory_spec.rb +13 -2
  43. data/spec/spec_helper.rb +2 -0
  44. data/spec/support/shared_examples/money_examples.rb +14 -0
  45. metadata +32 -40
  46. data/lib/money/money/formatting.rb +0 -418
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+
3
+ describe Money::LocaleBackend do
4
+ describe '.find' do
5
+ it 'returns an initialized backend' do
6
+ expect(described_class.find(:legacy)).to be_a(Money::LocaleBackend::Legacy)
7
+ expect(described_class.find(:i18n)).to be_a(Money::LocaleBackend::I18n)
8
+ end
9
+
10
+ it 'raises an error if a backend is unknown' do
11
+ expect { described_class.find(:foo) }.to raise_error(Money::LocaleBackend::Unknown)
12
+ end
13
+ end
14
+ end
@@ -1,6 +1,22 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  describe Money do
4
+ describe '.locale_backend' do
5
+ after { Money.locale_backend = :legacy }
6
+
7
+ it 'sets the locale_backend' do
8
+ Money.locale_backend = :i18n
9
+
10
+ expect(Money.locale_backend).to be_a(Money::LocaleBackend::I18n)
11
+ end
12
+
13
+ it 'sets the locale_backend to nil' do
14
+ Money.locale_backend = nil
15
+
16
+ expect(Money.locale_backend).to eq(nil)
17
+ end
18
+ end
19
+
4
20
  describe ".new" do
5
21
  let(:initializing_value) { 1 }
6
22
  subject(:money) { Money.new(initializing_value) }
@@ -169,6 +185,16 @@ describe Money do
169
185
  Money.from_amount(1.999).to_d
170
186
  end).to eq 1.99
171
187
  end
188
+
189
+ context 'given a currency is provided' do
190
+ context 'and the currency is nil' do
191
+ let(:currency) { nil }
192
+
193
+ it "should have the default currency" do
194
+ expect(Money.from_amount(1, currency).currency).to eq Money.default_currency
195
+ end
196
+ end
197
+ end
172
198
  end
173
199
 
174
200
  %w[cents pence].each do |units|
@@ -191,7 +217,7 @@ describe Money do
191
217
  it "stores fractional as an integer regardless of what is passed into the constructor" do
192
218
  m = Money.new(100)
193
219
  expect(m.fractional).to eq 100
194
- expect(m.fractional).to be_a(Fixnum)
220
+ expect(m.fractional).to be_a(Integer)
195
221
  end
196
222
 
197
223
  context "loading a serialized Money via YAML" do
@@ -349,9 +375,9 @@ YAML
349
375
  expect {money.round_to_nearest_cash_value}.to raise_error(Money::UndefinedSmallestDenomination)
350
376
  end
351
377
 
352
- it "returns a Fixnum when infinite_precision is not set" do
378
+ it "returns a Integer when infinite_precision is not set" do
353
379
  money = Money.new(100, "USD")
354
- expect(money.round_to_nearest_cash_value).to be_a Fixnum
380
+ expect(money.round_to_nearest_cash_value).to be_a Integer
355
381
  end
356
382
 
357
383
  it "returns a BigDecimal when infinite_precision is set", :infinite_precision do
@@ -408,12 +434,16 @@ YAML
408
434
  end
409
435
 
410
436
  describe "#currency_as_string=" do
411
- it "sets the currency object using the provided string" do
437
+ it "sets the currency object using the provided string leaving cents intact" do
412
438
  money = Money.new(100_00, "USD")
439
+
413
440
  money.currency_as_string = "EUR"
414
441
  expect(money.currency).to eq Money::Currency.new("EUR")
442
+ expect(money.cents).to eq 100_00
443
+
415
444
  money.currency_as_string = "YEN"
416
445
  expect(money.currency).to eq Money::Currency.new("YEN")
446
+ expect(money.cents).to eq 100_00
417
447
  end
418
448
  end
419
449
 
@@ -468,6 +498,24 @@ YAML
468
498
  expect(Money.new(10_00, "BRL").to_s).to eq "10,00"
469
499
  end
470
500
 
501
+ context "using i18n" do
502
+ before { I18n.backend.store_translations(:en, number: { format: { separator: "." } }) }
503
+ after { reset_i18n }
504
+
505
+ it "respects decimal mark" do
506
+ expect(Money.new(10_00, "BRL").to_s).to eq "10.00"
507
+ end
508
+ end
509
+
510
+ context "with defaults set" do
511
+ before { Money.default_formatting_rules = { with_currency: true } }
512
+ after { Money.default_formatting_rules = nil }
513
+
514
+ it "ignores defaults" do
515
+ expect(Money.new(10_00, 'USD').to_s).to eq '10.00'
516
+ end
517
+ end
518
+
471
519
  context "with infinite_precision", :infinite_precision do
472
520
  it "shows fractional cents" do
473
521
  expect(Money.new(1.05, "USD").to_s).to eq "0.0105"
@@ -536,6 +584,25 @@ YAML
536
584
  end
537
585
  end
538
586
 
587
+ describe "#with_currency" do
588
+ it 'returns self if currency is the same' do
589
+ money = Money.new(10_00, 'USD')
590
+
591
+ expect(money.with_currency('USD')).to eq(money)
592
+ expect(money.with_currency('USD').object_id).to eq(money.object_id)
593
+ end
594
+
595
+ it 'returns a new instance in a given currency' do
596
+ money = Money.new(10_00, 'USD')
597
+ new_money = money.with_currency('EUR')
598
+
599
+ expect(new_money).to eq(Money.new(10_00, 'EUR'))
600
+ expect(money.fractional).to eq(new_money.fractional)
601
+ expect(money.bank).to eq(new_money.bank)
602
+ expect(money.object_id).not_to eq(new_money.object_id)
603
+ end
604
+ end
605
+
539
606
  describe "#exchange_to" do
540
607
  it "exchanges the amount via its exchange bank" do
541
608
  money = Money.new(100_00, "USD")
@@ -577,6 +644,18 @@ YAML
577
644
  expect(moneys[1]).to eq Money.us_dollar(3)
578
645
  end
579
646
 
647
+ it "handles small splits" do
648
+ moneys = Money.us_dollar(5).allocate([0.03, 0.07])
649
+ expect(moneys[0]).to eq Money.us_dollar(2)
650
+ expect(moneys[1]).to eq Money.us_dollar(3)
651
+ end
652
+
653
+ it "handles large splits" do
654
+ moneys = Money.us_dollar(5).allocate([3, 7])
655
+ expect(moneys[0]).to eq Money.us_dollar(2)
656
+ expect(moneys[1]).to eq Money.us_dollar(3)
657
+ end
658
+
580
659
  it "does not lose pennies" do
581
660
  moneys = Money.us_dollar(100).allocate([0.333, 0.333, 0.333])
582
661
  expect(moneys[0].cents).to eq 34
@@ -584,8 +663,37 @@ YAML
584
663
  expect(moneys[2].cents).to eq 33
585
664
  end
586
665
 
587
- it "requires total to be less then 1" do
588
- expect { Money.us_dollar(0.05).allocate([0.5, 0.6]) }.to raise_error(ArgumentError)
666
+ it "does not round rationals" do
667
+ splits = 7.times.map { Rational(950, 6650) }
668
+ moneys = Money.us_dollar(6650).allocate(splits)
669
+ moneys.each do |money|
670
+ expect(money.cents).to eq 950
671
+ end
672
+ end
673
+
674
+ it "handles mixed split types" do
675
+ splits = [Rational(1, 4), 0.25, 0.25, BigDecimal('0.25')]
676
+ moneys = Money.us_dollar(100).allocate(splits)
677
+ moneys.each do |money|
678
+ expect(money.cents).to eq 25
679
+ end
680
+ end
681
+
682
+ context "negative amount" do
683
+ it "does not lose pennies" do
684
+ moneys = Money.us_dollar(-100).allocate([0.333, 0.333, 0.333])
685
+
686
+ expect(moneys[0].cents).to eq(-34)
687
+ expect(moneys[1].cents).to eq(-33)
688
+ expect(moneys[2].cents).to eq(-33)
689
+ end
690
+
691
+ it "allocates the same way as positive amounts" do
692
+ ratios = [0.6667, 0.3333]
693
+
694
+ expect(Money.us_dollar(10_00).allocate(ratios).map(&:fractional)).to eq([6_67, 3_33])
695
+ expect(Money.us_dollar(-10_00).allocate(ratios).map(&:fractional)).to eq([-6_67, -3_33])
696
+ end
589
697
  end
590
698
 
591
699
  it "keeps subclasses intact" do
@@ -595,12 +703,8 @@ YAML
595
703
 
596
704
  context "with infinite_precision", :infinite_precision do
597
705
  it "allows for fractional cents allocation" do
598
- one_third = BigDecimal("1") / BigDecimal("3")
599
-
600
- moneys = Money.new(100).allocate([one_third, one_third, one_third])
601
- expect(moneys[0].cents).to eq one_third * BigDecimal("100")
602
- expect(moneys[1].cents).to eq one_third * BigDecimal("100")
603
- expect(moneys[2].cents).to eq one_third * BigDecimal("100")
706
+ moneys = Money.new(100).allocate([1, 1, 1])
707
+ expect(moneys.inject(0, :+)).to eq(Money.new(100))
604
708
  end
605
709
  end
606
710
  end
@@ -637,27 +741,40 @@ YAML
637
741
 
638
742
  context "with infinite_precision", :infinite_precision do
639
743
  it "allows for splitting by fractional cents" do
640
- thirty_three_and_one_third = BigDecimal("100") / BigDecimal("3")
641
-
642
744
  moneys = Money.new(100).split(3)
643
- expect(moneys[0].cents).to eq thirty_three_and_one_third
644
- expect(moneys[1].cents).to eq thirty_three_and_one_third
645
- expect(moneys[2].cents).to eq thirty_three_and_one_third
745
+ expect(moneys.inject(0, :+)).to eq(Money.new(100))
646
746
  end
647
747
  end
648
748
  end
649
749
 
650
750
  describe "#round" do
651
-
652
751
  let(:money) { Money.new(15.75, 'NZD') }
653
752
  subject(:rounded) { money.round }
654
753
 
655
754
  context "without infinite_precision" do
656
- it "returns self (as it is already rounded)" do
657
- rounded = money.round
658
- expect(rounded).to be money
755
+ it "returns a different money" do
756
+ expect(rounded).not_to be money
757
+ end
758
+
759
+ it "rounds the cents" do
659
760
  expect(rounded.cents).to eq 16
660
761
  end
762
+
763
+ it "maintains the currency" do
764
+ expect(rounded.currency).to eq Money::Currency.new('NZD')
765
+ end
766
+
767
+ it "uses a provided rounding strategy" do
768
+ rounded = money.round(BigDecimal::ROUND_DOWN)
769
+ expect(rounded.cents).to eq 15
770
+ end
771
+
772
+ it "does not accumulate rounding error" do
773
+ money_1 = Money.new(10.9).round(BigDecimal::ROUND_DOWN)
774
+ money_2 = Money.new(10.9).round(BigDecimal::ROUND_DOWN)
775
+
776
+ expect(money_1 + money_2).to eq(Money.new(20))
777
+ end
661
778
  end
662
779
 
663
780
  context "with infinite_precision", :infinite_precision do
@@ -678,15 +795,31 @@ YAML
678
795
  expect(rounded.cents).to eq 15
679
796
  end
680
797
 
681
- context "when using a subclass of Money" do
682
- let(:special_money_class) { Class.new(Money) }
683
- let(:money) { special_money_class.new(15.75, 'NZD') }
798
+ context "when using a specific rounding precision" do
799
+ let(:money) { Money.new(15.7526, 'NZD') }
684
800
 
685
- it "preserves the class in the result" do
686
- expect(rounded).to be_a special_money_class
801
+ it "uses the provided rounding precision" do
802
+ rounded = money.round(BigDecimal::ROUND_DOWN, 3)
803
+ expect(rounded.fractional).to eq 15.752
687
804
  end
688
805
  end
689
806
  end
807
+
808
+ it 'preserves assigned bank' do
809
+ bank = Money::Bank::VariableExchange.new
810
+ rounded = Money.new(1_00, 'USD', bank).round
811
+
812
+ expect(rounded.bank).to eq(bank)
813
+ end
814
+
815
+ context "when using a subclass of Money" do
816
+ let(:special_money_class) { Class.new(Money) }
817
+ let(:money) { special_money_class.new(15.75, 'NZD') }
818
+
819
+ it "preserves the class in the result" do
820
+ expect(rounded).to be_a special_money_class
821
+ end
822
+ end
690
823
  end
691
824
 
692
825
  describe "#inspect" do
@@ -15,7 +15,7 @@ describe Money::RatesStore::Memory do
15
15
  end
16
16
 
17
17
  context ':without_mutex' do
18
- let(:subject) { Money::RatesStore::Memory.new(:without_mutex => true) }
18
+ let(:subject) { Money::RatesStore::Memory.new(without_mutex: true) }
19
19
 
20
20
  it "doesn't use mutex if requested not to" do
21
21
  expect(subject.instance_variable_get(:@mutex)).not_to receive(:synchronize)
@@ -58,7 +58,7 @@ describe Money::RatesStore::Memory do
58
58
  end
59
59
 
60
60
  context 'no mutex' do
61
- let(:subject) { Money::RatesStore::Memory.new(:without_mutex => true) }
61
+ let(:subject) { Money::RatesStore::Memory.new(without_mutex: true) }
62
62
 
63
63
  it 'does not use mutex' do
64
64
  expect(subject.instance_variable_get('@mutex')).not_to receive(:synchronize)
@@ -66,4 +66,15 @@ describe Money::RatesStore::Memory do
66
66
  end
67
67
  end
68
68
  end
69
+
70
+ describe '#marshal_dump' do
71
+ let(:subject) { Money::RatesStore::Memory.new(optional: true) }
72
+
73
+ it 'can reload' do
74
+ bank = Money::Bank::VariableExchange.new(subject)
75
+ bank = Marshal.load(Marshal.dump(bank))
76
+ expect(bank.store.instance_variable_get(:@options)).to eq subject.instance_variable_get(:@options)
77
+ expect(bank.store.instance_variable_get(:@index)).to eq subject.instance_variable_get(:@index)
78
+ end
79
+ end
69
80
  end
@@ -5,6 +5,8 @@ $LOAD_PATH.unshift File.dirname(__FILE__)
5
5
  require "rspec"
6
6
  require "money"
7
7
 
8
+ Dir['./spec/support/**/*.rb'].sort.each { |f| require f }
9
+
8
10
  I18n.enforce_available_locales = false
9
11
 
10
12
  RSpec.configure do |c|
@@ -0,0 +1,14 @@
1
+ RSpec.shared_examples 'instance with custom bank' do |operation, value|
2
+ let(:custom_bank) { Money::Bank::VariableExchange.new }
3
+ let(:instance) { Money.new(1, :usd, custom_bank) }
4
+
5
+ subject { value ? instance.send(operation, value) : instance.send(operation) }
6
+
7
+ it "returns custom bank from new instance" do
8
+ new_money_instances = Array(subject).select { |el| el.is_a?(Money) }
9
+
10
+ new_money_instances.each do |money_instance|
11
+ expect(money_instance.bank).to eq(custom_bank)
12
+ end
13
+ end
14
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: money
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.7.1
4
+ version: 6.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shane Emmons
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-08 00:00:00.000000000 Z
11
+ date: 2018-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: 0.6.4
20
20
  - - "<="
21
21
  - !ruby/object:Gem::Version
22
- version: 0.7.0
22
+ version: '2'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -28,26 +28,6 @@ dependencies:
28
28
  - !ruby/object:Gem::Version
29
29
  version: 0.6.4
30
30
  - - "<="
31
- - !ruby/object:Gem::Version
32
- version: 0.7.0
33
- - !ruby/object:Gem::Dependency
34
- name: sixarm_ruby_unaccent
35
- requirement: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - ">="
38
- - !ruby/object:Gem::Version
39
- version: 1.1.1
40
- - - "<"
41
- - !ruby/object:Gem::Version
42
- version: '2'
43
- type: :runtime
44
- prerelease: false
45
- version_requirements: !ruby/object:Gem::Requirement
46
- requirements:
47
- - - ">="
48
- - !ruby/object:Gem::Version
49
- version: 1.1.1
50
- - - "<"
51
31
  - !ruby/object:Gem::Version
52
32
  version: '2'
53
33
  - !ruby/object:Gem::Dependency
@@ -84,28 +64,28 @@ dependencies:
84
64
  requirements:
85
65
  - - "~>"
86
66
  - !ruby/object:Gem::Version
87
- version: 3.4.0
67
+ version: '3.4'
88
68
  type: :development
89
69
  prerelease: false
90
70
  version_requirements: !ruby/object:Gem::Requirement
91
71
  requirements:
92
72
  - - "~>"
93
73
  - !ruby/object:Gem::Version
94
- version: 3.4.0
74
+ version: '3.4'
95
75
  - !ruby/object:Gem::Dependency
96
76
  name: yard
97
77
  requirement: !ruby/object:Gem::Requirement
98
78
  requirements:
99
79
  - - "~>"
100
80
  - !ruby/object:Gem::Version
101
- version: '0.8'
81
+ version: 0.9.11
102
82
  type: :development
103
83
  prerelease: false
104
84
  version_requirements: !ruby/object:Gem::Requirement
105
85
  requirements:
106
86
  - - "~>"
107
87
  - !ruby/object:Gem::Version
108
- version: '0.8'
88
+ version: 0.9.11
109
89
  - !ruby/object:Gem::Dependency
110
90
  name: kramdown
111
91
  requirement: !ruby/object:Gem::Requirement
@@ -148,10 +128,17 @@ files:
148
128
  - lib/money/currency.rb
149
129
  - lib/money/currency/heuristics.rb
150
130
  - lib/money/currency/loader.rb
131
+ - lib/money/locale_backend/base.rb
132
+ - lib/money/locale_backend/errors.rb
133
+ - lib/money/locale_backend/i18n.rb
134
+ - lib/money/locale_backend/legacy.rb
151
135
  - lib/money/money.rb
136
+ - lib/money/money/allocation.rb
152
137
  - lib/money/money/arithmetic.rb
153
138
  - lib/money/money/constructors.rb
154
- - lib/money/money/formatting.rb
139
+ - lib/money/money/formatter.rb
140
+ - lib/money/money/formatting_rules.rb
141
+ - lib/money/money/locale_backend.rb
155
142
  - lib/money/rates_store/memory.rb
156
143
  - lib/money/version.rb
157
144
  - money.gemspec
@@ -161,25 +148,25 @@ files:
161
148
  - spec/currency/heuristics_spec.rb
162
149
  - spec/currency/loader_spec.rb
163
150
  - spec/currency_spec.rb
151
+ - spec/locale_backend/i18n_spec.rb
152
+ - spec/locale_backend/legacy_spec.rb
153
+ - spec/money/allocation_spec.rb
164
154
  - spec/money/arithmetic_spec.rb
165
155
  - spec/money/constructors_spec.rb
166
156
  - spec/money/formatting_spec.rb
157
+ - spec/money/locale_backend_spec.rb
167
158
  - spec/money_spec.rb
168
159
  - spec/rates_store/memory_spec.rb
169
160
  - spec/spec_helper.rb
170
- homepage: http://rubymoney.github.io/money
161
+ - spec/support/shared_examples/money_examples.rb
162
+ homepage: https://rubymoney.github.io/money
171
163
  licenses:
172
164
  - MIT
173
- metadata: {}
174
- post_install_message: |
175
- Please note the following API changes in Money version 6
176
-
177
- - Money#amount, Money#dollars methods now return instances of BigDecimal (rather than Float).
178
-
179
- Please read the migration notes at https://github.com/RubyMoney/money#migration-notes
180
- and choose the migration that best suits your application.
181
-
182
- Test responsibly :-)
165
+ metadata:
166
+ changelog_uri: https://github.com/RubyMoney/money/blob/master/CHANGELOG.md
167
+ source_code_uri: https://github.com/RubyMoney/money/
168
+ bug_tracker_uri: https://github.com/RubyMoney/money/issues
169
+ post_install_message:
183
170
  rdoc_options: []
184
171
  require_paths:
185
172
  - lib
@@ -195,7 +182,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
195
182
  version: '0'
196
183
  requirements: []
197
184
  rubyforge_project:
198
- rubygems_version: 2.5.1
185
+ rubygems_version: 2.6.8
199
186
  signing_key:
200
187
  specification_version: 4
201
188
  summary: A Ruby Library for dealing with money and currency conversion.
@@ -206,9 +193,14 @@ test_files:
206
193
  - spec/currency/heuristics_spec.rb
207
194
  - spec/currency/loader_spec.rb
208
195
  - spec/currency_spec.rb
196
+ - spec/locale_backend/i18n_spec.rb
197
+ - spec/locale_backend/legacy_spec.rb
198
+ - spec/money/allocation_spec.rb
209
199
  - spec/money/arithmetic_spec.rb
210
200
  - spec/money/constructors_spec.rb
211
201
  - spec/money/formatting_spec.rb
202
+ - spec/money/locale_backend_spec.rb
212
203
  - spec/money_spec.rb
213
204
  - spec/rates_store/memory_spec.rb
214
205
  - spec/spec_helper.rb
206
+ - spec/support/shared_examples/money_examples.rb