shopify-money 0.12.0 → 0.14.2

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -3
  3. data/Gemfile +2 -1
  4. data/README.md +20 -1
  5. data/Rakefile +1 -0
  6. data/bin/console +1 -0
  7. data/config/currency_iso.json +1 -1
  8. data/dev.yml +1 -1
  9. data/lib/money.rb +4 -0
  10. data/lib/money/allocator.rb +144 -0
  11. data/lib/money/core_extensions.rb +1 -0
  12. data/lib/money/currency.rb +1 -0
  13. data/lib/money/currency/loader.rb +1 -0
  14. data/lib/money/deprecations.rb +1 -0
  15. data/lib/money/errors.rb +1 -0
  16. data/lib/money/helpers.rb +5 -15
  17. data/lib/money/money.rb +8 -111
  18. data/lib/money/null_currency.rb +1 -0
  19. data/lib/money/version.rb +2 -1
  20. data/lib/money_accessor.rb +1 -0
  21. data/lib/money_column.rb +1 -0
  22. data/lib/money_column/active_record_hooks.rb +2 -1
  23. data/lib/money_column/active_record_type.rb +1 -0
  24. data/lib/money_column/railtie.rb +1 -0
  25. data/lib/rubocop/cop/money.rb +3 -0
  26. data/lib/rubocop/cop/money/missing_currency.rb +75 -0
  27. data/lib/shopify-money.rb +2 -0
  28. data/money.gemspec +7 -3
  29. data/spec/accounting_money_parser_spec.rb +1 -0
  30. data/spec/allocator_spec.rb +148 -0
  31. data/spec/core_extensions_spec.rb +2 -1
  32. data/spec/currency/loader_spec.rb +1 -0
  33. data/spec/currency_spec.rb +1 -0
  34. data/spec/helpers_spec.rb +1 -6
  35. data/spec/money_accessor_spec.rb +1 -0
  36. data/spec/money_column_spec.rb +1 -0
  37. data/spec/money_parser_spec.rb +1 -0
  38. data/spec/money_spec.rb +13 -96
  39. data/spec/null_currency_spec.rb +1 -0
  40. data/spec/rubocop/cop/money/missing_currency_spec.rb +108 -0
  41. data/spec/rubocop_helper.rb +10 -0
  42. data/spec/schema.rb +1 -0
  43. data/spec/spec_helper.rb +1 -5
  44. metadata +20 -24
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class Money
2
3
  class NullCurrency
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class Money
2
- VERSION = "0.12.0"
3
+ VERSION = "0.14.2"
3
4
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module MoneyAccessor
2
3
  def self.included(base)
3
4
  base.extend(ClassMethods)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require_relative 'money_column/active_record_hooks'
2
3
  require_relative 'money_column/active_record_type'
3
4
  require_relative 'money_column/railtie'
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module MoneyColumn
2
3
  module ActiveRecordHooks
3
4
  def self.included(base)
@@ -57,7 +58,7 @@ module MoneyColumn
57
58
  if options[:currency_read_only]
58
59
  currency_source = Money::Helpers.value_to_currency(currency_raw_source)
59
60
  if currency_raw_source && !money.currency.compatible?(currency_source)
60
- Money.deprecate("[money_column] currency mismatch between #{currency_source} and #{money.currency}.")
61
+ Money.deprecate("[money_column] currency mismatch between #{currency_source} and #{money.currency} in column #{column}.")
61
62
  end
62
63
  else
63
64
  self[options[:currency_column]] = money.currency.to_s unless money.no_currency?
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class MoneyColumn::ActiveRecordType < ActiveRecord::Type::Decimal
2
3
  def serialize(money)
3
4
  return nil unless money
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module MoneyColumn
2
3
  class Railtie < Rails::Railtie
3
4
  ActiveSupport.on_load :active_record do
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop/cop/money/missing_currency'
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Money
6
+ class MissingCurrency < Cop
7
+ # `Money.new()` without a currency argument cannot guarantee correctness:
8
+ # - no error raised for cross-currency computation (e.g. 5 CAD + 5 USD)
9
+ # - #subunits returns wrong values for 0 and 3 decimals currencies
10
+ #
11
+ # @example
12
+ # # bad
13
+ # Money.new(123.45)
14
+ # Money.new
15
+ # "1,234.50".to_money
16
+ #
17
+ # # good
18
+ # Money.new(123.45, 'CAD')
19
+ # "1,234.50".to_money('CAD')
20
+ #
21
+
22
+ def_node_matcher :money_new, <<~PATTERN
23
+ (send (const nil? :Money) {:new :from_amount :from_cents} $...)
24
+ PATTERN
25
+
26
+ def_node_matcher :to_money_without_currency?, <<~PATTERN
27
+ (send _ :to_money)
28
+ PATTERN
29
+
30
+ def_node_matcher :to_money_block?, <<~PATTERN
31
+ (send _ _ (block_pass (sym :to_money)))
32
+ PATTERN
33
+
34
+ def on_send(node)
35
+ money_new(node) do |_amount, currency_arg|
36
+ return if currency_arg
37
+
38
+ add_offense(node, message: 'Money is missing currency argument')
39
+ end
40
+
41
+ if to_money_block?(node) || to_money_without_currency?(node)
42
+ add_offense(node, message: 'to_money is missing currency argument')
43
+ end
44
+ end
45
+
46
+ def autocorrect(node)
47
+ currency = cop_config['ReplacementCurrency']
48
+ return unless currency
49
+
50
+ receiver, method, _ = *node
51
+
52
+ lambda do |corrector|
53
+ money_new(node) do |amount, currency_arg|
54
+ return if currency_arg
55
+
56
+ corrector.replace(
57
+ node.loc.expression,
58
+ "#{receiver.source}.#{method}(#{amount&.source || 0}, '#{currency}')"
59
+ )
60
+ end
61
+
62
+ if to_money_without_currency?(node)
63
+ corrector.insert_after(node.loc.expression, "('#{currency}')")
64
+ elsif to_money_block?(node)
65
+ corrector.replace(
66
+ node.loc.expression,
67
+ "#{receiver.source}.#{method} { |x| x.to_money('#{currency}') }"
68
+ )
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,2 @@
1
+ # frozen_string_literal: true
2
+ require_relative 'money'
@@ -1,4 +1,5 @@
1
1
  # -*- encoding: utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  require_relative "lib/money/version"
3
4
 
4
5
  Gem::Specification.new do |s|
@@ -12,13 +13,16 @@ Gem::Specification.new do |s|
12
13
  s.licenses = "MIT"
13
14
  s.summary = "Shopify's money gem"
14
15
 
16
+ s.metadata['allowed_push_host'] = "https://rubygems.org"
17
+
15
18
  s.add_development_dependency("bundler", ">= 1.5")
16
19
  s.add_development_dependency("simplecov", ">= 0")
17
- s.add_development_dependency("rails", "~> 5.0")
20
+ s.add_development_dependency("rails", "~> 6.0")
18
21
  s.add_development_dependency("rspec", "~> 3.2")
19
22
  s.add_development_dependency("database_cleaner", "~> 1.6")
20
- s.add_development_dependency("sqlite3", "~> 1.3.6")
21
- s.add_development_dependency("bigdecimal", "~> 1.3.2")
23
+ s.add_development_dependency("sqlite3", "~> 1.4.2")
24
+
25
+ s.required_ruby_version = '>= 2.6'
22
26
 
23
27
  s.files = `git ls-files`.split($/)
24
28
  s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  RSpec.describe AccountingMoneyParser do
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+
4
+ RSpec.describe "Allocator" do
5
+ describe "allocate"do
6
+ specify "#allocate takes no action when one gets all" do
7
+ expect(new_allocator(5).allocate([1])).to eq([Money.new(5)])
8
+ end
9
+
10
+ specify "#allocate does not lose pennies" do
11
+ moneys = new_allocator(0.05).allocate([0.3,0.7])
12
+ expect(moneys[0]).to eq(Money.new(0.02))
13
+ expect(moneys[1]).to eq(Money.new(0.03))
14
+ end
15
+
16
+ specify "#allocate does not lose dollars with non-decimal currency" do
17
+ moneys = new_allocator(5, 'JPY').allocate([0.3,0.7])
18
+ expect(moneys[0]).to eq(Money.new(2, 'JPY'))
19
+ expect(moneys[1]).to eq(Money.new(3, 'JPY'))
20
+ end
21
+
22
+ specify "#allocate does not lose dollars with three decimal currency" do
23
+ moneys = new_allocator(0.005, 'JOD').allocate([0.3,0.7])
24
+ expect(moneys[0]).to eq(Money.new(0.002, 'JOD'))
25
+ expect(moneys[1]).to eq(Money.new(0.003, 'JOD'))
26
+ end
27
+
28
+ specify "#allocate does not lose pennies even when given a lossy split" do
29
+ moneys = new_allocator(1).allocate([0.333,0.333, 0.333])
30
+ expect(moneys[0].subunits).to eq(34)
31
+ expect(moneys[1].subunits).to eq(33)
32
+ expect(moneys[2].subunits).to eq(33)
33
+ end
34
+
35
+ specify "#allocate requires total to be less than 1" do
36
+ expect { new_allocator(0.05).allocate([0.5,0.6]) }.to raise_error(ArgumentError)
37
+ end
38
+
39
+ specify "#allocate will use rationals if provided" do
40
+ splits = [128400,20439,14589,14589,25936].map{ |num| Rational(num, 203953) } # sums to > 1 if converted to float
41
+ expect(new_allocator(2.25).allocate(splits)).to eq([Money.new(1.42), Money.new(0.23), Money.new(0.16), Money.new(0.16), Money.new(0.28)])
42
+ end
43
+
44
+ specify "#allocate will convert rationals with high precision" do
45
+ ratios = [Rational(1, 1), Rational(0)]
46
+ expect(new_allocator("858993456.12").allocate(ratios)).to eq([Money.new("858993456.12"), Money.empty])
47
+ ratios = [Rational(1, 6), Rational(5, 6)]
48
+ expect(new_allocator("3.00").allocate(ratios)).to eq([Money.new("0.50"), Money.new("2.50")])
49
+ end
50
+
51
+ specify "#allocate doesn't raise with weird negative rational ratios" do
52
+ rate = Rational(-5, 1201)
53
+ expect { new_allocator(1).allocate([rate, 1 - rate]) }.not_to raise_error
54
+ end
55
+
56
+ specify "#allocate fills pennies from beginning to end with roundrobin strategy" do
57
+ moneys = new_allocator(0.05).allocate([0.3,0.7], :roundrobin)
58
+ expect(moneys[0]).to eq(Money.new(0.02))
59
+ expect(moneys[1]).to eq(Money.new(0.03))
60
+ end
61
+
62
+ specify "#allocate fills pennies from end to beginning with roundrobin_reverse strategy" do
63
+ moneys = new_allocator(0.05).allocate([0.3,0.7], :roundrobin_reverse)
64
+ expect(moneys[0]).to eq(Money.new(0.01))
65
+ expect(moneys[1]).to eq(Money.new(0.04))
66
+ end
67
+
68
+ specify "#allocate raise ArgumentError when invalid strategy is provided" do
69
+ expect { new_allocator(0.03).allocate([0.5, 0.5], :bad_strategy_name) }.to raise_error(ArgumentError, "Invalid strategy. Valid options: :roundrobin, :roundrobin_reverse")
70
+ end
71
+
72
+ specify "#allocate does not raise ArgumentError when invalid splits types are provided" do
73
+ moneys = new_allocator(0.03).allocate([0.5, 0.5], :roundrobin)
74
+ expect(moneys[0]).to eq(Money.new(0.02))
75
+ expect(moneys[1]).to eq(Money.new(0.01))
76
+ end
77
+ end
78
+
79
+ describe 'allocate_max_amounts' do
80
+ specify "#allocate_max_amounts returns the weighted allocation without exceeding the maxima when there is room for the remainder" do
81
+ expect(
82
+ new_allocator(30.75).allocate_max_amounts([Money.new(26), Money.new(4.75)]),
83
+ ).to eq([Money.new(26), Money.new(4.75)])
84
+ end
85
+
86
+ specify "#allocate_max_amounts returns the weighted allocation without exceeding the maxima when there is room for the remainder with currency" do
87
+ expect(
88
+ new_allocator(3075, 'JPY').allocate_max_amounts([Money.new(2600, 'JPY'), Money.new(475, 'JPY')]),
89
+ ).to eq([Money.new(2600, 'JPY'), Money.new(475, 'JPY')])
90
+ end
91
+
92
+ specify "#allocate_max_amounts legal computation with no currency objects" do
93
+ expect(
94
+ new_allocator(3075, 'JPY').allocate_max_amounts([2600, 475]),
95
+ ).to eq([Money.new(2600, 'JPY'), Money.new(475, 'JPY')])
96
+
97
+ expect(
98
+ new_allocator(3075, Money::NULL_CURRENCY).allocate_max_amounts([Money.new(2600, 'JPY'), Money.new(475, 'JPY')]),
99
+ ).to eq([Money.new(2600, 'JPY'), Money.new(475, 'JPY')])
100
+ end
101
+
102
+ specify "#allocate_max_amounts illegal computation across currencies" do
103
+ expect {
104
+ new_allocator(3075, 'USD').allocate_max_amounts([Money.new(2600, 'JPY'), Money.new(475, 'JPY')])
105
+ }.to raise_error(ArgumentError)
106
+ end
107
+
108
+ specify "#allocate_max_amounts drops the remainder when returning the weighted allocation without exceeding the maxima when there is no room for the remainder" do
109
+ expect(
110
+ new_allocator(30.75).allocate_max_amounts([Money.new(26), Money.new(4.74)]),
111
+ ).to eq([Money.new(26), Money.new(4.74)])
112
+ end
113
+
114
+ specify "#allocate_max_amounts returns the weighted allocation when there is no remainder" do
115
+ expect(
116
+ new_allocator(30).allocate_max_amounts([Money.new(15), Money.new(15)]),
117
+ ).to eq([Money.new(15), Money.new(15)])
118
+ end
119
+
120
+ specify "#allocate_max_amounts allocates the remainder round-robin when the maxima are not reached" do
121
+ expect(
122
+ new_allocator(1).allocate_max_amounts([Money.new(33), Money.new(33), Money.new(33)]),
123
+ ).to eq([Money.new(0.34), Money.new(0.33), Money.new(0.33)])
124
+ end
125
+
126
+ specify "#allocate_max_amounts allocates up to the maxima specified" do
127
+ expect(
128
+ new_allocator(100).allocate_max_amounts([Money.new(5), Money.new(2)]),
129
+ ).to eq([Money.new(5), Money.new(2)])
130
+ end
131
+
132
+ specify "#allocate_max_amounts supports all-zero maxima" do
133
+ expect(
134
+ new_allocator(3).allocate_max_amounts([Money.empty, Money.empty, Money.empty]),
135
+ ).to eq([Money.empty, Money.empty, Money.empty])
136
+ end
137
+
138
+ specify "#allocate_max_amounts allocates the right amount without rounding error" do
139
+ expect(
140
+ new_allocator(24.2).allocate_max_amounts([Money.new(46), Money.new(46), Money.new(50), Money.new(50),Money.new(50)]),
141
+ ).to eq([Money.new(4.6), Money.new(4.6), Money.new(5), Money.new(5), Money.new(5)])
142
+ end
143
+ end
144
+
145
+ def new_allocator(amount, currency = nil)
146
+ Money::Allocator.new(Money.new(amount, currency))
147
+ end
148
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  RSpec.shared_examples_for "an object supporting to_money" do
@@ -56,6 +57,6 @@ RSpec.describe BigDecimal do
56
57
  it_should_behave_like "an object supporting to_money"
57
58
 
58
59
  it "parses a zero BigDecimal to Money.zero" do
59
- expect(BigDecimal.new("-0.000").to_money).to eq(Money.zero)
60
+ expect(BigDecimal("-0.000").to_money).to eq(Money.zero)
60
61
  end
61
62
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  RSpec.describe Money::Currency::Loader do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  RSpec.describe "Currency" do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  RSpec.describe Money::Helpers do
@@ -49,12 +50,6 @@ RSpec.describe Money::Helpers do
49
50
  expect(subject.value_to_decimal('invalid')).to eq(0)
50
51
  end
51
52
 
52
- it 'returns the bigdecimal representation of numbers while they are deprecated' do
53
- expect(Money).to receive(:deprecate).exactly(2).times
54
- expect(subject.value_to_decimal('1.23abc')).to eq(amount)
55
- expect(subject.value_to_decimal("1.23\n23")).to eq(amount)
56
- end
57
-
58
53
  it 'raises on invalid object' do
59
54
  expect { subject.value_to_decimal(OpenStruct.new(amount: 1)) }.to raise_error(ArgumentError)
60
55
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  class NormalObject
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  class MoneyRecord < ActiveRecord::Base
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  RSpec.describe MoneyParser do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
  require 'yaml'
3
4
 
@@ -583,113 +584,29 @@ RSpec.describe "Money" do
583
584
  end
584
585
 
585
586
  describe "allocation"do
586
- specify "#allocate takes no action when one gets all" do
587
- expect(Money.new(5).allocate([1])).to eq([Money.new(5)])
587
+ specify "#allocate is calculated by Money::Allocator#allocate" do
588
+ expected = [Money.new(1), [Money.new(1)]]
589
+ expect_any_instance_of(Money::Allocator).to receive(:allocate).with([0.5, 0.5], :roundrobin).and_return(expected)
590
+ expect(Money.new(2).allocate([0.5, 0.5])).to eq(expected)
588
591
  end
589
592
 
590
- specify "#allocate does not lose pennies" do
593
+ specify "#allocate does not lose pennies (integration test)" do
591
594
  moneys = Money.new(0.05).allocate([0.3,0.7])
592
595
  expect(moneys[0]).to eq(Money.new(0.02))
593
596
  expect(moneys[1]).to eq(Money.new(0.03))
594
597
  end
595
598
 
596
- specify "#allocate does not lose dollars with non-decimal currency" do
597
- moneys = Money.new(5, 'JPY').allocate([0.3,0.7])
598
- expect(moneys[0]).to eq(Money.new(2, 'JPY'))
599
- expect(moneys[1]).to eq(Money.new(3, 'JPY'))
599
+ specify "#allocate_max_amounts is calculated by Money::Allocator#allocate_max_amounts" do
600
+ expected = [Money.new(1), [Money.new(1)]]
601
+ expect_any_instance_of(Money::Allocator).to receive(:allocate_max_amounts).and_return(expected)
602
+ expect(Money.new(2).allocate_max_amounts([0.5, 0.5])).to eq(expected)
600
603
  end
601
604
 
602
- specify "#allocate does not lose dollars with three decimal currency" do
603
- moneys = Money.new(0.005, 'JOD').allocate([0.3,0.7])
604
- expect(moneys[0]).to eq(Money.new(0.002, 'JOD'))
605
- expect(moneys[1]).to eq(Money.new(0.003, 'JOD'))
606
- end
607
-
608
- specify "#allocate does not lose pennies even when given a lossy split" do
609
- moneys = Money.new(1).allocate([0.333,0.333, 0.333])
610
- expect(moneys[0].subunits).to eq(34)
611
- expect(moneys[1].subunits).to eq(33)
612
- expect(moneys[2].subunits).to eq(33)
613
- end
614
-
615
- specify "#allocate requires total to be less than 1" do
616
- expect { Money.new(0.05).allocate([0.5,0.6]) }.to raise_error(ArgumentError)
617
- end
618
-
619
- specify "#allocate will use rationals if provided" do
620
- splits = [128400,20439,14589,14589,25936].map{ |num| Rational(num, 203953) } # sums to > 1 if converted to float
621
- expect(Money.new(2.25).allocate(splits)).to eq([Money.new(1.42), Money.new(0.23), Money.new(0.16), Money.new(0.16), Money.new(0.28)])
622
- end
623
-
624
- specify "#allocate will convert rationals with high precision" do
625
- ratios = [Rational(1, 1), Rational(0)]
626
- expect(Money.new("858993456.12").allocate(ratios)).to eq([Money.new("858993456.12"), Money.empty])
627
- ratios = [Rational(1, 6), Rational(5, 6)]
628
- expect(Money.new("3.00").allocate(ratios)).to eq([Money.new("0.50"), Money.new("2.50")])
629
- end
630
-
631
- specify "#allocate doesn't raise with weird negative rational ratios" do
632
- rate = Rational(-5, 1201)
633
- expect { Money.new(1).allocate([rate, 1 - rate]) }.not_to raise_error
634
- end
635
-
636
- specify "#allocate_max_amounts returns the weighted allocation without exceeding the maxima when there is room for the remainder" do
605
+ specify "#allocate_max_amounts returns the weighted allocation without exceeding the maxima when there is room for the remainder (integration test)" do
637
606
  expect(
638
607
  Money.new(30.75).allocate_max_amounts([Money.new(26), Money.new(4.75)]),
639
608
  ).to eq([Money.new(26), Money.new(4.75)])
640
609
  end
641
-
642
- specify "#allocate_max_amounts returns the weighted allocation without exceeding the maxima when there is room for the remainder with currency" do
643
- expect(
644
- Money.new(3075, 'JPY').allocate_max_amounts([Money.new(2600, 'JPY'), Money.new(475, 'JPY')]),
645
- ).to eq([Money.new(2600, 'JPY'), Money.new(475, 'JPY')])
646
- end
647
-
648
- specify "#allocate_max_amounts legal computation with no currency objects" do
649
- expect(
650
- Money.new(3075, 'JPY').allocate_max_amounts([2600, 475]),
651
- ).to eq([Money.new(2600, 'JPY'), Money.new(475, 'JPY')])
652
-
653
- expect(
654
- Money.new(3075, Money::NULL_CURRENCY).allocate_max_amounts([Money.new(2600, 'JPY'), Money.new(475, 'JPY')]),
655
- ).to eq([Money.new(2600, 'JPY'), Money.new(475, 'JPY')])
656
- end
657
-
658
- specify "#allocate_max_amounts illegal computation across currencies" do
659
- expect {
660
- Money.new(3075, 'USD').allocate_max_amounts([Money.new(2600, 'JPY'), Money.new(475, 'JPY')])
661
- }.to raise_error(ArgumentError)
662
- end
663
-
664
- specify "#allocate_max_amounts drops the remainder when returning the weighted allocation without exceeding the maxima when there is no room for the remainder" do
665
- expect(
666
- Money.new(30.75).allocate_max_amounts([Money.new(26), Money.new(4.74)]),
667
- ).to eq([Money.new(26), Money.new(4.74)])
668
- end
669
-
670
- specify "#allocate_max_amounts returns the weighted allocation when there is no remainder" do
671
- expect(
672
- Money.new(30).allocate_max_amounts([Money.new(15), Money.new(15)]),
673
- ).to eq([Money.new(15), Money.new(15)])
674
- end
675
-
676
- specify "#allocate_max_amounts allocates the remainder round-robin when the maxima are not reached" do
677
- expect(
678
- Money.new(1).allocate_max_amounts([Money.new(33), Money.new(33), Money.new(33)]),
679
- ).to eq([Money.new(0.34), Money.new(0.33), Money.new(0.33)])
680
- end
681
-
682
- specify "#allocate_max_amounts allocates up to the maxima specified" do
683
- expect(
684
- Money.new(100).allocate_max_amounts([Money.new(5), Money.new(2)]),
685
- ).to eq([Money.new(5), Money.new(2)])
686
- end
687
-
688
- specify "#allocate_max_amounts supports all-zero maxima" do
689
- expect(
690
- Money.new(3).allocate_max_amounts([Money.empty, Money.empty, Money.empty]),
691
- ).to eq([Money.empty, Money.empty, Money.empty])
692
- end
693
610
  end
694
611
 
695
612
  describe "split" do
@@ -828,8 +745,8 @@ RSpec.describe "Money" do
828
745
  end
829
746
 
830
747
  it "accepts Rational number" do
831
- expect(Money.from_amount(Rational("999999999999999999.999")).value).to eql(BigDecimal.new("1000000000000000000", Money::Helpers::MAX_DECIMAL))
832
- expect(Money.from_amount(Rational("999999999999999999.99")).value).to eql(BigDecimal.new("999999999999999999.99", Money::Helpers::MAX_DECIMAL))
748
+ expect(Money.from_amount(Rational("999999999999999999.999")).value).to eql(BigDecimal("1000000000000000000", Money::Helpers::MAX_DECIMAL))
749
+ expect(Money.from_amount(Rational("999999999999999999.99")).value).to eql(BigDecimal("999999999999999999.99", Money::Helpers::MAX_DECIMAL))
833
750
  end
834
751
 
835
752
  it "raises ArgumentError with unsupported argument" do