shopify-money 0.14.1 → 0.14.6
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 +4 -4
- data/.travis.yml +0 -3
- data/Gemfile +2 -1
- data/README.md +20 -1
- data/Rakefile +1 -0
- data/bin/console +1 -0
- data/config/currency_historic.yml +181 -0
- data/config/currency_iso.yml +2630 -0
- data/config/currency_non_iso.yml +96 -0
- data/dev.yml +1 -1
- data/lib/money.rb +3 -0
- data/lib/money/allocator.rb +1 -0
- data/lib/money/core_extensions.rb +1 -0
- data/lib/money/currency.rb +1 -0
- data/lib/money/currency/loader.rb +28 -15
- data/lib/money/deprecations.rb +1 -0
- data/lib/money/errors.rb +1 -0
- data/lib/money/helpers.rb +5 -15
- data/lib/money/money.rb +17 -5
- data/lib/money/null_currency.rb +1 -0
- data/lib/money/version.rb +2 -1
- data/lib/money_accessor.rb +1 -0
- data/lib/money_column.rb +1 -0
- data/lib/money_column/active_record_hooks.rb +2 -1
- data/lib/money_column/active_record_type.rb +1 -0
- data/lib/money_column/railtie.rb +1 -0
- data/lib/rubocop/cop/money.rb +3 -0
- data/lib/rubocop/cop/money/missing_currency.rb +75 -0
- data/lib/shopify-money.rb +2 -0
- data/money.gemspec +7 -3
- data/spec/accounting_money_parser_spec.rb +1 -0
- data/spec/allocator_spec.rb +1 -0
- data/spec/core_extensions_spec.rb +1 -0
- data/spec/currency/loader_spec.rb +1 -0
- data/spec/currency_spec.rb +1 -0
- data/spec/helpers_spec.rb +1 -6
- data/spec/money_accessor_spec.rb +1 -0
- data/spec/money_column_spec.rb +1 -0
- data/spec/money_parser_spec.rb +1 -0
- data/spec/money_spec.rb +28 -0
- data/spec/null_currency_spec.rb +1 -0
- data/spec/rubocop/cop/money/missing_currency_spec.rb +108 -0
- data/spec/rubocop_helper.rb +10 -0
- data/spec/schema.rb +1 -0
- data/spec/spec_helper.rb +1 -5
- metadata +19 -25
- data/config/currency_historic.json +0 -157
- data/config/currency_iso.json +0 -2642
- data/config/currency_non_iso.json +0 -82
@@ -0,0 +1,96 @@
|
|
1
|
+
---
|
2
|
+
jep:
|
3
|
+
priority: 100
|
4
|
+
iso_code: JEP
|
5
|
+
name: Jersey Pound
|
6
|
+
symbol: "£"
|
7
|
+
disambiguate_symbol: JEP
|
8
|
+
alternate_symbols: []
|
9
|
+
subunit: Penny
|
10
|
+
subunit_to_unit: 100
|
11
|
+
symbol_first: true
|
12
|
+
html_entity: "£"
|
13
|
+
decimal_mark: "."
|
14
|
+
thousands_separator: ","
|
15
|
+
iso_numeric: ''
|
16
|
+
smallest_denomination: 1
|
17
|
+
kid:
|
18
|
+
# The Kiribati Dollar is pegged 1:1 to the AUD, but banknotes and coins in both currencies circulate interchangeably.
|
19
|
+
# "Although Kiribati retained 1 and 2 cents coins well after Australia demoted theirs,
|
20
|
+
# redundancy and devaluation has slowly removed these coins from general circulation."
|
21
|
+
# Source: https://en.wikipedia.org/wiki/Kiribati_dollar
|
22
|
+
priority: 100
|
23
|
+
iso_code: KID
|
24
|
+
name: Kiribati Dollar
|
25
|
+
symbol: "$"
|
26
|
+
disambiguate_symbol: KID
|
27
|
+
alternate_symbols: []
|
28
|
+
subunit: Cent
|
29
|
+
subunit_to_unit: 100
|
30
|
+
symbol_first: true
|
31
|
+
html_entity: "$"
|
32
|
+
decimal_mark: "."
|
33
|
+
thousands_separator: ","
|
34
|
+
iso_numeric: ''
|
35
|
+
smallest_denomination: 5
|
36
|
+
ggp:
|
37
|
+
priority: 100
|
38
|
+
iso_code: GGP
|
39
|
+
name: Guernsey Pound
|
40
|
+
symbol: "£"
|
41
|
+
disambiguate_symbol: GGP
|
42
|
+
alternate_symbols: []
|
43
|
+
subunit: Penny
|
44
|
+
subunit_to_unit: 100
|
45
|
+
symbol_first: true
|
46
|
+
html_entity: "£"
|
47
|
+
decimal_mark: "."
|
48
|
+
thousands_separator: ","
|
49
|
+
iso_numeric: ''
|
50
|
+
smallest_denomination: 1
|
51
|
+
imp:
|
52
|
+
priority: 100
|
53
|
+
iso_code: IMP
|
54
|
+
name: Isle of Man Pound
|
55
|
+
symbol: "£"
|
56
|
+
disambiguate_symbol: IMP
|
57
|
+
alternate_symbols:
|
58
|
+
- M£
|
59
|
+
subunit: Penny
|
60
|
+
subunit_to_unit: 100
|
61
|
+
symbol_first: true
|
62
|
+
html_entity: "£"
|
63
|
+
decimal_mark: "."
|
64
|
+
thousands_separator: ","
|
65
|
+
iso_numeric: ''
|
66
|
+
smallest_denomination: 1
|
67
|
+
xfu:
|
68
|
+
priority: 100
|
69
|
+
iso_code: XFU
|
70
|
+
name: UIC Franc
|
71
|
+
symbol: ''
|
72
|
+
disambiguate_symbol: XFU
|
73
|
+
alternate_symbols: []
|
74
|
+
subunit: ''
|
75
|
+
subunit_to_unit: 100
|
76
|
+
symbol_first: true
|
77
|
+
html_entity: ''
|
78
|
+
decimal_mark: "."
|
79
|
+
thousands_separator: ","
|
80
|
+
iso_numeric: ''
|
81
|
+
smallest_denomination: ''
|
82
|
+
gbx:
|
83
|
+
priority: 100
|
84
|
+
iso_code: GBX
|
85
|
+
name: British Penny
|
86
|
+
symbol: ''
|
87
|
+
disambiguate_symbol: GBX
|
88
|
+
alternate_symbols: []
|
89
|
+
subunit: ''
|
90
|
+
subunit_to_unit: 1
|
91
|
+
symbol_first: true
|
92
|
+
html_entity: ''
|
93
|
+
decimal_mark: "."
|
94
|
+
thousands_separator: ","
|
95
|
+
iso_numeric: ''
|
96
|
+
smallest_denomination: 1
|
data/dev.yml
CHANGED
data/lib/money.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require_relative 'money/money_parser'
|
2
3
|
require_relative 'money/helpers'
|
3
4
|
require_relative 'money/currency'
|
@@ -10,3 +11,5 @@ require_relative 'money/accounting_money_parser'
|
|
10
11
|
require_relative 'money/core_extensions'
|
11
12
|
require_relative 'money_accessor'
|
12
13
|
require_relative 'money_column' if defined?(ActiveRecord)
|
14
|
+
|
15
|
+
require_relative 'rubocop/cop/money' if defined?(RuboCop)
|
data/lib/money/allocator.rb
CHANGED
data/lib/money/currency.rb
CHANGED
@@ -1,25 +1,38 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'yaml'
|
2
3
|
|
3
4
|
class Money
|
4
5
|
class Currency
|
5
6
|
module Loader
|
6
|
-
|
7
|
+
class << self
|
8
|
+
def load_currencies
|
9
|
+
currency_data_path = File.expand_path("../../../../config", __FILE__)
|
7
10
|
|
8
|
-
|
11
|
+
currencies = {}
|
12
|
+
currencies.merge! YAML.load_file("#{currency_data_path}/currency_historic.yml")
|
13
|
+
currencies.merge! YAML.load_file("#{currency_data_path}/currency_non_iso.yml")
|
14
|
+
currencies.merge! YAML.load_file("#{currency_data_path}/currency_iso.yml")
|
15
|
+
deep_deduplicate!(currencies)
|
16
|
+
end
|
9
17
|
|
10
|
-
|
11
|
-
currencies = {}
|
12
|
-
currencies.merge! parse_currency_file("currency_historic.json")
|
13
|
-
currencies.merge! parse_currency_file("currency_non_iso.json")
|
14
|
-
currencies.merge! parse_currency_file("currency_iso.json")
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
+
private
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
def deep_deduplicate!(data)
|
21
|
+
case data
|
22
|
+
when Hash
|
23
|
+
return data if data.frozen?
|
24
|
+
data.transform_keys! { |k| deep_deduplicate!(k) }
|
25
|
+
data.transform_values! { |v| deep_deduplicate!(v) }
|
26
|
+
data.freeze
|
27
|
+
when Array
|
28
|
+
return data if data.frozen?
|
29
|
+
data.map! { |d| deep_deduplicate!(d) }.freeze
|
30
|
+
when String
|
31
|
+
-data
|
32
|
+
else
|
33
|
+
data.freeze
|
34
|
+
end
|
35
|
+
end
|
23
36
|
end
|
24
37
|
end
|
25
38
|
end
|
data/lib/money/deprecations.rb
CHANGED
data/lib/money/errors.rb
CHANGED
data/lib/money/helpers.rb
CHANGED
@@ -5,7 +5,6 @@ class Money
|
|
5
5
|
module Helpers
|
6
6
|
module_function
|
7
7
|
|
8
|
-
NUMERIC_REGEX = /\A\s*[\+\-]?(\d+|\d*\.\d+)\s*\z/
|
9
8
|
DECIMAL_ZERO = BigDecimal(0).freeze
|
10
9
|
MAX_DECIMAL = 21
|
11
10
|
|
@@ -25,7 +24,11 @@ class Money
|
|
25
24
|
when Rational
|
26
25
|
BigDecimal(num, MAX_DECIMAL)
|
27
26
|
when String
|
28
|
-
|
27
|
+
decimal = BigDecimal(num, exception: false)
|
28
|
+
return decimal if decimal
|
29
|
+
|
30
|
+
Money.deprecate("using Money.new('#{num}') is deprecated and will raise an ArgumentError in the next major release")
|
31
|
+
DECIMAL_ZERO
|
29
32
|
else
|
30
33
|
raise ArgumentError, "could not parse as decimal #{num.inspect}"
|
31
34
|
end
|
@@ -54,18 +57,5 @@ class Money
|
|
54
57
|
raise ArgumentError, "could not parse as currency #{currency.inspect}"
|
55
58
|
end
|
56
59
|
end
|
57
|
-
|
58
|
-
def string_to_decimal(num)
|
59
|
-
if num =~ NUMERIC_REGEX
|
60
|
-
return BigDecimal(num)
|
61
|
-
end
|
62
|
-
|
63
|
-
Money.deprecate("using Money.new('#{num}') is deprecated and will raise an ArgumentError in the next major release")
|
64
|
-
begin
|
65
|
-
BigDecimal(num)
|
66
|
-
rescue ArgumentError
|
67
|
-
DECIMAL_ZERO
|
68
|
-
end
|
69
|
-
end
|
70
60
|
end
|
71
61
|
end
|
data/lib/money/money.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'forwardable'
|
2
3
|
|
3
4
|
class Money
|
@@ -30,8 +31,8 @@ class Money
|
|
30
31
|
end
|
31
32
|
alias_method :empty, :zero
|
32
33
|
|
33
|
-
def parse(*args)
|
34
|
-
parser.parse(*args)
|
34
|
+
def parse(*args, **kwargs)
|
35
|
+
parser.parse(*args, **kwargs)
|
35
36
|
end
|
36
37
|
|
37
38
|
def from_cents(cents, currency = nil)
|
@@ -206,11 +207,22 @@ class Money
|
|
206
207
|
end
|
207
208
|
|
208
209
|
def to_s(style = nil)
|
209
|
-
case style
|
210
|
+
units = case style
|
210
211
|
when :legacy_dollars
|
211
|
-
|
212
|
+
2
|
212
213
|
when :amount, nil
|
213
|
-
|
214
|
+
currency.minor_units
|
215
|
+
else
|
216
|
+
raise ArgumentError, "Unexpected style: #{style}"
|
217
|
+
end
|
218
|
+
|
219
|
+
rounded_value = value.round(units)
|
220
|
+
if units == 0
|
221
|
+
sprintf("%d", rounded_value)
|
222
|
+
else
|
223
|
+
sign = rounded_value < 0 ? '-' : ''
|
224
|
+
rounded_value = rounded_value.abs
|
225
|
+
sprintf("%s%d.%0#{units}d", sign, rounded_value.truncate, rounded_value.frac * (10 ** units))
|
214
226
|
end
|
215
227
|
end
|
216
228
|
|
data/lib/money/null_currency.rb
CHANGED
data/lib/money/version.rb
CHANGED
data/lib/money_accessor.rb
CHANGED
data/lib/money_column.rb
CHANGED
@@ -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?
|
data/lib/money_column/railtie.rb
CHANGED
@@ -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
|
data/money.gemspec
CHANGED
@@ -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", "~>
|
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.
|
21
|
-
|
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) }
|