monetize 1.12.0 → 1.13.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/ruby.yml +2 -2
- data/LICENSE +1 -1
- data/README.md +18 -6
- data/lib/monetize/parser.rb +30 -6
- data/lib/monetize/version.rb +1 -1
- data/lib/monetize.rb +6 -0
- data/spec/monetize_spec.rb +48 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 07adb2e223118b56f5944a6b90b8c51901df761f6b5ecebea8fd8ee8dea3343e
|
4
|
+
data.tar.gz: a61b3fda9d0c22fefb028043db74625c91083787068b31ecf639a05286f92cff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d4774d81cc075b5c68849cd07c69f2311683f16adfbb00075d85e7530f4a1cb052a82a1b772b812b9b029fbe47b8b4400aabb0588ce27a35ef6e9d6340122cb
|
7
|
+
data.tar.gz: c5e7266b20bf556a2619974f8d97a690e6817eec1a56e9cd0497c6569bc36c681fc417c19900fa95c1ae7fcf7c10569867bec072d4a25e8c99d6f49c0b9901e1
|
data/.github/workflows/ruby.yml
CHANGED
@@ -19,10 +19,10 @@ jobs:
|
|
19
19
|
runs-on: ubuntu-latest
|
20
20
|
strategy:
|
21
21
|
matrix:
|
22
|
-
ruby-version: ['2.6', '2.7', '3.0']
|
22
|
+
ruby-version: ['2.6', '2.7', '3.0', '3.1', '3.2']
|
23
23
|
|
24
24
|
steps:
|
25
|
-
- uses: actions/checkout@
|
25
|
+
- uses: actions/checkout@v3
|
26
26
|
- name: Set up Ruby
|
27
27
|
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
28
28
|
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -10,13 +10,9 @@ A library for converting various objects into `Money` objects.
|
|
10
10
|
|
11
11
|
## Installation
|
12
12
|
|
13
|
-
|
13
|
+
Run:
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
And then execute:
|
18
|
-
|
19
|
-
$ bundle
|
15
|
+
bundle add monetize
|
20
16
|
|
21
17
|
Or install it yourself as:
|
22
18
|
|
@@ -53,6 +49,22 @@ Monetize.parse("£100") == Money.new(100_00, "GBP")
|
|
53
49
|
"€100".to_money == Money.new(100_00, "EUR")
|
54
50
|
```
|
55
51
|
|
52
|
+
Parsing can be improved where the input is not expected to contain fractonal subunits.
|
53
|
+
To do this, set `Monetize.expect_whole_subunits = true`
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
Monetize.parse('EUR 10,000') == Money.new(100_00, "EUR")
|
57
|
+
|
58
|
+
Monetize.expect_whole_subunits = true
|
59
|
+
Monetize.parse('EUR 10,000') == Money.new(10_000_00, "EUR")
|
60
|
+
```
|
61
|
+
|
62
|
+
Why does this work? If we expect fractional subunits then the parser will treat a single
|
63
|
+
delimiter as a decimal marker if it matches the currency's decimal marker. But often
|
64
|
+
this is not the case - a European site will show $10.000 because that's the local format.
|
65
|
+
As a human, if this was a stock ticker we might expect fractional cents. If it's a retail price we know it's actually an incorrect thousands separator.
|
66
|
+
|
67
|
+
|
56
68
|
Monetize can also parse a list of values, returning an array-like object ([Monetize::Collection](lib/collection.rb)):
|
57
69
|
|
58
70
|
```ruby
|
data/lib/monetize/parser.rb
CHANGED
@@ -8,6 +8,8 @@ module Monetize
|
|
8
8
|
'£' => 'GBP',
|
9
9
|
'₤' => 'GBP',
|
10
10
|
'R$' => 'BRL',
|
11
|
+
'RM' => 'MYR',
|
12
|
+
'Rp' => 'IDR',
|
11
13
|
'R' => 'ZAR',
|
12
14
|
'¥' => 'JPY',
|
13
15
|
'C$' => 'CAD',
|
@@ -23,6 +25,10 @@ module Monetize
|
|
23
25
|
'zł' => 'PLN',
|
24
26
|
'₸' => 'KZT',
|
25
27
|
"₩" => 'KRW',
|
28
|
+
'S$' => 'SGD',
|
29
|
+
'HK$'=> 'HKD',
|
30
|
+
'NT$'=> 'TWD',
|
31
|
+
'₱' => 'PHP',
|
26
32
|
}
|
27
33
|
|
28
34
|
MULTIPLIER_SUFFIXES = { 'K' => 3, 'M' => 6, 'B' => 9, 'T' => 12 }
|
@@ -70,6 +76,7 @@ module Monetize
|
|
70
76
|
def parse_currency
|
71
77
|
computed_currency = nil
|
72
78
|
computed_currency = input[/[A-Z]{2,3}/]
|
79
|
+
computed_currency = nil unless Monetize::Parser::CURRENCY_SYMBOLS.value?(computed_currency)
|
73
80
|
computed_currency ||= compute_currency if assume_from_symbol?
|
74
81
|
|
75
82
|
|
@@ -80,6 +87,10 @@ module Monetize
|
|
80
87
|
options.fetch(:assume_from_symbol) { Monetize.assume_from_symbol }
|
81
88
|
end
|
82
89
|
|
90
|
+
def expect_whole_subunits?
|
91
|
+
options.fetch(:expect_whole_subunits) { Monetize.expect_whole_subunits }
|
92
|
+
end
|
93
|
+
|
83
94
|
def apply_multiplier(multiplier_exp, amount)
|
84
95
|
amount * 10**multiplier_exp
|
85
96
|
end
|
@@ -109,13 +120,26 @@ module Monetize
|
|
109
120
|
end
|
110
121
|
end
|
111
122
|
|
123
|
+
def minor_has_correct_dp_for_currency_subunit?(minor, currency)
|
124
|
+
minor.length == currency.subunit_to_unit.to_s.length - 1
|
125
|
+
end
|
126
|
+
|
112
127
|
def extract_major_minor_with_single_delimiter(num, currency, delimiter)
|
113
|
-
if
|
114
|
-
split_major_minor(num, delimiter)
|
115
|
-
|
116
|
-
|
128
|
+
if expect_whole_subunits?
|
129
|
+
possible_major, possible_minor = split_major_minor(num, delimiter)
|
130
|
+
if minor_has_correct_dp_for_currency_subunit?(possible_minor, currency)
|
131
|
+
split_major_minor(num, delimiter)
|
132
|
+
else
|
133
|
+
extract_major_minor_with_tentative_delimiter(num, delimiter)
|
134
|
+
end
|
117
135
|
else
|
118
|
-
|
136
|
+
if delimiter == currency.decimal_mark
|
137
|
+
split_major_minor(num, delimiter)
|
138
|
+
elsif Monetize.enforce_currency_delimiters && delimiter == currency.thousands_separator
|
139
|
+
[num.gsub(delimiter, ''), 0]
|
140
|
+
else
|
141
|
+
extract_major_minor_with_tentative_delimiter(num, delimiter)
|
142
|
+
end
|
119
143
|
end
|
120
144
|
end
|
121
145
|
|
@@ -130,7 +154,7 @@ module Monetize
|
|
130
154
|
is_decimal_mark = possible_minor.length != 3 ||
|
131
155
|
possible_major.length > 3 ||
|
132
156
|
possible_major.to_i == 0 ||
|
133
|
-
delimiter == '.'
|
157
|
+
(!expect_whole_subunits? && delimiter == '.')
|
134
158
|
|
135
159
|
if is_decimal_mark
|
136
160
|
[possible_major, possible_minor]
|
data/lib/monetize/version.rb
CHANGED
data/lib/monetize.rb
CHANGED
@@ -20,6 +20,12 @@ module Monetize
|
|
20
20
|
# to true to enforce the delimiters set in the currency all the time.
|
21
21
|
attr_accessor :enforce_currency_delimiters
|
22
22
|
|
23
|
+
|
24
|
+
# Where this set to true, the behavior for parsing thousands separators is changed to
|
25
|
+
# expect that eg. €10.000 is EUR 10 000 and not EUR 10.000 - it's incredibly rare when parsing
|
26
|
+
# human text that we're dealing with fractions of cents.
|
27
|
+
attr_accessor :expect_whole_subunits
|
28
|
+
|
23
29
|
def parse(input, currency = Money.default_currency, options = {})
|
24
30
|
parse! input, currency, options
|
25
31
|
rescue Error
|
data/spec/monetize_spec.rb
CHANGED
@@ -172,8 +172,28 @@ describe Monetize do
|
|
172
172
|
expect('20.00 GBP'.to_money).to eq Money.new(20_00, 'GBP')
|
173
173
|
end
|
174
174
|
|
175
|
-
|
176
|
-
|
175
|
+
context 'with default currency' do
|
176
|
+
before do
|
177
|
+
Money.default_currency = Money::Currency.new('USD')
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'parses currency given using default currency' do
|
181
|
+
expect('20.00 OMG'.to_money).to eq Money.new(20_00, 'USD')
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
context 'without default currency' do
|
186
|
+
before do
|
187
|
+
Money.default_currency = nil
|
188
|
+
end
|
189
|
+
|
190
|
+
after do
|
191
|
+
Money.default_currency = Money::Currency.new('USD')
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'raises an error if currency code is invalid' do
|
195
|
+
expect { '20.00 OMG'.to_money }.to raise_error
|
196
|
+
end
|
177
197
|
end
|
178
198
|
end
|
179
199
|
end
|
@@ -344,6 +364,32 @@ describe Monetize do
|
|
344
364
|
expect('€0.5324'.to_money('EU4')).to eq Money.new(5324, 'EU4')
|
345
365
|
end
|
346
366
|
end
|
367
|
+
|
368
|
+
describe "expecting whole subunits" do
|
369
|
+
before(:all) do
|
370
|
+
Monetize.expect_whole_subunits = true
|
371
|
+
Monetize.assume_from_symbol = true
|
372
|
+
end
|
373
|
+
|
374
|
+
after(:all) do
|
375
|
+
Monetize.expect_whole_subunits = false
|
376
|
+
Monetize.assume_from_symbol = false
|
377
|
+
end
|
378
|
+
|
379
|
+
it "handles euros" do
|
380
|
+
expect(Monetize.parse('€10,000')).to eq Money.new(10_000_00, 'EUR')
|
381
|
+
expect(Monetize.parse('€10,00')).to eq Money.new(10_00, 'EUR')
|
382
|
+
expect(Monetize.parse('€10.00')).to eq Money.new(10_00, 'EUR')
|
383
|
+
expect(Monetize.parse('EUR 10,000.00')).to eq Money.new(10_000_00, 'EUR')
|
384
|
+
end
|
385
|
+
|
386
|
+
it "handles GBP" do
|
387
|
+
expect(Monetize.parse('£10,000')).to eq Money.new(10_000_00, 'GBP')
|
388
|
+
expect(Monetize.parse('£10.000')).to eq Money.new(10_000_00, 'GBP')
|
389
|
+
expect(Monetize.parse('£10,00')).to eq Money.new(10_00, 'GBP')
|
390
|
+
expect(Monetize.parse('£10.00')).to eq Money.new(10_00, 'GBP')
|
391
|
+
end
|
392
|
+
end
|
347
393
|
end
|
348
394
|
|
349
395
|
describe '.parse!' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: monetize
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shane Emmons
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2024-01-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: money
|
@@ -121,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
121
|
- !ruby/object:Gem::Version
|
122
122
|
version: '0'
|
123
123
|
requirements: []
|
124
|
-
rubygems_version: 3.
|
124
|
+
rubygems_version: 3.5.3
|
125
125
|
signing_key:
|
126
126
|
specification_version: 4
|
127
127
|
summary: A library for converting various objects into `Money` objects.
|