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.
- checksums.yaml +4 -4
- data/README.md +8 -2
- data/UPGRADING.md +59 -0
- data/config/currency_historic.yml +14 -0
- data/config/currency_iso.yml +22 -4
- data/lib/money/allocator.rb +3 -1
- data/lib/money/config.rb +25 -0
- data/lib/money/core_extensions.rb +1 -1
- data/lib/money/helpers.rb +8 -4
- data/lib/money/money.rb +48 -23
- data/lib/money/parser/accounting.rb +11 -0
- data/lib/money/parser/fuzzy.rb +174 -0
- data/lib/money/parser/locale_aware.rb +52 -0
- data/lib/money/parser/simple.rb +30 -0
- data/lib/money/rails/job_argument_serializer.rb +22 -0
- data/lib/money/railtie.rb +19 -0
- data/lib/money/version.rb +1 -1
- data/lib/money.rb +7 -2
- data/lib/money_column/active_record_hooks.rb +12 -7
- data/spec/config_spec.rb +48 -0
- data/spec/helpers_spec.rb +11 -5
- data/spec/money_column_spec.rb +54 -33
- data/spec/money_spec.rb +129 -62
- data/spec/{accounting_money_parser_spec.rb → parser/accounting_spec.rb} +9 -15
- data/spec/{money_parser_spec.rb → parser/fuzzy_spec.rb} +25 -13
- data/spec/parser/locale_aware_spec.rb +208 -0
- data/spec/parser/simple_spec.rb +62 -0
- data/spec/rails/job_argument_serializer_spec.rb +20 -0
- data/spec/rails_spec_helper.rb +11 -0
- data/spec/spec_helper.rb +15 -0
- metadata +27 -11
- data/lib/money/accounting_money_parser.rb +0 -8
- data/lib/money/money_parser.rb +0 -156
data/lib/money/money_parser.rb
DELETED
@@ -1,156 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Parse an amount from a string
|
4
|
-
class MoneyParser
|
5
|
-
class MoneyFormatError < ArgumentError; end
|
6
|
-
|
7
|
-
MARKS = %w[. , · ’ ˙ '] + [' ']
|
8
|
-
|
9
|
-
ESCAPED_MARKS = Regexp.escape(MARKS.join)
|
10
|
-
ESCAPED_NON_SPACE_MARKS = Regexp.escape((MARKS - [' ']).join)
|
11
|
-
ESCAPED_NON_DOT_MARKS = Regexp.escape((MARKS - ['.']).join)
|
12
|
-
ESCAPED_NON_COMMA_MARKS = Regexp.escape((MARKS - [',']).join)
|
13
|
-
|
14
|
-
NUMERIC_REGEX = /(
|
15
|
-
[\+\-]?
|
16
|
-
[\d#{ESCAPED_NON_SPACE_MARKS}][\d#{ESCAPED_MARKS}]*
|
17
|
-
)/ix
|
18
|
-
|
19
|
-
# 1,234,567.89
|
20
|
-
DOT_DECIMAL_REGEX = /\A
|
21
|
-
[\+\-]?
|
22
|
-
(?:
|
23
|
-
(?:\d+)
|
24
|
-
(?:[#{ESCAPED_NON_DOT_MARKS}]\d{3})+
|
25
|
-
(?:\.\d{2,})?
|
26
|
-
)
|
27
|
-
\z/ix
|
28
|
-
|
29
|
-
# 1.234.567,89
|
30
|
-
COMMA_DECIMAL_REGEX = /\A
|
31
|
-
[\+\-]?
|
32
|
-
(?:
|
33
|
-
(?:\d+)
|
34
|
-
(?:[#{ESCAPED_NON_COMMA_MARKS}]\d{3})+
|
35
|
-
(?:\,\d{2,})?
|
36
|
-
)
|
37
|
-
\z/ix
|
38
|
-
|
39
|
-
# 12,34,567.89
|
40
|
-
INDIAN_NUMERIC_REGEX = /\A
|
41
|
-
[\+\-]?
|
42
|
-
(?:
|
43
|
-
(?:\d+)
|
44
|
-
(?:\,\d{2})+
|
45
|
-
(?:\,\d{3})
|
46
|
-
(?:\.\d{2})?
|
47
|
-
)
|
48
|
-
\z/ix
|
49
|
-
|
50
|
-
# 1,1123,4567.89
|
51
|
-
CHINESE_NUMERIC_REGEX = /\A
|
52
|
-
[\+\-]?
|
53
|
-
(?:
|
54
|
-
(?:\d+)
|
55
|
-
(?:\,\d{4})+
|
56
|
-
(?:\.\d{2})?
|
57
|
-
)
|
58
|
-
\z/ix
|
59
|
-
|
60
|
-
def self.parse(input, currency = nil, **options)
|
61
|
-
new.parse(input, currency, **options)
|
62
|
-
end
|
63
|
-
|
64
|
-
def parse(input, currency = nil, strict: false)
|
65
|
-
currency = Money::Helpers.value_to_currency(currency)
|
66
|
-
amount = extract_amount_from_string(input, currency, strict)
|
67
|
-
Money.new(amount, currency)
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
71
|
-
|
72
|
-
def extract_amount_from_string(input, currency, strict)
|
73
|
-
unless input.is_a?(String)
|
74
|
-
return input
|
75
|
-
end
|
76
|
-
|
77
|
-
if input.strip.empty?
|
78
|
-
return '0'
|
79
|
-
end
|
80
|
-
|
81
|
-
number = input.scan(NUMERIC_REGEX).flatten.first
|
82
|
-
number = number.to_s.strip
|
83
|
-
|
84
|
-
if number.empty?
|
85
|
-
raise MoneyFormatError, "invalid money string: #{input}" if strict
|
86
|
-
Money.deprecate("invalid money strings will raise in the next major release \"#{input}\"")
|
87
|
-
return '0'
|
88
|
-
end
|
89
|
-
|
90
|
-
marks = number.scan(/[#{ESCAPED_MARKS}]/).flatten
|
91
|
-
if marks.empty?
|
92
|
-
return number
|
93
|
-
end
|
94
|
-
|
95
|
-
if marks.size == 1
|
96
|
-
return normalize_number(number, marks, currency)
|
97
|
-
end
|
98
|
-
|
99
|
-
# remove end of string mark
|
100
|
-
number.sub!(/[#{ESCAPED_MARKS}]\z/, '')
|
101
|
-
|
102
|
-
if amount = number[DOT_DECIMAL_REGEX] || number[INDIAN_NUMERIC_REGEX] || number[CHINESE_NUMERIC_REGEX]
|
103
|
-
return amount.tr(ESCAPED_NON_DOT_MARKS, '')
|
104
|
-
end
|
105
|
-
|
106
|
-
if amount = number[COMMA_DECIMAL_REGEX]
|
107
|
-
return amount.tr(ESCAPED_NON_COMMA_MARKS, '').sub(',', '.')
|
108
|
-
end
|
109
|
-
|
110
|
-
raise MoneyFormatError, "invalid money string: #{input}" if strict
|
111
|
-
Money.deprecate("invalid money strings will raise in the next major release \"#{input}\"")
|
112
|
-
|
113
|
-
normalize_number(number, marks, currency)
|
114
|
-
end
|
115
|
-
|
116
|
-
def normalize_number(number, marks, currency)
|
117
|
-
digits = number.rpartition(marks.last)
|
118
|
-
digits.first.tr!(ESCAPED_MARKS, '')
|
119
|
-
|
120
|
-
if last_digits_decimals?(digits, marks, currency)
|
121
|
-
"#{digits.first}.#{digits.last}"
|
122
|
-
else
|
123
|
-
"#{digits.first}#{digits.last}"
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
def last_digits_decimals?(digits, marks, currency)
|
128
|
-
# Thousands marks are always different from decimal marks
|
129
|
-
# Example: 1,234,456
|
130
|
-
*other_marks, last_mark = marks
|
131
|
-
other_marks.uniq!
|
132
|
-
if other_marks.size == 1
|
133
|
-
return other_marks.first != last_mark
|
134
|
-
end
|
135
|
-
|
136
|
-
# Thousands always have more than 2 digits
|
137
|
-
# Example: 1,23 must be 1 dollar and 23 cents
|
138
|
-
if digits.last.size < 3
|
139
|
-
return !digits.last.empty?
|
140
|
-
end
|
141
|
-
|
142
|
-
# 0 before the final mark indicates last digits are decimals
|
143
|
-
# Example: 0,23
|
144
|
-
if digits.first.to_i.zero?
|
145
|
-
return true
|
146
|
-
end
|
147
|
-
|
148
|
-
# legacy support for 1.000 USD
|
149
|
-
if digits.last.size == 3 && digits.first.size <= 3 && currency.minor_units < 3
|
150
|
-
return false
|
151
|
-
end
|
152
|
-
|
153
|
-
# The last mark matches the one used by the provided currency to delimiter decimals
|
154
|
-
currency.decimal_mark == last_mark
|
155
|
-
end
|
156
|
-
end
|