shopify-money 0.16.0 → 1.0.2.pre

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.
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Money
4
+ module Rails
5
+ class JobArgumentSerializer < ::ActiveJob::Serializers::ObjectSerializer
6
+ def serialize(money)
7
+ super("value" => money.value, "currency" => money.currency.iso_code)
8
+ end
9
+
10
+ def deserialize(hash)
11
+ Money.new(hash["value"], hash["currency"])
12
+ end
13
+
14
+ private
15
+
16
+ def klass
17
+ Money
18
+ end
19
+ end
20
+ end
21
+ end
22
+
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Money
4
+ class Railtie < Rails::Railtie
5
+ initializer "shopify-money.setup_active_job_serializer" do
6
+ ActiveSupport.on_load :active_job do
7
+ require_relative "rails/job_argument_serializer"
8
+ ActiveJob::Serializers.add_serializers ::Money::Rails::JobArgumentSerializer
9
+ end
10
+ end
11
+
12
+ initializer "shopify-money.setup_locale_aware_parser" do
13
+ ActiveSupport.on_load(:action_view) do
14
+ Money::Parser::LocaleAware.decimal_separator_resolver =
15
+ -> { ::I18n.translate("number.currency.format.separator") }
16
+ end
17
+ end
18
+ end
19
+ end
data/lib/money/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  class Money
3
- VERSION = "0.16.0"
3
+ VERSION = "1.0.2.pre"
4
4
  end
data/lib/money.rb CHANGED
@@ -1,14 +1,19 @@
1
1
  # frozen_string_literal: true
2
- require_relative 'money/money_parser'
2
+ require_relative 'money/version'
3
+ require_relative 'money/parser/fuzzy'
3
4
  require_relative 'money/helpers'
4
5
  require_relative 'money/currency'
5
6
  require_relative 'money/null_currency'
6
7
  require_relative 'money/allocator'
8
+ require_relative 'money/config'
7
9
  require_relative 'money/money'
8
10
  require_relative 'money/errors'
9
11
  require_relative 'money/deprecations'
10
- require_relative 'money/accounting_money_parser'
12
+ require_relative 'money/parser/accounting'
13
+ require_relative 'money/parser/locale_aware'
14
+ require_relative 'money/parser/simple'
11
15
  require_relative 'money/core_extensions'
12
16
  require_relative 'money_column' if defined?(ActiveRecord)
17
+ require_relative 'money/railtie' if defined?(Rails::Railtie)
13
18
 
14
19
  require_relative 'rubocop/cop/money' if defined?(RuboCop)
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  module MoneyColumn
3
+ class CurrencyReadOnlyError < StandardError; end
4
+
3
5
  module ActiveRecordHooks
4
6
  def self.included(base)
5
7
  base.extend(ClassMethods)
@@ -49,16 +51,19 @@ module MoneyColumn
49
51
  return self[column] = nil
50
52
  end
51
53
 
52
- currency_raw_source = options[:currency] || (send(options[:currency_column]) rescue nil)
53
-
54
- if !money.is_a?(Money)
55
- return self[column] = Money.new(money, currency_raw_source).value
54
+ unless money.is_a?(Money)
55
+ return self[column] = Money::Helpers.value_to_decimal(money)
56
56
  end
57
57
 
58
58
  if options[:currency_read_only]
59
- currency_source = Money::Helpers.value_to_currency(currency_raw_source)
60
- if currency_raw_source && !money.currency.compatible?(currency_source)
61
- Money.deprecate("[money_column] currency mismatch between #{currency_source} and #{money.currency} in column #{column}.")
59
+ currency = options[:currency] || try(options[:currency_column])
60
+ if currency && !money.currency.compatible?(Money::Helpers.value_to_currency(currency))
61
+ msg = "[money_column] currency mismatch between #{currency} and #{money.currency} in column #{column}."
62
+ if Money.config.legacy_deprecations
63
+ Money.deprecate(msg)
64
+ else
65
+ raise MoneyColumn::CurrencyReadOnlyError, msg
66
+ end
62
67
  end
63
68
  else
64
69
  self[options[:currency_column]] = money.currency.to_s unless money.no_currency?
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+
4
+ RSpec.describe "Money::Config" do
5
+ describe 'legacy_deprecations' do
6
+ it "respects the default currency" do
7
+ configure(default_currency: 'USD', legacy_deprecations: true) do
8
+ expect(Money.default_currency).to eq("USD")
9
+ end
10
+ end
11
+
12
+ it 'defaults to not opt-in to v1' do
13
+ expect(Money::Config.new.legacy_deprecations).to eq(false)
14
+ end
15
+
16
+ it 'legacy_deprecations returns true when opting in to v1' do
17
+ configure(legacy_deprecations: true) do
18
+ expect(Money.config.legacy_deprecations).to eq(true)
19
+ end
20
+ end
21
+
22
+ it 'sets the deprecations to raise' do
23
+ configure(legacy_deprecations: true) do
24
+ expect { Money.deprecate("test") }.to raise_error(ActiveSupport::DeprecationException)
25
+ end
26
+ end
27
+
28
+ it 'legacy_deprecations defaults to NULL_CURRENCY' do
29
+ configure(legacy_default_currency: true) do
30
+ expect(Money.config.default_currency).to eq(Money::NULL_CURRENCY)
31
+ end
32
+ end
33
+ end
34
+
35
+ describe 'default_currency' do
36
+ it 'defaults to nil' do
37
+ configure do
38
+ expect(Money.config.default_currency).to eq(nil)
39
+ end
40
+ end
41
+
42
+ it 'can be set to a new currency' do
43
+ configure(default_currency: 'USD') do
44
+ expect(Money.config.default_currency).to eq('USD')
45
+ end
46
+ end
47
+ end
48
+ end
data/spec/helpers_spec.rb CHANGED
@@ -46,8 +46,10 @@ RSpec.describe Money::Helpers do
46
46
  end
47
47
 
48
48
  it 'invalid string returns zero' do
49
- expect(Money).to receive(:deprecate).once
50
- expect(subject.value_to_decimal('invalid')).to eq(0)
49
+ configure(legacy_deprecations: true) do
50
+ expect(Money).to receive(:deprecate).once
51
+ expect(subject.value_to_decimal('invalid')).to eq(0)
52
+ end
51
53
  end
52
54
 
53
55
  it 'raises on invalid object' do
@@ -70,7 +72,9 @@ RSpec.describe Money::Helpers do
70
72
  end
71
73
 
72
74
  it 'returns the default currency when value is empty' do
73
- expect(subject.value_to_currency('')).to eq(Money.default_currency)
75
+ configure(legacy_deprecations: true, default_currency: 'USD') do
76
+ expect(subject.value_to_currency('')).to eq(Money::Currency.new('USD'))
77
+ end
74
78
  end
75
79
 
76
80
  it 'returns the default currency when value is xxx' do
@@ -86,8 +90,10 @@ RSpec.describe Money::Helpers do
86
90
  end
87
91
 
88
92
  it 'returns the null currency when invalid iso is passed' do
89
- expect(Money).to receive(:deprecate).once
90
- expect(subject.value_to_currency('invalid')).to eq(Money::NULL_CURRENCY)
93
+ configure(legacy_deprecations: true) do
94
+ expect(Money).to receive(:deprecate).once
95
+ expect(subject.value_to_currency('invalid')).to eq(Money::NULL_CURRENCY)
96
+ end
91
97
  end
92
98
 
93
99
  it 'raises on invalid object' do
@@ -30,13 +30,18 @@ end
30
30
 
31
31
  class MoneyWithDelegatedCurrency < ActiveRecord::Base
32
32
  self.table_name = 'money_records'
33
- attr_accessor :delegated_record
34
33
  delegate :currency, to: :delegated_record
35
34
  money_column :price, currency_column: 'currency', currency_read_only: true
36
35
  money_column :prix, currency_column: 'currency2', currency_read_only: true
37
36
  def currency2
38
37
  delegated_record.currency
39
38
  end
39
+
40
+ private
41
+
42
+ def delegated_record
43
+ MoneyRecord.new(currency: 'USD')
44
+ end
40
45
  end
41
46
 
42
47
  class MoneyWithCustomAccessors < ActiveRecord::Base
@@ -97,11 +102,13 @@ RSpec.describe 'MoneyColumn' do
97
102
  end
98
103
 
99
104
  it 'returns money with null currency when the currency in the DB is invalid' do
100
- expect(Money).to receive(:deprecate).once
101
- record.update_columns(currency: 'invalid')
102
- record.reload
103
- expect(record.price.currency).to be_a(Money::NullCurrency)
104
- expect(record.price.value).to eq(1.23)
105
+ configure(legacy_deprecations: true) do
106
+ expect(Money).to receive(:deprecate).once
107
+ record.update_columns(currency: 'invalid')
108
+ record.reload
109
+ expect(record.price.currency).to be_a(Money::NullCurrency)
110
+ expect(record.price.value).to eq(1.23)
111
+ end
105
112
  end
106
113
 
107
114
  it 'handles legacy support for saving floats' do
@@ -114,12 +121,12 @@ RSpec.describe 'MoneyColumn' do
114
121
  expect(record.prix.currency.to_s).to eq('CAD')
115
122
  end
116
123
 
117
- it 'handles legacy support for saving floats with correct currency rounding' do
124
+ it 'handles legacy support for saving floats as provided' do
118
125
  record.update(price: 3.2112, prix: 3.2156)
119
- expect(record.attributes['price']).to eq(3.21)
126
+ expect(record.attributes['price']).to eq(3.2112)
120
127
  expect(record.price.value).to eq(3.21)
121
128
  expect(record.price.currency.to_s).to eq(currency)
122
- expect(record.attributes['prix']).to eq(3.22)
129
+ expect(record.attributes['prix']).to eq(3.2156)
123
130
  expect(record.prix.value).to eq(3.22)
124
131
  expect(record.prix.currency.to_s).to eq('CAD')
125
132
  end
@@ -165,8 +172,8 @@ RSpec.describe 'MoneyColumn' do
165
172
  describe 'garbage amount' do
166
173
  let(:amount) { 'foo' }
167
174
 
168
- it 'raises a deprecation warning' do
169
- expect { subject }.to raise_error(ActiveSupport::DeprecationException)
175
+ it 'raises an ArgumentError' do
176
+ expect { subject }.to raise_error(ArgumentError)
170
177
  end
171
178
  end
172
179
 
@@ -174,7 +181,7 @@ RSpec.describe 'MoneyColumn' do
174
181
  let(:currency) { 'foo' }
175
182
 
176
183
  it 'raises an UnknownCurrency error' do
177
- expect { subject }.to raise_error(ActiveSupport::DeprecationException)
184
+ expect { subject }.to raise_error(Money::Currency::UnknownCurrency)
178
185
  end
179
186
  end
180
187
 
@@ -217,11 +224,20 @@ RSpec.describe 'MoneyColumn' do
217
224
  describe 'read_only_currency true' do
218
225
  it 'does not write the currency to the db' do
219
226
  record = MoneyWithReadOnlyCurrency.create
220
- record.update_columns(price: 1, currency: 'USD')
221
- expect(Money).to receive(:deprecate).once
222
- record.update(price: Money.new(4, 'CAD'))
223
- expect(record.price.value).to eq(4)
224
- expect(record.price.currency.to_s).to eq('USD')
227
+ record.update_columns(currency: 'USD')
228
+ expect { record.update(price: Money.new(4, 'CAD')) }.to raise_error(MoneyColumn::CurrencyReadOnlyError)
229
+ end
230
+
231
+ it 'legacy_deprecations does not write the currency to the db' do
232
+ configure(legacy_deprecations: true) do
233
+ record = MoneyWithReadOnlyCurrency.create
234
+ record.update_columns(currency: 'USD')
235
+
236
+ expect(Money).to receive(:deprecate).once
237
+ record.update(price: Money.new(4, 'CAD'))
238
+ expect(record.price.value).to eq(4)
239
+ expect(record.price.currency.to_s).to eq('USD')
240
+ end
225
241
  end
226
242
 
227
243
  it 'reads the currency that is already in the db' do
@@ -233,12 +249,14 @@ RSpec.describe 'MoneyColumn' do
233
249
  end
234
250
 
235
251
  it 'reads an invalid currency from the db and generates a no currency object' do
236
- expect(Money).to receive(:deprecate).once
237
- record = MoneyWithReadOnlyCurrency.create
238
- record.update_columns(currency: 'invalid', price: 1)
239
- record.reload
240
- expect(record.price.value).to eq(1)
241
- expect(record.price.currency.to_s).to eq('')
252
+ configure(legacy_deprecations: true) do
253
+ expect(Money).to receive(:deprecate).once
254
+ record = MoneyWithReadOnlyCurrency.create
255
+ record.update_columns(currency: 'invalid', price: 1)
256
+ record.reload
257
+ expect(record.price.value).to eq(1)
258
+ expect(record.price.currency.to_s).to eq('')
259
+ end
242
260
  end
243
261
 
244
262
  it 'sets the currency correctly when the currency is changed' do
@@ -248,12 +266,12 @@ RSpec.describe 'MoneyColumn' do
248
266
  end
249
267
 
250
268
  it 'handle cases where the delegate allow_nil is false' do
251
- record = MoneyWithDelegatedCurrency.new(price: Money.new(10, 'USD'), delegated_record: MoneyRecord.new(currency: 'USD'))
269
+ record = MoneyWithDelegatedCurrency.new(price: Money.new(10, 'USD'))
252
270
  expect(record.price.currency.to_s).to eq('USD')
253
271
  end
254
272
 
255
273
  it 'handle cases where a manual delegate does not allow nil' do
256
- record = MoneyWithDelegatedCurrency.new(prix: Money.new(10, 'USD'), delegated_record: MoneyRecord.new(currency: 'USD'))
274
+ record = MoneyWithDelegatedCurrency.new(prix: Money.new(10, 'USD'))
257
275
  expect(record.price.currency.to_s).to eq('USD')
258
276
  end
259
277
  end
@@ -370,10 +388,7 @@ RSpec.describe 'MoneyColumn' do
370
388
 
371
389
  describe 'default_currency = nil' do
372
390
  around do |example|
373
- default_currency = Money.default_currency
374
- Money.default_currency = nil
375
- example.run
376
- Money.default_currency = default_currency
391
+ configure(default_currency: nil) { example.run }
377
392
  end
378
393
 
379
394
  it 'writes currency from input value to the db' do
@@ -384,11 +399,17 @@ RSpec.describe 'MoneyColumn' do
384
399
  expect(record.price.currency.to_s).to eq('GBP')
385
400
  end
386
401
 
387
- it 'raises missing currency error when input is not a money object' do
388
- record.update(currency: nil)
402
+ it 'raises missing currency error reading a value that was saved using legacy non-money object' do
403
+ record.update(currency: nil, price: 3)
404
+ expect { record.price }.to raise_error(ArgumentError, 'missing currency')
405
+ end
389
406
 
390
- expect { record.update(price: 3) }
391
- .to raise_error(ArgumentError, 'missing currency')
407
+ it 'handles legacy support for saving price and currency separately' do
408
+ record.update(currency: nil)
409
+ record.update(price: 7, currency: 'GBP')
410
+ record.reload
411
+ expect(record.price.value).to eq(7)
412
+ expect(record.price.currency.to_s).to eq('GBP')
392
413
  end
393
414
  end
394
415
  end
data/spec/money_spec.rb CHANGED
@@ -3,23 +3,20 @@ require 'spec_helper'
3
3
  require 'yaml'
4
4
 
5
5
  RSpec.describe "Money" do
6
-
7
6
  let (:money) { Money.new(1) }
8
7
  let (:amount_money) { Money.new(1.23, 'USD') }
9
8
  let (:non_fractional_money) { Money.new(1, 'JPY') }
10
9
  let (:zero_money) { Money.new(0) }
11
10
 
12
- context "default currency not set" do
13
- before(:each) do
14
- @default_currency = Money.default_currency
15
- Money.default_currency = nil
16
- end
17
- after(:each) do
18
- Money.default_currency = @default_currency
19
- end
11
+ it "has a version" do
12
+ expect(Money::VERSION).not_to(eq(nil))
13
+ end
20
14
 
15
+ context "default currency not set" do
21
16
  it "raises an error" do
22
- expect { money }.to raise_error(ArgumentError)
17
+ configure(default_currency: nil) do
18
+ expect { money }.to raise_error(ArgumentError)
19
+ end
23
20
  end
24
21
  end
25
22
 
@@ -39,9 +36,15 @@ RSpec.describe "Money" do
39
36
  expect(Money.new(1).to_money('CAD')).to eq(Money.new(1, 'CAD'))
40
37
  end
41
38
 
42
- it "#to_money doesn't overwrite the money object's currency" do
43
- expect(Money).to receive(:deprecate).once
44
- expect(Money.new(1, 'USD').to_money('CAD')).to eq(Money.new(1, 'USD'))
39
+ it "legacy_deprecations #to_money doesn't overwrite the money object's currency" do
40
+ configure(legacy_deprecations: true) do
41
+ expect(Money).to receive(:deprecate).once
42
+ expect(Money.new(1, 'USD').to_money('CAD')).to eq(Money.new(1, 'USD'))
43
+ end
44
+ end
45
+
46
+ it "#to_money raises when changing currency" do
47
+ expect{ Money.new(1, 'USD').to_money('CAD') }.to raise_error(Money::IncompatibleCurrencyError)
45
48
  end
46
49
 
47
50
  it "defaults to 0 when constructed with no arguments" do
@@ -52,9 +55,15 @@ RSpec.describe "Money" do
52
55
  expect(Money.new('')).to eq(Money.new(0))
53
56
  end
54
57
 
55
- it "defaults to 0 when constructed with an invalid string" do
56
- expect(Money).to receive(:deprecate).once
57
- expect(Money.new('invalid')).to eq(Money.new(0.00))
58
+ it "legacy_deprecations defaults to 0 when constructed with an invalid string" do
59
+ configure(legacy_deprecations: true) do
60
+ expect(Money).to receive(:deprecate).once
61
+ expect(Money.new('invalid', 'USD')).to eq(Money.new(0.00, 'USD'))
62
+ end
63
+ end
64
+
65
+ it "raises when constructed with an invalid string" do
66
+ expect{ Money.new('invalid') }.to raise_error(ArgumentError)
58
67
  end
59
68
 
60
69
  it "to_s correctly displays the right number of decimal places" do
@@ -62,14 +71,14 @@ RSpec.describe "Money" do
62
71
  expect(non_fractional_money.to_s).to eq("1")
63
72
  end
64
73
 
65
- it "to_s with a legacy_dollars style" do
66
- expect(amount_money.to_s(:legacy_dollars)).to eq("1.23")
67
- expect(non_fractional_money.to_s(:legacy_dollars)).to eq("1.00")
74
+ it "to_fs with a legacy_dollars style" do
75
+ expect(amount_money.to_fs(:legacy_dollars)).to eq("1.23")
76
+ expect(non_fractional_money.to_fs(:legacy_dollars)).to eq("1.00")
68
77
  end
69
78
 
70
- it "to_s with a amount style" do
71
- expect(amount_money.to_s(:amount)).to eq("1.23")
72
- expect(non_fractional_money.to_s(:amount)).to eq("1")
79
+ it "to_fs with a amount style" do
80
+ expect(amount_money.to_fs(:amount)).to eq("1.23")
81
+ expect(non_fractional_money.to_fs(:amount)).to eq("1")
73
82
  end
74
83
 
75
84
  it "to_s correctly displays negative numbers" do
@@ -95,12 +104,31 @@ RSpec.describe "Money" do
95
104
  expect(Money.new("999999999999999999.99", "USD").to_s).to eq("999999999999999999.99")
96
105
  end
97
106
 
98
- it "to_s raises ArgumentError on unsupported style" do
99
- expect{ money.to_s(:some_weird_style) }.to raise_error(ArgumentError)
107
+ it "to_fs raises ArgumentError on unsupported style" do
108
+ expect{ money.to_fs(:some_weird_style) }.to raise_error(ArgumentError)
109
+ end
110
+
111
+ it "to_fs is aliased as to_s for backward compatibility" do
112
+ expect(money.method(:to_s)).to eq(money.method(:to_fs))
113
+ end
114
+
115
+ it "to_fs is aliased as to_formatted_s for backward compatibility" do
116
+ expect(money.method(:to_formatted_s)).to eq(money.method(:to_fs))
117
+ end
118
+
119
+ it "legacy_json_format makes as_json return the legacy format" do
120
+ configure(legacy_json_format: true) do
121
+ expect(Money.new(1, 'CAD').as_json).to eq("1.00")
122
+ end
123
+ end
124
+
125
+ it "legacy_format correctly sets the json format" do
126
+ expect(Money.new(1, 'CAD').as_json(legacy_format: true)).to eq("1.00")
127
+ expect(Money.new(1, 'CAD').to_json(legacy_format: true)).to eq("1.00")
100
128
  end
101
129
 
102
- it "as_json as a float with 2 decimal places" do
103
- expect(money.as_json).to eq("1.00")
130
+ it "as_json as a json containing the value and currency" do
131
+ expect(money.as_json).to eq(value: "1.00", currency: "CAD")
104
132
  end
105
133
 
106
134
  it "is constructable with a BigDecimal" do
@@ -139,9 +167,15 @@ RSpec.describe "Money" do
139
167
  expect((Money.new + Money.new)).to eq(Money.new)
140
168
  end
141
169
 
142
- it "adds inconsistent currencies" do
143
- expect(Money).to receive(:deprecate).once
144
- expect(Money.new(5, 'USD') + Money.new(1, 'CAD')).to eq(Money.new(6, 'USD'))
170
+ it "legacy_deprecations adds inconsistent currencies" do
171
+ configure(legacy_deprecations: true) do
172
+ expect(Money).to receive(:deprecate).once
173
+ expect(Money.new(5, 'USD') + Money.new(1, 'CAD')).to eq(Money.new(6, 'USD'))
174
+ end
175
+ end
176
+
177
+ it "raises when adding inconsistent currencies" do
178
+ expect{ Money.new(5, 'USD') + Money.new(1, 'CAD') }.to raise_error(Money::IncompatibleCurrencyError)
145
179
  end
146
180
 
147
181
  it "is subtractable" do
@@ -157,8 +191,10 @@ RSpec.describe "Money" do
157
191
  end
158
192
 
159
193
  it "logs a deprecation warning when adding across currencies" do
160
- expect(Money).to receive(:deprecate)
161
- expect(Money.new(10, 'USD') - Money.new(1, 'JPY')).to eq(Money.new(9, 'USD'))
194
+ configure(legacy_deprecations: true) do
195
+ expect(Money).to receive(:deprecate)
196
+ expect(Money.new(10, 'USD') - Money.new(1, 'JPY')).to eq(Money.new(9, 'USD'))
197
+ end
162
198
  end
163
199
 
164
200
  it "keeps currency when doing a computation with a null currency" do
@@ -254,9 +290,15 @@ RSpec.describe "Money" do
254
290
  expect(((1.0 / 12) * Money.new(3.3))).to eq(Money.new(0.28))
255
291
  end
256
292
 
257
- it "is multipliable by a money object" do
258
- expect(Money).to receive(:deprecate).once
259
- expect((Money.new(3.3) * Money.new(1))).to eq(Money.new(3.3))
293
+ it "legacy_deprecations is multipliable by a money object" do
294
+ configure(legacy_deprecations: true) do
295
+ expect(Money).to receive(:deprecate).once
296
+ expect((Money.new(3.3, 'USD') * Money.new(1, 'USD'))).to eq(Money.new(3.3, 'USD'))
297
+ end
298
+ end
299
+
300
+ it "raises when multiplied by a money object" do
301
+ expect{ (Money.new(3.3) * Money.new(1)) }.to raise_error(ArgumentError)
260
302
  end
261
303
 
262
304
  it "rounds multiplication result with fractional penny of 5 or higher up" do
@@ -294,7 +336,14 @@ RSpec.describe "Money" do
294
336
  end
295
337
 
296
338
  it "returns cents in to_json" do
297
- expect(Money.new(1.00).to_json).to eq("1.00")
339
+ configure(legacy_json_format: true) do
340
+ expect(Money.new('1.23', 'USD').to_json).to eq('1.23')
341
+ end
342
+ end
343
+
344
+ it "returns value and currency in to_json" do
345
+ expect(Money.new(1.00).to_json).to eq('{"value":"1.00","currency":"CAD"}')
346
+ expect(JSON.dump(Money.new(1.00, "CAD"))).to eq('{"value":"1.00","currency":"CAD"}')
298
347
  end
299
348
 
300
349
  it "supports absolute value" do
@@ -352,9 +401,36 @@ RSpec.describe "Money" do
352
401
  end
353
402
 
354
403
  it "generates a true rational" do
355
- expect(Money.rational(Money.new(10.0), Money.new(15.0))).to eq(Rational(2,3))
356
- expect(Money).to receive(:deprecate).once
357
- expect(Money.rational(Money.new(10.0, 'USD'), Money.new(15.0, 'JPY'))).to eq(Rational(2,3))
404
+ expect(Money.rational(Money.new(10.0, 'USD'), Money.new(15.0, 'USD'))).to eq(Rational(2,3))
405
+
406
+ configure(legacy_deprecations: true) do
407
+ expect(Money).to receive(:deprecate).once
408
+ expect(Money.rational(Money.new(10.0, 'USD'), Money.new(15.0, 'JPY'))).to eq(Rational(2,3))
409
+ end
410
+ end
411
+
412
+ it "does not allocate a new money object when multiplying by 1" do
413
+ expect((money * 1).object_id).to eq(money.object_id)
414
+ end
415
+
416
+ it "does not allocate a new money object when adding 0" do
417
+ expect((money + 0).object_id).to eq(money.object_id)
418
+ end
419
+
420
+ it "does not allocate a new money object when subtracting 0" do
421
+ expect((money - 0).object_id).to eq(money.object_id)
422
+ end
423
+
424
+ it "does not allocate when computing absolute value when already positive" do
425
+ expect((money.abs).object_id).to eq(money.object_id)
426
+ end
427
+
428
+ it "does not allocate when computing floor value when already floored" do
429
+ expect((money.floor).object_id).to eq(money.object_id)
430
+ end
431
+
432
+ it "does not allocate when computing floor value when already rounded" do
433
+ expect((money.round).object_id).to eq(money.object_id)
358
434
  end
359
435
 
360
436
  describe "frozen with amount of $1" do
@@ -413,9 +489,11 @@ RSpec.describe "Money" do
413
489
  end
414
490
 
415
491
  it "<=> issues deprecation warning when comparing incompatible currency" do
416
- expect(Money).to receive(:deprecate).twice
417
- expect(Money.new(1000, 'USD') <=> Money.new(2000, 'JPY')).to eq(-1)
418
- expect(Money.new(2000, 'JPY') <=> Money.new(1000, 'USD')).to eq(1)
492
+ configure(legacy_deprecations: true) do
493
+ expect(Money).to receive(:deprecate).twice
494
+ expect(Money.new(1000, 'USD') <=> Money.new(2000, 'JPY')).to eq(-1)
495
+ expect(Money.new(2000, 'JPY') <=> Money.new(1000, 'USD')).to eq(1)
496
+ end
419
497
  end
420
498
 
421
499
  describe('same values') do
@@ -437,15 +515,22 @@ RSpec.describe "Money" do
437
515
  it { expect(cad_10 < nil_10).to(eq(false)) }
438
516
  end
439
517
 
440
- describe('different currencies') do
518
+ describe('legacy different currencies') do
519
+ around(:each) do |test|
520
+ configure(legacy_deprecations: true) { test.run }
521
+ end
522
+
441
523
  it { expect(Money).to(receive(:deprecate).once); expect(cad_10 <=> usd_10).to(eq(0)) }
442
524
  it { expect(Money).to(receive(:deprecate).once); expect(cad_10 > usd_10).to(eq(false)) }
443
525
  it { expect(Money).to(receive(:deprecate).once); expect(cad_10 >= usd_10).to(eq(true)) }
444
- it { expect(cad_10 == usd_10).to(eq(false)) }
445
526
  it { expect(Money).to(receive(:deprecate).once); expect(cad_10 <= usd_10).to(eq(true)) }
446
527
  it { expect(Money).to(receive(:deprecate).once); expect(cad_10 < usd_10).to(eq(false)) }
447
528
  end
448
529
 
530
+ describe('different currencies') do
531
+ it { expect(cad_10 == usd_10).to(eq(false)) }
532
+ end
533
+
449
534
  describe('to_money types') do
450
535
  it { expect(cad_10 <=> 10.00).to(eq(0)) }
451
536
  it { expect(cad_10 > 10.00).to(eq(false)) }
@@ -709,23 +794,6 @@ RSpec.describe "Money" do
709
794
  end
710
795
  end
711
796
 
712
- describe "parser dependency injection" do
713
- before(:each) { Money.parser = AccountingMoneyParser }
714
- after(:each) { Money.parser = MoneyParser }
715
-
716
- it "keeps AccountingMoneyParser class on new money objects" do
717
- expect(Money.new.class.parser).to eq(AccountingMoneyParser)
718
- end
719
-
720
- it "supports parenthesis from AccountingMoneyParser" do
721
- expect(Money.parse("($5.00)")).to eq(Money.new(-5))
722
- end
723
-
724
- it "supports parenthesis from AccountingMoneyParser for .to_money" do
725
- expect("($5.00)".to_money).to eq(Money.new(-5))
726
- end
727
- end
728
-
729
797
  describe "round" do
730
798
 
731
799
  it "rounds to 0 decimal places by default" do
@@ -875,8 +943,7 @@ RSpec.describe "Money" do
875
943
  end
876
944
 
877
945
  context "with .default_currency set" do
878
- before(:each) { Money.default_currency = Money::Currency.new('EUR') }
879
- after(:each) { Money.default_currency = Money::NULL_CURRENCY }
946
+ around(:each) { |test| configure(default_currency: Money::Currency.new('EUR')) { test.run }}
880
947
 
881
948
  it "can be nested and falls back to default_currency outside of the blocks" do
882
949
  money2, money3 = nil