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.
@@ -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