shopify-money 0.14.8 → 0.15.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 186250af5f49f67f218ce8b30f47cd6c20ff762f9fdb2813ca9ffe1d12a7700d
4
- data.tar.gz: 1e6ce179c120a2781dc0be48ee0377c4179e6dc07c8fd6306689947a0847daf4
3
+ metadata.gz: 56953634d128da5cb62dfb11b5c60868a162c4ff7edb9bb810110d17c02469f9
4
+ data.tar.gz: c8e6f0e99b480cfcf9be4183adfc633baf14f0f9ee0d777bea01b225c01cfc09
5
5
  SHA512:
6
- metadata.gz: 3d2076a57d0b364a782ce10ffe8961e8ca57b535b8c12ba006887a92336902694ecf1a9b34538632bdad51ea3bbbf2e44aa15988344a406d16890168c72823a8
7
- data.tar.gz: 8b539f90a996544a93fbb733dbde048460a4a5069e1efef6e44b63ae8e790dd6f90a407b7e4ae0fbbb2d850864b5015204ec8a4663b2d45673589611e16ce02b
6
+ metadata.gz: 4888a59e2f50348092b73c2b7255b215f994f9b47efbd379ad88d6f4624f4eca403840f584f4d5760a17c02d20f38f0fc49f286c0e19e3557e4976037d1f8049
7
+ data.tar.gz: ce77e720fae3724a0cc8303336ac12aee09a7a61862f0ba01f0dc7dce3c4e86f2fd7073ee7828d5cc313b77d9b285dfce07bd84e1d8e289e597e1cf25a349c7d
@@ -50,6 +50,10 @@ class Money
50
50
  self.class == other.class && iso_code == other.iso_code
51
51
  end
52
52
 
53
+ def hash
54
+ [ self.class, iso_code ].hash
55
+ end
56
+
53
57
  def compatible?(other)
54
58
  other.is_a?(NullCurrency) || eql?(other)
55
59
  end
@@ -26,19 +26,10 @@ class Money
26
26
  end
27
27
  alias_method :from_amount, :new
28
28
 
29
- def zero(currency = NULL_CURRENCY)
30
- new(0, currency)
31
- end
32
- alias_method :empty, :zero
33
-
34
29
  def parse(*args, **kwargs)
35
30
  parser.parse(*args, **kwargs)
36
31
  end
37
32
 
38
- def from_cents(cents, currency = nil)
39
- new(cents.round.to_f / 100, currency)
40
- end
41
-
42
33
  def from_subunits(subunits, currency_iso, format: :iso4217)
43
34
  currency = Helpers.value_to_currency(currency_iso)
44
35
 
@@ -106,11 +97,6 @@ class Money
106
97
  coder['currency'] = @currency.iso_code
107
98
  end
108
99
 
109
- def cents
110
- # Money.deprecate('`money.cents` is deprecated and will be removed in the next major release. Please use `money.subunits` instead. Keep in mind, subunits are currency aware.')
111
- (value * 100).to_i
112
- end
113
-
114
100
  def subunits(format: :iso4217)
115
101
  subunit_to_unit_value = if format == :iso4217
116
102
  @currency.subunit_to_unit
@@ -243,10 +229,6 @@ class Money
243
229
  end
244
230
  end
245
231
 
246
- def to_liquid
247
- cents
248
- end
249
-
250
232
  def to_json(options = {})
251
233
  to_s
252
234
  end
@@ -1,5 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
  class Money
3
+ # A placeholder currency for instances where no actual currency is available,
4
+ # as defined by ISO4217. You should rarely, if ever, need to use this
5
+ # directly. It's here mostly for backwards compatibility and for that reason
6
+ # behaves like a dollar, which is how this gem worked before the introduction
7
+ # of currency.
8
+ #
9
+ # Here follows a list of preferred alternatives over using Money with
10
+ # NullCurrency:
11
+ #
12
+ # For comparisons where you don't know the currency beforehand, you can use
13
+ # Numeric predicate methods like #positive?/#negative?/#zero?/#nonzero?.
14
+ # Comparison operators with Numeric (==, !=, <=, =>, <, >) work as well.
15
+ #
16
+ # @example
17
+ # Money.new(1, 'CAD').positive? #=> true
18
+ # Money.new(2, 'CAD') >= 0 #=> true
19
+ #
20
+ # Money with NullCurrency has behaviour that may surprise you, such as
21
+ # database validations or GraphQL enum not allowing the string representation
22
+ # of NullCurrency. Prefer using Money.new(0, currency) where possible, as
23
+ # this sidesteps these issues and provides additional currency check
24
+ # safeties.
25
+ #
26
+ # Unlike other currencies, it is allowed to calculate a Money object with
27
+ # NullCurrency with another currency. The resulting Money object will have
28
+ # the other currency.
29
+ #
30
+ # @example
31
+ # Money.new(0, Money::NULL_CURRENCY) + Money.new(5, 'CAD')
32
+ # #=> #<Money value:5.00 currency:CAD>
33
+ #
3
34
  class NullCurrency
4
35
 
5
36
  attr_reader :iso_code, :iso_numeric, :name, :smallest_denomination, :subunit_symbol,
@@ -9,7 +40,7 @@ class Money
9
40
  @symbol = '$'
10
41
  @disambiguate_symbol = nil
11
42
  @subunit_symbol = nil
12
- @iso_code = 'XXX' # Valid ISO4217
43
+ @iso_code = 'XXX'
13
44
  @iso_numeric = '999'
14
45
  @name = 'No Currency'
15
46
  @smallest_denomination = 1
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  class Money
3
- VERSION = "0.14.8"
3
+ VERSION = "0.15.0"
4
4
  end
@@ -1,3 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rubocop/cop/money/missing_currency'
4
+ require 'rubocop/cop/money/zero_money'
@@ -20,11 +20,11 @@ module RuboCop
20
20
  #
21
21
 
22
22
  def_node_matcher :money_new, <<~PATTERN
23
- (send (const nil? :Money) {:new :from_amount :from_cents} $...)
23
+ (send (const {nil? cbase} :Money) {:new :from_amount :from_cents} $...)
24
24
  PATTERN
25
25
 
26
26
  def_node_matcher :to_money_without_currency?, <<~PATTERN
27
- (send _ :to_money)
27
+ ({send csend} _ :to_money)
28
28
  PATTERN
29
29
 
30
30
  def_node_matcher :to_money_block?, <<~PATTERN
@@ -42,11 +42,9 @@ module RuboCop
42
42
  add_offense(node, message: 'to_money is missing currency argument')
43
43
  end
44
44
  end
45
+ alias on_csend on_send
45
46
 
46
47
  def autocorrect(node)
47
- currency = cop_config['ReplacementCurrency']
48
- return unless currency
49
-
50
48
  receiver, method, _ = *node
51
49
 
52
50
  lambda do |corrector|
@@ -55,20 +53,30 @@ module RuboCop
55
53
 
56
54
  corrector.replace(
57
55
  node.loc.expression,
58
- "#{receiver.source}.#{method}(#{amount&.source || 0}, '#{currency}')"
56
+ "#{receiver.source}.#{method}(#{amount&.source || 0}, #{replacement_currency})"
59
57
  )
60
58
  end
61
59
 
62
60
  if to_money_without_currency?(node)
63
- corrector.insert_after(node.loc.expression, "('#{currency}')")
61
+ corrector.insert_after(node.loc.expression, "(#{replacement_currency})")
64
62
  elsif to_money_block?(node)
65
63
  corrector.replace(
66
64
  node.loc.expression,
67
- "#{receiver.source}.#{method} { |x| x.to_money('#{currency}') }"
65
+ "#{receiver.source}.#{method} { |x| x.to_money(#{replacement_currency}) }"
68
66
  )
69
67
  end
70
68
  end
71
69
  end
70
+
71
+ private
72
+
73
+ def replacement_currency
74
+ if cop_config['ReplacementCurrency']
75
+ "'#{cop_config['ReplacementCurrency']}'"
76
+ else
77
+ 'Money::NULL_CURRENCY'
78
+ end
79
+ end
72
80
  end
73
81
  end
74
82
  end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Money
6
+ class ZeroMoney < Cop
7
+ # `Money.zero` and it's alias `empty`, with or without currency
8
+ # argument is removed in favour of the more explicit Money.new
9
+ # syntax. Supplying it with a real currency is preferred for
10
+ # additional currency safety checks.
11
+ #
12
+ # If no currency was supplied, it defaults to
13
+ # Money::NULL_CURRENCY which was the default setting of
14
+ # Money.default_currency and should effectively be the same. The cop
15
+ # can be configured with a ReplacementCurrency in case that is more
16
+ # appropriate for your application.
17
+ #
18
+ # @example
19
+ #
20
+ # # bad
21
+ # Money.zero
22
+ #
23
+ # # good when configured with `ReplacementCurrency: CAD`
24
+ # Money.new(0, 'CAD')
25
+ #
26
+
27
+ MSG = 'Money.zero is removed, use `Money.new(0, %<currency>s)`.'
28
+
29
+ def_node_matcher :money_zero, <<~PATTERN
30
+ (send (const {nil? cbase} :Money) {:zero :empty} $...)
31
+ PATTERN
32
+
33
+ def on_send(node)
34
+ money_zero(node) do |currency_arg|
35
+ add_offense(node, message: format(MSG, currency: replacement_currency(currency_arg)))
36
+ end
37
+ end
38
+
39
+ def autocorrect(node)
40
+ receiver, _ = *node
41
+
42
+ lambda do |corrector|
43
+ money_zero(node) do |currency_arg|
44
+ replacement_currency = replacement_currency(currency_arg)
45
+
46
+ corrector.replace(
47
+ node.loc.expression,
48
+ "#{receiver.source}.new(0, #{replacement_currency})"
49
+ )
50
+ end
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def replacement_currency(currency_arg)
57
+ return currency_arg.first.source unless currency_arg.empty?
58
+ return "'#{cop_config['ReplacementCurrency']}'" if cop_config['ReplacementCurrency']
59
+
60
+ 'Money::NULL_CURRENCY'
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -43,7 +43,7 @@ RSpec.describe "Allocator" do
43
43
 
44
44
  specify "#allocate will convert rationals with high precision" do
45
45
  ratios = [Rational(1, 1), Rational(0)]
46
- expect(new_allocator("858993456.12").allocate(ratios)).to eq([Money.new("858993456.12"), Money.empty])
46
+ expect(new_allocator("858993456.12").allocate(ratios)).to eq([Money.new("858993456.12"), Money.new(0, Money::NULL_CURRENCY)])
47
47
  ratios = [Rational(1, 6), Rational(5, 6)]
48
48
  expect(new_allocator("3.00").allocate(ratios)).to eq([Money.new("0.50"), Money.new("2.50")])
49
49
  end
@@ -131,8 +131,8 @@ RSpec.describe "Allocator" do
131
131
 
132
132
  specify "#allocate_max_amounts supports all-zero maxima" do
133
133
  expect(
134
- new_allocator(3).allocate_max_amounts([Money.empty, Money.empty, Money.empty]),
135
- ).to eq([Money.empty, Money.empty, Money.empty])
134
+ new_allocator(3).allocate_max_amounts([Money.new(0, Money::NULL_CURRENCY), Money.new(0, Money::NULL_CURRENCY), Money.new(0, Money::NULL_CURRENCY)]),
135
+ ).to eq([Money.new(0, Money::NULL_CURRENCY), Money.new(0, Money::NULL_CURRENCY), Money.new(0, Money::NULL_CURRENCY)])
136
136
  end
137
137
 
138
138
  specify "#allocate_max_amounts allocates the right amount without rounding error" do
@@ -17,7 +17,7 @@ RSpec.describe Integer do
17
17
  it_should_behave_like "an object supporting to_money"
18
18
 
19
19
  it "parses 0 to Money.zero" do
20
- expect(0.to_money).to eq(Money.zero)
20
+ expect(0.to_money).to eq(Money.new(0, Money::NULL_CURRENCY))
21
21
  end
22
22
  end
23
23
 
@@ -30,7 +30,7 @@ RSpec.describe Float do
30
30
  it_should_behave_like "an object supporting to_money"
31
31
 
32
32
  it "parses 0.0 to Money.zero" do
33
- expect(0.0.to_money).to eq(Money.zero)
33
+ expect(0.0.to_money).to eq(Money.new(0, Money::NULL_CURRENCY))
34
34
  end
35
35
  end
36
36
 
@@ -43,8 +43,8 @@ RSpec.describe String do
43
43
  it_should_behave_like "an object supporting to_money"
44
44
 
45
45
  it "parses an empty string to Money.zero" do
46
- expect(''.to_money).to eq(Money.zero)
47
- expect(' '.to_money).to eq(Money.zero)
46
+ expect(''.to_money).to eq(Money.new(0, Money::NULL_CURRENCY))
47
+ expect(' '.to_money).to eq(Money.new(0, Money::NULL_CURRENCY))
48
48
  end
49
49
  end
50
50
 
@@ -57,6 +57,6 @@ RSpec.describe BigDecimal do
57
57
  it_should_behave_like "an object supporting to_money"
58
58
 
59
59
  it "parses a zero BigDecimal to Money.zero" do
60
- expect(BigDecimal("-0.000").to_money).to eq(Money.zero)
60
+ expect(BigDecimal("-0.000").to_money).to eq(Money.new(0, Money::NULL_CURRENCY))
61
61
  end
62
62
  end
@@ -77,6 +77,16 @@ RSpec.describe "Currency" do
77
77
  end
78
78
  end
79
79
 
80
+ describe "#hash" do
81
+ specify "equal currencies from different loaders have the same hash" do
82
+ currency_1 = Money::Currency.find('USD')
83
+ currency_2 = YAML.load(Money::Currency.find('USD').to_yaml)
84
+
85
+ expect(currency_1.eql?(currency_2)).to eq(true)
86
+ expect(currency_1.hash).to eq(currency_2.hash)
87
+ end
88
+ end
89
+
80
90
  describe "==" do
81
91
  it "returns true when both objects have the same currency" do
82
92
  expect(currency == Money.new(1, 'USD').currency).to eq(true)
@@ -136,7 +136,7 @@ RSpec.describe 'MoneyColumn' do
136
136
 
137
137
  it 'does not overwrite a currency column with a default currency when saving zero' do
138
138
  expect(record.currency.to_s).to eq('EUR')
139
- record.update(price: Money.zero)
139
+ record.update(price: Money.new(0, Money::NULL_CURRENCY))
140
140
  expect(record.currency.to_s).to eq('EUR')
141
141
  end
142
142
 
@@ -8,12 +8,12 @@ RSpec.describe MoneyParser do
8
8
 
9
9
  describe "parsing of amounts with period decimal separator" do
10
10
  it "parses an empty string to $0" do
11
- expect(@parser.parse("")).to eq(Money.zero)
11
+ expect(@parser.parse("")).to eq(Money.new(0, Money::NULL_CURRENCY))
12
12
  end
13
13
 
14
14
  it "parses an invalid string when not strict" do
15
15
  expect(Money).to receive(:deprecate).twice
16
- expect(@parser.parse("no money")).to eq(Money.zero)
16
+ expect(@parser.parse("no money")).to eq(Money.new(0, Money::NULL_CURRENCY))
17
17
  expect(@parser.parse("1..")).to eq(Money.new(1))
18
18
  end
19
19
 
@@ -9,10 +9,6 @@ RSpec.describe "Money" do
9
9
  let (:non_fractional_money) { Money.new(1, 'JPY') }
10
10
  let (:zero_money) { Money.new(0) }
11
11
 
12
- it "is contructable with empty class method" do
13
- expect(Money.empty).to eq(Money.new)
14
- end
15
-
16
12
  context "default currency not set" do
17
13
  before(:each) do
18
14
  @default_currency = Money.default_currency
@@ -28,15 +24,11 @@ RSpec.describe "Money" do
28
24
  end
29
25
 
30
26
  it ".zero has no currency" do
31
- expect(Money.zero.currency).to be_a(Money::NullCurrency)
27
+ expect(Money.new(0, Money::NULL_CURRENCY).currency).to be_a(Money::NullCurrency)
32
28
  end
33
29
 
34
30
  it ".zero is a 0$ value" do
35
- expect(Money.zero).to eq(Money.new(0))
36
- end
37
-
38
- it ".zero accepts an optional currency" do
39
- expect(Money.zero('USD')).to eq(Money.new(0, 'USD'))
31
+ expect(Money.new(0, Money::NULL_CURRENCY)).to eq(Money.new(0))
40
32
  end
41
33
 
42
34
  it "returns itself with to_money" do
@@ -247,11 +239,6 @@ RSpec.describe "Money" do
247
239
  expect((1.50 * Money.new(1.00))).to eq(Money.new(1.50))
248
240
  end
249
241
 
250
- it "is multipliable by a cents amount" do
251
- expect((Money.new(1.00) * 0.50)).to eq(Money.new(0.50))
252
- expect((0.50 * Money.new(1.00))).to eq(Money.new(0.50))
253
- end
254
-
255
242
  it "is multipliable by a rational" do
256
243
  expect((Money.new(3.3) * Rational(1, 12))).to eq(Money.new(0.28))
257
244
  expect((Rational(1, 12) * Money.new(3.3))).to eq(Money.new(0.28))
@@ -306,10 +293,6 @@ RSpec.describe "Money" do
306
293
  expect { Money.new(55.00) / 55 }.to raise_error(RuntimeError)
307
294
  end
308
295
 
309
- it "returns cents in to_liquid" do
310
- expect(Money.new(1.00).to_liquid).to eq(100)
311
- end
312
-
313
296
  it "returns cents in to_json" do
314
297
  expect(Money.new(1.00).to_json).to eq("1.00")
315
298
  end
@@ -330,19 +313,7 @@ RSpec.describe "Money" do
330
313
  expect(Money.new(1.50).to_f.to_s).to eq("1.5")
331
314
  end
332
315
 
333
- it "is creatable from an integer value in cents" do
334
- expect(Money.from_cents(1950)).to eq(Money.new(19.50))
335
- end
336
-
337
- it "is creatable from an integer value of 0 in cents" do
338
- expect(Money.from_cents(0)).to eq(Money.new)
339
- end
340
-
341
- it "is creatable from a float cents amount" do
342
- expect(Money.from_cents(1950.5)).to eq(Money.new(19.51))
343
- end
344
-
345
- describe '#from_subunits' do
316
+ describe '#from_subunits' do
346
317
  it "creates Money object from an integer value in cents and currency" do
347
318
  expect(Money.from_subunits(1950, 'CAD')).to eq(Money.new(19.50))
348
319
  end
@@ -619,10 +590,6 @@ RSpec.describe "Money" do
619
590
  expect(money.value).to eq(BigDecimal("1.00"))
620
591
  end
621
592
 
622
- it "returns cents as 100 cents" do
623
- expect(money.cents).to eq(100)
624
- end
625
-
626
593
  it "returns cents as 100 cents" do
627
594
  expect(money.subunits).to eq(100)
628
595
  end
@@ -783,20 +750,6 @@ RSpec.describe "Money" do
783
750
  end
784
751
 
785
752
  describe "from_amount quacks like RubyMoney" do
786
- it "accepts numeric values" do
787
- expect(Money.from_amount(1)).to eq Money.from_cents(1_00)
788
- expect(Money.from_amount(1.0)).to eq Money.from_cents(1_00)
789
- expect(Money.from_amount(BigDecimal("1"))).to eq Money.from_cents(1_00)
790
- end
791
-
792
- it "accepts string values" do
793
- expect(Money.from_amount("1")).to eq Money.from_cents(1_00)
794
- end
795
-
796
- it "accepts nil values" do
797
- expect(Money.from_amount(nil)).to eq Money.from_cents(0)
798
- end
799
-
800
753
  it "accepts an optional currency parameter" do
801
754
  expect { Money.from_amount(1, "CAD") }.to_not raise_error
802
755
  end
@@ -816,10 +769,14 @@ RSpec.describe "Money" do
816
769
  money = YAML.dump(Money.new(750, 'usd'))
817
770
  expect(money).to eq("--- !ruby/object:Money\nvalue: '750.0'\ncurrency: USD\n")
818
771
  end
772
+
773
+ it "does not change BigDecimal value to Integer while rounding for currencies without subunits" do
774
+ money = Money.new(100, 'JPY').to_yaml
775
+ expect(money).to eq("--- !ruby/object:Money\nvalue: '100.0'\ncurrency: JPY\n")
776
+ end
819
777
  end
820
778
 
821
779
  describe "YAML deserialization" do
822
-
823
780
  it "accepts values with currencies" do
824
781
  money = YAML.load("--- !ruby/object:Money\nvalue: '750.0'\ncurrency: USD\n")
825
782
  expect(money).to eq(Money.new(750, 'usd'))
@@ -963,10 +920,4 @@ RSpec.describe "Money" do
963
920
  expect(money.currency.iso_code).to eq('EUR')
964
921
  end
965
922
  end
966
-
967
- describe '#to_yaml' do
968
- it 'returns a yaml representation' do
969
- expect(Money.new(100, 'JPY').to_yaml).to eq("--- !ruby/object:Money\nvalue: '100.0'\ncurrency: JPY\n")
970
- end
971
- end
972
923
  end
@@ -8,12 +8,16 @@ RSpec.describe RuboCop::Cop::Money::MissingCurrency do
8
8
 
9
9
  let(:config) { RuboCop::Config.new }
10
10
 
11
- describe '#on_send' do
12
- it 'registers an offense for Money.new without a currency argument' do
11
+ context 'with default configuration' do
12
+ it 'registers an offense and corrects for Money.new without a currency argument' do
13
13
  expect_offense(<<~RUBY)
14
14
  Money.new(1)
15
15
  ^^^^^^^^^^^^ Money is missing currency argument
16
16
  RUBY
17
+
18
+ expect_correction(<<~RUBY)
19
+ Money.new(1, Money::NULL_CURRENCY)
20
+ RUBY
17
21
  end
18
22
 
19
23
  it 'does not register an offense for Money.new with currency argument' do
@@ -22,18 +26,26 @@ RSpec.describe RuboCop::Cop::Money::MissingCurrency do
22
26
  RUBY
23
27
  end
24
28
 
25
- it 'registers an offense for Money.new without a currency argument' do
29
+ it 'registers an offense and corrects for Money.new without a currency argument' do
26
30
  expect_offense(<<~RUBY)
27
31
  Money.new
28
32
  ^^^^^^^^^ Money is missing currency argument
29
33
  RUBY
34
+
35
+ expect_correction(<<~RUBY)
36
+ Money.new(0, Money::NULL_CURRENCY)
37
+ RUBY
30
38
  end
31
39
 
32
- it 'registers an offense for Money.from_amount without a currency argument' do
40
+ it 'registers an offense and corrects for Money.from_amount without a currency argument' do
33
41
  expect_offense(<<~RUBY)
34
42
  Money.from_amount(1)
35
43
  ^^^^^^^^^^^^^^^^^^^^ Money is missing currency argument
36
44
  RUBY
45
+
46
+ expect_correction(<<~RUBY)
47
+ Money.from_amount(1, Money::NULL_CURRENCY)
48
+ RUBY
37
49
  end
38
50
 
39
51
  it 'does not register an offense for Money.from_amount with currency argument' do
@@ -42,11 +54,15 @@ RSpec.describe RuboCop::Cop::Money::MissingCurrency do
42
54
  RUBY
43
55
  end
44
56
 
45
- it 'registers an offense for Money.from_cents without a currency argument' do
57
+ it 'registers an offense and corrects for Money.from_cents without a currency argument' do
46
58
  expect_offense(<<~RUBY)
47
59
  Money.from_cents(1)
48
60
  ^^^^^^^^^^^^^^^^^^^ Money is missing currency argument
49
61
  RUBY
62
+
63
+ expect_correction(<<~RUBY)
64
+ Money.from_cents(1, Money::NULL_CURRENCY)
65
+ RUBY
50
66
  end
51
67
 
52
68
  it 'does not register an offense for Money.from_cents with currency argument' do
@@ -55,11 +71,26 @@ RSpec.describe RuboCop::Cop::Money::MissingCurrency do
55
71
  RUBY
56
72
  end
57
73
 
58
- it 'registers an offense for to_money without a currency argument' do
74
+ it 'registers an offense and corrects for to_money without a currency argument' do
59
75
  expect_offense(<<~RUBY)
60
76
  '1'.to_money
61
77
  ^^^^^^^^^^^^ to_money is missing currency argument
62
78
  RUBY
79
+
80
+ expect_correction(<<~RUBY)
81
+ '1'.to_money(Money::NULL_CURRENCY)
82
+ RUBY
83
+ end
84
+
85
+ it 'registers an offense and corrects for safe navigation to_money without a currency argument' do
86
+ expect_offense(<<~RUBY)
87
+ item&.to_money
88
+ ^^^^^^^^^^^^^^ to_money is missing currency argument
89
+ RUBY
90
+
91
+ expect_correction(<<~RUBY)
92
+ item&.to_money(Money::NULL_CURRENCY)
93
+ RUBY
63
94
  end
64
95
 
65
96
  it 'does not register an offense for to_money with currency argument' do
@@ -68,15 +99,19 @@ RSpec.describe RuboCop::Cop::Money::MissingCurrency do
68
99
  RUBY
69
100
  end
70
101
 
71
- it 'registers an offense for to_money block pass form' do
102
+ it 'registers an offense and corrects for to_money block pass form' do
72
103
  expect_offense(<<~RUBY)
73
104
  ['1'].map(&:to_money)
74
105
  ^^^^^^^^^^^^^^^^^^^^^ to_money is missing currency argument
75
106
  RUBY
107
+
108
+ expect_correction(<<~RUBY)
109
+ ['1'].map { |x| x.to_money(Money::NULL_CURRENCY) }
110
+ RUBY
76
111
  end
77
112
  end
78
113
 
79
- describe '#autocorrect' do
114
+ context 'with ReplacementCurrency configuration' do
80
115
  let(:config) do
81
116
  RuboCop::Config.new(
82
117
  'Money/MissingCurrency' => {
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../rubocop_helper'
4
+ require 'rubocop/cop/money/zero_money'
5
+
6
+ RSpec.describe RuboCop::Cop::Money::ZeroMoney do
7
+ subject(:cop) { described_class.new(config) }
8
+
9
+ let(:config) { RuboCop::Config.new }
10
+
11
+ context 'with default configuration' do
12
+ it 'registers an offense and corrects Money.zero without currency' do
13
+ expect_offense(<<~RUBY)
14
+ Money.zero
15
+ ^^^^^^^^^^ Money.zero is removed, use `Money.new(0, Money::NULL_CURRENCY)`.
16
+ RUBY
17
+
18
+ expect_correction(<<~RUBY)
19
+ Money.new(0, Money::NULL_CURRENCY)
20
+ RUBY
21
+ end
22
+
23
+ it 'registers an offense and corrects Money.zero with currency' do
24
+ expect_offense(<<~RUBY)
25
+ Money.zero('CAD')
26
+ ^^^^^^^^^^^^^^^^^ Money.zero is removed, use `Money.new(0, 'CAD')`.
27
+ RUBY
28
+
29
+ expect_correction(<<~RUBY)
30
+ Money.new(0, 'CAD')
31
+ RUBY
32
+ end
33
+
34
+ it 'does not register an offense when using Money.new with a currency' do
35
+ expect_no_offenses(<<~RUBY)
36
+ Money.new(0, 'CAD')
37
+ RUBY
38
+ end
39
+ end
40
+
41
+ context 'with ReplacementCurrency configuration' do
42
+ let(:config) do
43
+ RuboCop::Config.new(
44
+ 'Money/ZeroMoney' => {
45
+ 'ReplacementCurrency' => 'CAD'
46
+ }
47
+ )
48
+ end
49
+
50
+ it 'registers an offense and corrects Money.zero without currency' do
51
+ expect_offense(<<~RUBY)
52
+ Money.zero
53
+ ^^^^^^^^^^ Money.zero is removed, use `Money.new(0, 'CAD')`.
54
+ RUBY
55
+
56
+ expect_correction(<<~RUBY)
57
+ Money.new(0, 'CAD')
58
+ RUBY
59
+ end
60
+
61
+ it 'registers an offense and corrects Money.zero with currency' do
62
+ expect_offense(<<~RUBY)
63
+ Money.zero('EUR')
64
+ ^^^^^^^^^^^^^^^^^ Money.zero is removed, use `Money.new(0, 'EUR')`.
65
+ RUBY
66
+
67
+ expect_correction(<<~RUBY)
68
+ Money.new(0, 'EUR')
69
+ RUBY
70
+ end
71
+
72
+ it 'does not register an offense when using Money.new with a currency' do
73
+ expect_no_offenses(<<~RUBY)
74
+ Money.new(0, 'EUR')
75
+ RUBY
76
+ end
77
+ end
78
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shopify-money
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.8
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify Inc
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-06 00:00:00.000000000 Z
11
+ date: 2021-01-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -135,6 +135,7 @@ files:
135
135
  - lib/money_column/railtie.rb
136
136
  - lib/rubocop/cop/money.rb
137
137
  - lib/rubocop/cop/money/missing_currency.rb
138
+ - lib/rubocop/cop/money/zero_money.rb
138
139
  - lib/shopify-money.rb
139
140
  - money.gemspec
140
141
  - spec/accounting_money_parser_spec.rb
@@ -149,6 +150,7 @@ files:
149
150
  - spec/money_spec.rb
150
151
  - spec/null_currency_spec.rb
151
152
  - spec/rubocop/cop/money/missing_currency_spec.rb
153
+ - spec/rubocop/cop/money/zero_money_spec.rb
152
154
  - spec/rubocop_helper.rb
153
155
  - spec/schema.rb
154
156
  - spec/spec_helper.rb
@@ -189,6 +191,7 @@ test_files:
189
191
  - spec/money_spec.rb
190
192
  - spec/null_currency_spec.rb
191
193
  - spec/rubocop/cop/money/missing_currency_spec.rb
194
+ - spec/rubocop/cop/money/zero_money_spec.rb
192
195
  - spec/rubocop_helper.rb
193
196
  - spec/schema.rb
194
197
  - spec/spec_helper.rb