shopify-money 0.16.0 → 1.0.2.pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -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