shopify-money 1.2.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/tests.yml +2 -2
- data/README.md +30 -16
- data/dev.yml +1 -1
- data/lib/money/core_extensions.rb +9 -1
- data/lib/money/deprecations.rb +4 -1
- data/lib/money/helpers.rb +0 -2
- data/lib/money/money.rb +2 -7
- data/lib/money/version.rb +1 -1
- data/lib/rubocop/cop/money/missing_currency.rb +2 -1
- data/lib/rubocop/cop/money/unsafe_to_money.rb +1 -1
- data/money.gemspec +1 -1
- data/spec/core_extensions_spec.rb +20 -2
- data/spec/deprecations_spec.rb +9 -0
- data/spec/helpers_spec.rb +2 -2
- data/spec/money_spec.rb +0 -7
- data/spec/rubocop/cop/money/missing_currency_spec.rb +7 -0
- data/spec/rubocop/cop/money/unsafe_to_money_spec.rb +6 -0
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 591c60e355144246085ac254fe82b099c85ab4bf7f1e37672b8082331bd9d0aa
|
4
|
+
data.tar.gz: 493384ced59c9a37ebc798b4cb499bd0532ea30243c8248704bf0df6f776ca0f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1867df0795206ccd5996b1d8471f23f60340ace3e5e685ddbb98f601402a7748aade38263dbc7f12971c1e4368919cb0122c53eacf0b96b96df44189be3ca32e
|
7
|
+
data.tar.gz: 9ed8869fce8e66c4e9aee275ac3a28c24db47fd2ae8537f2ff3ee100541f122cd9b8b87e7ca102567b976548eb04b53b06f6c560f2e6e12dc3ca506e0bb87f01
|
data/.github/workflows/tests.yml
CHANGED
data/README.md
CHANGED
@@ -1,20 +1,17 @@
|
|
1
1
|
# money
|
2
2
|
|
3
|
-
[![tests](https://github.com/Shopify/money/workflows/tests/badge.svg)](https://github.com/Shopify/money/actions?query=workflow%3Atests+branch%
|
3
|
+
[![tests](https://github.com/Shopify/money/workflows/tests/badge.svg)](https://github.com/Shopify/money/actions?query=workflow%3Atests+branch%3Amain)
|
4
4
|
|
5
5
|
|
6
6
|
money_column expects a DECIMAL(21,3) database field.
|
7
7
|
|
8
8
|
### Features
|
9
9
|
|
10
|
-
-
|
11
|
-
- Provides a `Money` class which encapsulates all information about
|
12
|
-
|
13
|
-
-
|
14
|
-
|
15
|
-
- Does NOT provides APIs for exchanging money from one currency to another.
|
16
|
-
- wont lose pennies during division!
|
17
|
-
- Money::NullCurrency for no currency support
|
10
|
+
- Provides a `Money` class which encapsulates all information about a certain amount of money, such as its value and its currency.
|
11
|
+
- Provides a `Money::Currency` class which encapsulates all information about a monetary unit.
|
12
|
+
- Represents monetary values as decimals. No need to convert your amounts every time you use them. Easily understand the data in your DB.
|
13
|
+
- Does NOT provide APIs for exchanging money from one currency to another.
|
14
|
+
- Will not lose pennies during divisions
|
18
15
|
|
19
16
|
## Installation
|
20
17
|
|
@@ -22,7 +19,7 @@ money_column expects a DECIMAL(21,3) database field.
|
|
22
19
|
|
23
20
|
## Upgrading to v1.0
|
24
21
|
|
25
|
-
see instructions and breaking changes: https://github.com/Shopify/money/blob/
|
22
|
+
see instructions and breaking changes: https://github.com/Shopify/money/blob/main/UPGRADING.md
|
26
23
|
|
27
24
|
## Usage
|
28
25
|
|
@@ -32,7 +29,7 @@ require 'money'
|
|
32
29
|
# 10.00 USD
|
33
30
|
money = Money.new(10.00, "USD")
|
34
31
|
money.subunits #=> 1000
|
35
|
-
money.currency
|
32
|
+
money.currency #=> Money::Currency.new("USD")
|
36
33
|
|
37
34
|
# Comparisons
|
38
35
|
Money.new(1000, "USD") == Money.new(1000, "USD") #=> true
|
@@ -43,13 +40,30 @@ Money.new(1000, "USD") != Money.new(1000, "EUR") #=> true
|
|
43
40
|
# Arithmetic
|
44
41
|
Money.new(1000, "USD") + Money.new(500, "USD") == Money.new(1500, "USD")
|
45
42
|
Money.new(1000, "USD") - Money.new(200, "USD") == Money.new(800, "USD")
|
46
|
-
Money.new(1000, "USD") / 5 == Money.new(200, "USD")
|
47
43
|
Money.new(1000, "USD") * 5 == Money.new(5000, "USD")
|
48
44
|
|
45
|
+
m = Money.new(1000, "USD")
|
46
|
+
# Splitting money evenly
|
47
|
+
m.split(2) == [Money.new(500, "USD"), Money.new(500, "USD")]
|
48
|
+
m.split(3).map(&:value) == [333.34, 333.33, 333.33]
|
49
|
+
m.calculate_splits(2) == { Money.new(500, "USD") => 2 }
|
50
|
+
m.calculate_splits(3) == { Money.new(333.34, "USD") => 1, Money.new(333.33, "USD") =>2 }
|
51
|
+
|
52
|
+
# Allocating money proportionally
|
53
|
+
m.allocate([0.50, 0.25, 0.25]).map(&:value) == [500, 250, 250]
|
54
|
+
m.allocate([Rational(2, 3), Rational(1, 3)]).map(&:value) == [666.67, 333.33]
|
55
|
+
|
56
|
+
## Allocating up to a cutoff
|
57
|
+
m.allocate_max_amounts([500, 300, 200]).map(&:value) == [500, 300, 200]
|
58
|
+
m.allocate_max_amounts([500, 300, 300]).map(&:value) == [454.55, 272.73, 272.72]
|
59
|
+
|
60
|
+
# Clamp
|
61
|
+
Money.new(50, "USD").clamp(1, 100) == Money.new(50, "USD")
|
62
|
+
|
49
63
|
# Unit to subunit conversions
|
50
|
-
Money.from_subunits(500, "USD")
|
51
|
-
Money.from_subunits(5, "JPY")
|
52
|
-
Money.from_subunits(5000, "TND") == Money.new(5, "TND")
|
64
|
+
Money.from_subunits(500, "USD") == Money.new(5, "USD") # 5 USD
|
65
|
+
Money.from_subunits(5, "JPY") == Money.new(5, "JPY") # 5 JPY
|
66
|
+
Money.from_subunits(5000, "TND") == Money.new(5, "TND") # 5 TND
|
53
67
|
```
|
54
68
|
|
55
69
|
## Currency
|
@@ -171,7 +185,7 @@ Money/UnsafeToMoney:
|
|
171
185
|
|
172
186
|
## Contributing to money
|
173
187
|
|
174
|
-
- Check out the latest
|
188
|
+
- Check out the latest main to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
175
189
|
- Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
176
190
|
- Fork the project
|
177
191
|
- Start a feature/bugfix branch
|
data/dev.yml
CHANGED
@@ -14,6 +14,14 @@ end
|
|
14
14
|
# '100.37'.to_money => #<Money @cents=10037>
|
15
15
|
class String
|
16
16
|
def to_money(currency = nil)
|
17
|
-
Money
|
17
|
+
if Money.config.legacy_deprecations
|
18
|
+
Money::Parser::Fuzzy.parse(self, currency).tap do |money|
|
19
|
+
message = "`#{self}.to_money` will behave like `Money.new` and raise on the next release. " \
|
20
|
+
"To parse user input, do so on the browser and use the user's locale."
|
21
|
+
Money.deprecate(message) if money.value != BigDecimal(self, exception: false)
|
22
|
+
end
|
23
|
+
else
|
24
|
+
Money.new(self, currency)
|
25
|
+
end
|
18
26
|
end
|
19
27
|
end
|
data/lib/money/deprecations.rb
CHANGED
@@ -3,7 +3,10 @@ Money.class_eval do
|
|
3
3
|
ACTIVE_SUPPORT_DEFINED = defined?(ActiveSupport)
|
4
4
|
|
5
5
|
def self.active_support_deprecator
|
6
|
-
@active_support_deprecator ||=
|
6
|
+
@active_support_deprecator ||= begin
|
7
|
+
next_major_version = Money::VERSION.split(".").first.to_i + 1
|
8
|
+
ActiveSupport::Deprecation.new("#{next_major_version}.0.0", "Shopify/Money")
|
9
|
+
end
|
7
10
|
end
|
8
11
|
|
9
12
|
def self.deprecate(message)
|
data/lib/money/helpers.rb
CHANGED
data/lib/money/money.rb
CHANGED
@@ -137,13 +137,8 @@ class Money
|
|
137
137
|
end
|
138
138
|
|
139
139
|
def *(numeric)
|
140
|
-
unless numeric.is_a?(Numeric)
|
141
|
-
|
142
|
-
Money.deprecate("Multiplying Money with #{numeric.class.name} is deprecated and will be removed in the next major release.")
|
143
|
-
else
|
144
|
-
raise ArgumentError, "Money objects can only be multiplied by a Numeric"
|
145
|
-
end
|
146
|
-
end
|
140
|
+
raise ArgumentError, "Money objects can only be multiplied by a Numeric" unless numeric.is_a?(Numeric)
|
141
|
+
|
147
142
|
return self if numeric == 1
|
148
143
|
Money.new(value.to_r * numeric, currency)
|
149
144
|
end
|
data/lib/money/version.rb
CHANGED
@@ -32,7 +32,8 @@ module RuboCop
|
|
32
32
|
PATTERN
|
33
33
|
|
34
34
|
def on_send(node)
|
35
|
-
money_new(node) do |
|
35
|
+
money_new(node) do |amount, currency_arg|
|
36
|
+
return if amount&.splat_type?
|
36
37
|
return if currency_arg
|
37
38
|
|
38
39
|
add_offense(node, message: 'Money is missing currency argument')
|
data/money.gemspec
CHANGED
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.add_development_dependency("database_cleaner", "~> 1.6")
|
23
23
|
s.add_development_dependency("sqlite3", "~> 1.4.2")
|
24
24
|
|
25
|
-
s.required_ruby_version = '>=
|
25
|
+
s.required_ruby_version = '>= 3.0'
|
26
26
|
|
27
27
|
s.files = `git ls-files`.split($/)
|
28
28
|
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
@@ -43,8 +43,26 @@ 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(
|
47
|
-
|
46
|
+
expect("".to_money("USD")).to eq(Money.new(0, "USD"))
|
47
|
+
|
48
|
+
configure(legacy_deprecations: true) do
|
49
|
+
expect(Money).to receive(:deprecate).once
|
50
|
+
expect(" ".to_money("CAD")).to eq(Money.new(0, "CAD"))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
it "#to_money to handle thousands delimiters" do
|
55
|
+
configure(legacy_deprecations: true) do
|
56
|
+
expect(Money).to receive(:deprecate).exactly(4).times
|
57
|
+
expect("29.000".to_money("USD")).to eq(Money.new("29000", "USD"))
|
58
|
+
expect("29.000,00".to_money("USD")).to eq(Money.new("29000", "USD"))
|
59
|
+
expect("29,000".to_money("USD")).to eq(Money.new("29000", "USD"))
|
60
|
+
expect("29,000.00".to_money("USD")).to eq(Money.new("29000", "USD"))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
it "#to_money should behave like Money.new with three decimal places amounts" do
|
65
|
+
expect("29.000".to_money("USD")).to eq(Money.new("29.00", "USD"))
|
48
66
|
end
|
49
67
|
end
|
50
68
|
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
RSpec.describe "deprecations" do
|
5
|
+
it "has the deprecation_horizon as the next major release" do
|
6
|
+
allow(Money).to receive(:const_get).with('VERSION').and_return("2.0.0")
|
7
|
+
expect(Money.active_support_deprecator.deprecation_horizon).to eq("3.0.0")
|
8
|
+
end
|
9
|
+
end
|
data/spec/helpers_spec.rb
CHANGED
@@ -7,8 +7,8 @@ RSpec.describe Money::Helpers do
|
|
7
7
|
let (:amount) { BigDecimal('1.23') }
|
8
8
|
let (:money) { Money.new(amount) }
|
9
9
|
|
10
|
-
it '
|
11
|
-
expect
|
10
|
+
it 'raises when provided with a money object' do
|
11
|
+
expect { subject.value_to_decimal(money) }.to raise_error(ArgumentError)
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'returns itself if it is already a big decimal' do
|
data/spec/money_spec.rb
CHANGED
@@ -290,13 +290,6 @@ RSpec.describe "Money" do
|
|
290
290
|
expect(((1.0 / 12) * Money.new(3.3))).to eq(Money.new(0.28))
|
291
291
|
end
|
292
292
|
|
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
293
|
it "raises when multiplied by a money object" do
|
301
294
|
expect{ (Money.new(3.3) * Money.new(1)) }.to raise_error(ArgumentError)
|
302
295
|
end
|
@@ -26,6 +26,13 @@ RSpec.describe RuboCop::Cop::Money::MissingCurrency do
|
|
26
26
|
RUBY
|
27
27
|
end
|
28
28
|
|
29
|
+
it 'does not register an offense for Money.new with splat argument' do
|
30
|
+
expect_no_offenses(<<~RUBY)
|
31
|
+
value_and_currency = [1, 'CAD']
|
32
|
+
Money.new(*value_and_currency)
|
33
|
+
RUBY
|
34
|
+
end
|
35
|
+
|
29
36
|
it 'registers an offense and corrects for Money.new without a currency argument' do
|
30
37
|
expect_offense(<<~RUBY)
|
31
38
|
Money.new
|
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:
|
4
|
+
version: 2.0.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:
|
11
|
+
date: 2024-01-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -149,6 +149,7 @@ files:
|
|
149
149
|
- spec/core_extensions_spec.rb
|
150
150
|
- spec/currency/loader_spec.rb
|
151
151
|
- spec/currency_spec.rb
|
152
|
+
- spec/deprecations_spec.rb
|
152
153
|
- spec/helpers_spec.rb
|
153
154
|
- spec/money_column_spec.rb
|
154
155
|
- spec/money_spec.rb
|
@@ -178,14 +179,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
178
179
|
requirements:
|
179
180
|
- - ">="
|
180
181
|
- !ruby/object:Gem::Version
|
181
|
-
version: '
|
182
|
+
version: '3.0'
|
182
183
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
183
184
|
requirements:
|
184
185
|
- - ">="
|
185
186
|
- !ruby/object:Gem::Version
|
186
187
|
version: '0'
|
187
188
|
requirements: []
|
188
|
-
rubygems_version: 3.
|
189
|
+
rubygems_version: 3.5.5
|
189
190
|
signing_key:
|
190
191
|
specification_version: 4
|
191
192
|
summary: Shopify's money gem
|
@@ -195,6 +196,7 @@ test_files:
|
|
195
196
|
- spec/core_extensions_spec.rb
|
196
197
|
- spec/currency/loader_spec.rb
|
197
198
|
- spec/currency_spec.rb
|
199
|
+
- spec/deprecations_spec.rb
|
198
200
|
- spec/helpers_spec.rb
|
199
201
|
- spec/money_column_spec.rb
|
200
202
|
- spec/money_spec.rb
|