monetize 1.4.0 → 1.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +10 -1
- data/CHANGELOG.md +76 -11
- data/Gemfile +11 -1
- data/README.md +16 -6
- data/lib/monetize.rb +34 -193
- data/lib/{collection.rb → monetize/collection.rb} +0 -1
- data/lib/monetize/core_extensions/hash.rb +2 -1
- data/lib/monetize/core_extensions/string.rb +1 -1
- data/lib/monetize/errors.rb +6 -0
- data/lib/monetize/parser.rb +178 -0
- data/lib/monetize/version.rb +1 -1
- data/monetize.gemspec +10 -4
- data/spec/core_extensions_spec.rb +17 -1
- data/spec/monetize_spec.rb +157 -94
- metadata +22 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c921047a6f291ae61ceb19db130de7b0288d8e2
|
4
|
+
data.tar.gz: f48eb20c8582b1453ef6114df30793f9367d934e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b4a49126c30cfd92968d6fed6cd43a806e5cda807f8dfd0c8956d434e0e3a3331191d9e228e5648c4d11157f01d3c3fcdb72f72f21e52f96002ab803b70265a
|
7
|
+
data.tar.gz: 571ec0ec170014d408f4ba0208a1b40f04cdf3436b2939e7d43b922cfe2ce3e981fb5a51a6dc79eab8d07ccad4ecfbc270548e15b4293428df87dbc0c912d277
|
data/.travis.yml
CHANGED
@@ -1,8 +1,17 @@
|
|
1
|
+
sudo: false
|
1
2
|
language: ruby
|
2
3
|
rvm:
|
3
4
|
- 1.9.3
|
4
5
|
- 2.0.0
|
5
|
-
- 2.1.
|
6
|
+
- 2.1.10
|
7
|
+
- 2.2.10
|
8
|
+
- 2.3.7
|
9
|
+
- 2.4.4
|
10
|
+
- 2.5.1
|
11
|
+
- 2.6.0
|
12
|
+
- jruby-9.0.5.0
|
13
|
+
before_install:
|
14
|
+
- gem install bundler --version '~> 1.17'
|
6
15
|
script: bundle exec rspec spec
|
7
16
|
notifications:
|
8
17
|
recipients:
|
data/CHANGELOG.md
CHANGED
@@ -1,21 +1,86 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
## 1.
|
4
|
-
-
|
5
|
-
- Add capability to parse currency amounts given with suffixes (K, M, B, and T)
|
3
|
+
## 1.9.1
|
4
|
+
- Ruby 2.6 support
|
6
5
|
|
7
|
-
## 1.
|
8
|
-
-
|
9
|
-
-
|
10
|
-
-
|
11
|
-
- Add Lira Sign (₤) as a symbol for GBP
|
6
|
+
## 1.9.0
|
7
|
+
- Relax Money gem dependency to ~> 6.12
|
8
|
+
- Refactor `Monetize::Parser`
|
9
|
+
- Ruby 2.5 support
|
12
10
|
|
13
|
-
## 1.
|
14
|
-
-
|
11
|
+
## 1.8.0
|
12
|
+
- Money version updated to 6.11.2
|
13
|
+
- Fix rounding problem in `.from_bigdecimal`
|
14
|
+
|
15
|
+
## 1.7.0
|
16
|
+
- Add South Korean Won currency
|
17
|
+
- Money version updated to 6.9
|
18
|
+
- Coveralls version update to 0.8.20
|
19
|
+
- Add South Korean Won currency
|
20
|
+
- Improve conversion to Money from Hash
|
21
|
+
|
22
|
+
## 1.6.0
|
23
|
+
- Ruby 2.4.0 support
|
24
|
+
- Money version updated to 6.8
|
15
25
|
|
16
|
-
##
|
26
|
+
## 1.5.0
|
27
|
+
- Fix issue where parsing a Money object resulted in a Money object with its currency set to `Money.default_currency`,
|
28
|
+
rather than the currency that it was sent in as.
|
29
|
+
- Add extra currencies:
|
30
|
+
- Azerbaijani manat
|
31
|
+
- Chinese yuan
|
32
|
+
- Czech koruna
|
33
|
+
- Hungarian forint
|
34
|
+
- Indian rupee
|
35
|
+
- Russian ruble
|
36
|
+
- Turkish Lira
|
37
|
+
- Ukrainian Hryvnia
|
38
|
+
- Swiss Frank
|
39
|
+
- Polish Zloty
|
40
|
+
- Kazakhstani Tenge
|
41
|
+
- Fix issue with losing precision on BigDecimal input
|
42
|
+
- Add Swedish krona
|
43
|
+
- Exclude ambiguous kr symbol from parsing
|
44
|
+
- Fix JPY parsing
|
45
|
+
- Subclass all errors to Monetize::Error
|
46
|
+
- Fix ruby 1.9.3 compatibility
|
47
|
+
- Suppress errors when using parse. Use `parse!` instead
|
48
|
+
- Strip currency symbol prefix when parsing input
|
49
|
+
|
50
|
+
## 1.4.0
|
17
51
|
- Fixed support for <code>Money.infinite_precision = true</code> in .to_money
|
18
52
|
- Add Rubocop config to project
|
19
53
|
- Reformat code to adapt to Rubocop guidelines
|
20
54
|
- Add config setting to always enforce currency delimiters
|
21
55
|
- Add rake console task
|
56
|
+
- Required Forwardable on Collection to resolve NameError [\#44](https://github.com/RubyMoney/monetize/issues/44)
|
57
|
+
- Add capability to parse currency amounts given with suffixes (K, M, B, and T)
|
58
|
+
|
59
|
+
## 1.3.1
|
60
|
+
- Updated Money version dependency to 6.6
|
61
|
+
|
62
|
+
## 1.3.0
|
63
|
+
- Add Lira Sign (₤) as a symbol for GBP
|
64
|
+
|
65
|
+
## 1.2.0
|
66
|
+
- Add support for parsing Yen symbol
|
67
|
+
- Add `Monetize.parse_collection` and `Monetize::Collection` class for parsing multiple values
|
68
|
+
- Add parsing of C$ for Canadian Dollar
|
69
|
+
- Add NilClass extension
|
70
|
+
- Add Hash extension
|
71
|
+
|
72
|
+
## 1.1.0
|
73
|
+
- Add :assume_from_symbol option to #parse
|
74
|
+
- Enable #parse to detect currency with signed amounts
|
75
|
+
- Updated Money version dependency to 6.5.0
|
76
|
+
|
77
|
+
## 1.0.0
|
78
|
+
- Updated Money version dependency to 6.4.0
|
79
|
+
|
80
|
+
## 0.4.1
|
81
|
+
- Updated Money version dependency to 6.2.1
|
82
|
+
|
83
|
+
## 0.4.0
|
84
|
+
- Added correct parsing of Brazilian Real $R symbol
|
85
|
+
- Add testing task for Brazilian Real parsing
|
86
|
+
- Updated Money version dependency to 6.2.0
|
data/Gemfile
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
|
-
gem 'coveralls', require: false
|
3
|
+
gem 'coveralls', '>= 0.8.20', require: false
|
4
|
+
|
5
|
+
# JSON and I18n gem no longer supports ruby < 2.0.0
|
6
|
+
if defined?(JRUBY_VERSION)
|
7
|
+
gem 'json'
|
8
|
+
elsif RUBY_VERSION =~ /^1/
|
9
|
+
gem 'json', '~> 1.8.3'
|
10
|
+
gem 'tins', '~> 1.6.0'
|
11
|
+
gem 'term-ansicolor', '~> 1.3.0'
|
12
|
+
gem 'i18n', '~> 0.9'
|
13
|
+
end
|
4
14
|
|
5
15
|
gemspec
|
data/README.md
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# Monetize
|
2
2
|
|
3
|
-
[![Gem Version](https://badge.fury.io/rb/monetize.
|
4
|
-
[![Build Status](https://travis-ci.org/RubyMoney/monetize.
|
5
|
-
[![Code Climate](https://codeclimate.com/github/RubyMoney/monetize.
|
6
|
-
[![Coverage Status](https://coveralls.io/repos/RubyMoney/monetize/badge.
|
7
|
-
[![Dependency Status](https://gemnasium.com/RubyMoney/monetize.
|
8
|
-
[![License](
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/monetize.svg)](http://badge.fury.io/rb/monetize)
|
4
|
+
[![Build Status](https://travis-ci.org/RubyMoney/monetize.svg?branch=master)](https://travis-ci.org/RubyMoney/monetize)
|
5
|
+
[![Code Climate](https://codeclimate.com/github/RubyMoney/monetize.svg)](https://codeclimate.com/github/RubyMoney/monetize)
|
6
|
+
[![Coverage Status](https://coveralls.io/repos/RubyMoney/monetize/badge.svg)](https://coveralls.io/r/RubyMoney/monetize)
|
7
|
+
[![Dependency Status](https://gemnasium.com/RubyMoney/monetize.svg)](https://gemnasium.com/RubyMoney/monetize)
|
8
|
+
[![License](https://img.shields.io/badge/license-MIT-green.svg)](http://opensource.org/licenses/MIT)
|
9
9
|
|
10
10
|
A library for converting various objects into `Money` objects.
|
11
11
|
|
@@ -33,6 +33,16 @@ Monetize.parse("GBP 100") == Money.new(100_00, "GBP")
|
|
33
33
|
"100".to_money == Money.new(100_00, "USD")
|
34
34
|
```
|
35
35
|
|
36
|
+
`parse` will return `nil` if it is unable to parse the input. Use `parse!` instead if you want a `Monetize::Error` (or one of the subclasses) to be raised instead:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
>> Monetize.parse('OMG 100')
|
40
|
+
=> nil
|
41
|
+
|
42
|
+
>> Monetize.parse!('OMG 100')
|
43
|
+
Monetize::ParseError: Unknown currency 'omg'
|
44
|
+
```
|
45
|
+
|
36
46
|
Optionally, enable the ability to assume the currency from a passed symbol. Otherwise, currency symbols will be ignored, and USD used as the default currency:
|
37
47
|
|
38
48
|
```ruby
|
data/lib/monetize.rb
CHANGED
@@ -2,30 +2,12 @@
|
|
2
2
|
|
3
3
|
require 'money'
|
4
4
|
require 'monetize/core_extensions'
|
5
|
+
require 'monetize/errors'
|
5
6
|
require 'monetize/version'
|
6
|
-
require '
|
7
|
+
require 'monetize/parser'
|
8
|
+
require 'monetize/collection'
|
7
9
|
|
8
10
|
module Monetize
|
9
|
-
CURRENCY_SYMBOLS = {
|
10
|
-
'$' => 'USD',
|
11
|
-
'€' => 'EUR',
|
12
|
-
'£' => 'GBP',
|
13
|
-
'₤' => 'GBP',
|
14
|
-
'R$' => 'BRL',
|
15
|
-
'R' => 'ZAR',
|
16
|
-
'¥' => 'JPY',
|
17
|
-
'C$' => 'CAD'
|
18
|
-
}
|
19
|
-
|
20
|
-
MULTIPLIER_SUFFIXES = {
|
21
|
-
'K' => 3,
|
22
|
-
'M' => 6,
|
23
|
-
'B' => 9,
|
24
|
-
'T' => 12
|
25
|
-
}
|
26
|
-
MULTIPLIER_SUFFIXES.default = 0
|
27
|
-
MULTIPLIER_REGEXP = Regexp.new(format('^(.*?\d)(%s)\b([^\d]*)$', MULTIPLIER_SUFFIXES.keys.join('|')), 'i')
|
28
|
-
|
29
11
|
# Class methods
|
30
12
|
class << self
|
31
13
|
# @attr_accessor [true, false] assume_from_symbol Use this to enable the
|
@@ -37,195 +19,54 @@ module Monetize
|
|
37
19
|
# though, it will try to determine the correct separator by itself. Set this
|
38
20
|
# to true to enforce the delimiters set in the currency all the time.
|
39
21
|
attr_accessor :enforce_currency_delimiters
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.parse(input, currency = Money.default_currency, options = {})
|
43
|
-
input = input.to_s.strip
|
44
22
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
50
|
-
|
51
|
-
currency = computed_currency || currency || Money.default_currency
|
52
|
-
currency = Money::Currency.wrap(currency)
|
53
|
-
|
54
|
-
fractional = extract_cents(input, currency)
|
55
|
-
Money.new(fractional, currency)
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.parse_collection(input, currency = Money.default_currency, options = {})
|
59
|
-
Collection.parse(input, currency, options)
|
60
|
-
end
|
61
|
-
|
62
|
-
def self.from_string(value, currency = Money.default_currency)
|
63
|
-
value = BigDecimal.new(value.to_s)
|
64
|
-
from_bigdecimal(value, currency)
|
65
|
-
end
|
66
|
-
|
67
|
-
def self.from_fixnum(value, currency = Money.default_currency)
|
68
|
-
currency = Money::Currency.wrap(currency)
|
69
|
-
value *= currency.subunit_to_unit
|
70
|
-
Money.new(value, currency)
|
71
|
-
end
|
72
|
-
|
73
|
-
def self.from_float(value, currency = Money.default_currency)
|
74
|
-
value = BigDecimal.new(value.to_s)
|
75
|
-
from_bigdecimal(value, currency)
|
76
|
-
end
|
77
|
-
|
78
|
-
def self.from_bigdecimal(value, currency = Money.default_currency)
|
79
|
-
currency = Money::Currency.wrap(currency)
|
80
|
-
value *= currency.subunit_to_unit
|
81
|
-
value = value.round unless Money.infinite_precision
|
82
|
-
Money.new(value, currency)
|
83
|
-
end
|
84
|
-
|
85
|
-
def self.from_numeric(value, currency = Money.default_currency)
|
86
|
-
case value
|
87
|
-
when Fixnum
|
88
|
-
from_fixnum(value, currency)
|
89
|
-
when Numeric
|
90
|
-
value = BigDecimal.new(value.to_s)
|
91
|
-
from_bigdecimal(value, currency)
|
92
|
-
else
|
93
|
-
fail ArgumentError, "'value' should be a type of Numeric"
|
23
|
+
def parse(input, currency = Money.default_currency, options = {})
|
24
|
+
parse! input, currency, options
|
25
|
+
rescue Error
|
26
|
+
nil
|
94
27
|
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def self.extract_cents(input, currency = Money.default_currency)
|
98
|
-
multiplier_exp, input = extract_multiplier(input)
|
99
|
-
|
100
|
-
num = input.gsub(/[^\d.,'-]/, '')
|
101
|
-
|
102
|
-
negative, num = extract_sign(num)
|
103
|
-
|
104
|
-
num.chop! if num.match(/[\.|,]$/)
|
105
|
-
|
106
|
-
major, minor = extract_major_minor(num, currency)
|
107
|
-
|
108
|
-
cents = major.to_i * currency.subunit_to_unit
|
109
28
|
|
110
|
-
|
29
|
+
def parse!(input, currency = Money.default_currency, options = {})
|
30
|
+
return input if input.is_a?(Money)
|
31
|
+
return from_numeric(input, currency) if input.is_a?(Numeric)
|
111
32
|
|
112
|
-
|
33
|
+
parser = Monetize::Parser.new(input, currency, options)
|
34
|
+
currency_from_input = Money::Currency.wrap(parser.parse_currency)
|
113
35
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
private
|
118
|
-
|
119
|
-
def self.apply_multiplier(multiplier_exp, cents, minor)
|
120
|
-
cents *= (10**multiplier_exp)
|
121
|
-
minor = minor.to_s + ('0' * multiplier_exp)
|
122
|
-
shift = minor[0...multiplier_exp].to_i * 100
|
123
|
-
cents += shift
|
124
|
-
minor = (minor[multiplier_exp..-1] || '')
|
125
|
-
[cents, minor]
|
126
|
-
end
|
127
|
-
|
128
|
-
def self.apply_sign(negative, cents)
|
129
|
-
negative ? cents * -1 : cents
|
130
|
-
end
|
131
|
-
|
132
|
-
def self.contains_currency_symbol?(amount)
|
133
|
-
amount =~ currency_symbol_regex
|
134
|
-
end
|
135
|
-
|
136
|
-
def self.compute_currency(amount)
|
137
|
-
if contains_currency_symbol?(amount)
|
138
|
-
matches = amount.match(currency_symbol_regex)
|
139
|
-
CURRENCY_SYMBOLS[matches[:symbol]]
|
140
|
-
else
|
141
|
-
amount[/[A-Z]{2,3}/]
|
36
|
+
Money.new(parser.parse_cents(currency_from_input), currency_from_input)
|
37
|
+
rescue Money::Currency::UnknownCurrency => e
|
38
|
+
fail ParseError, e.message
|
142
39
|
end
|
143
|
-
end
|
144
|
-
|
145
|
-
def self.extract_major_minor(num, currency)
|
146
|
-
used_delimiters = num.scan(/[^\d]/).uniq
|
147
40
|
|
148
|
-
|
149
|
-
|
150
|
-
[num, 0]
|
151
|
-
when 2
|
152
|
-
thousands_separator, decimal_mark = used_delimiters
|
153
|
-
split_major_minor(num.gsub(thousands_separator, ''), decimal_mark)
|
154
|
-
when 1
|
155
|
-
extract_major_minor_with_single_delimiter(num, currency, used_delimiters.first)
|
156
|
-
else
|
157
|
-
fail ArgumentError, 'Invalid currency amount'
|
41
|
+
def parse_collection(input, currency = Money.default_currency, options = {})
|
42
|
+
Collection.parse(input, currency, options)
|
158
43
|
end
|
159
|
-
end
|
160
44
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
elsif enforce_currency_delimiters and delimiter == currency.thousands_separator
|
165
|
-
[num.gsub(delimiter, ''), 0]
|
166
|
-
else
|
167
|
-
extract_major_minor_with_tentative_delimiter(num, delimiter)
|
45
|
+
def from_string(value, currency = Money.default_currency)
|
46
|
+
value = BigDecimal(value.to_s)
|
47
|
+
Money.from_amount(value, currency)
|
168
48
|
end
|
169
|
-
end
|
170
|
-
|
171
|
-
def self.extract_major_minor_with_tentative_delimiter(num, delimiter)
|
172
|
-
if num.scan(delimiter).length > 1
|
173
|
-
# Multiple matches; treat as thousands separator
|
174
|
-
[num.gsub(delimiter, ''), '00']
|
175
|
-
else
|
176
|
-
possible_major, possible_minor = split_major_minor(num, delimiter)
|
177
49
|
|
178
|
-
|
179
|
-
|
180
|
-
[possible_major, possible_minor]
|
181
|
-
else
|
182
|
-
["#{possible_major}#{possible_minor}", '00']
|
183
|
-
end
|
50
|
+
def from_fixnum(value, currency = Money.default_currency)
|
51
|
+
Money.from_amount(value, currency)
|
184
52
|
end
|
185
|
-
|
53
|
+
alias_method :from_integer, :from_fixnum
|
186
54
|
|
187
|
-
|
188
|
-
|
189
|
-
multiplier_suffix = matches[2].upcase
|
190
|
-
[MULTIPLIER_SUFFIXES[multiplier_suffix], "#{$1}#{$3}"]
|
191
|
-
else
|
192
|
-
[0, input]
|
55
|
+
def from_float(value, currency = Money.default_currency)
|
56
|
+
Money.from_amount(value, currency)
|
193
57
|
end
|
194
|
-
end
|
195
|
-
|
196
|
-
def self.extract_sign(input)
|
197
|
-
result = (input =~ /^-+(.*)$/ or input =~ /^(.*)-+$/) ? [true, $1] : [false, input]
|
198
|
-
fail ArgumentError, 'Invalid currency amount (hyphen)' if result[1].include?('-')
|
199
|
-
result
|
200
|
-
end
|
201
58
|
|
202
|
-
|
203
|
-
|
204
|
-
end
|
205
|
-
|
206
|
-
def self.set_minor_precision(minor, currency)
|
207
|
-
if Money.infinite_precision
|
208
|
-
(BigDecimal.new(minor) / (10**minor.size)) * currency.subunit_to_unit
|
209
|
-
elsif minor.size < currency.decimal_places
|
210
|
-
(minor + ('0' * currency.decimal_places))[0, currency.decimal_places].to_i
|
211
|
-
elsif minor.size > currency.decimal_places
|
212
|
-
if minor[currency.decimal_places, 1].to_i >= 5
|
213
|
-
minor[0, currency.decimal_places].to_i + 1
|
214
|
-
else
|
215
|
-
minor[0, currency.decimal_places].to_i
|
216
|
-
end
|
217
|
-
else
|
218
|
-
minor.to_i
|
59
|
+
def from_bigdecimal(value, currency = Money.default_currency)
|
60
|
+
Money.from_amount(value, currency)
|
219
61
|
end
|
220
|
-
end
|
221
62
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
end
|
63
|
+
def from_numeric(value, currency = Money.default_currency)
|
64
|
+
fail ArgumentError, "'value' should be a type of Numeric" unless value.is_a?(Numeric)
|
65
|
+
Money.from_amount(value, currency)
|
66
|
+
end
|
227
67
|
|
228
|
-
|
229
|
-
|
68
|
+
def extract_cents(input, currency = Money.default_currency)
|
69
|
+
Monetize::Parser.new(input).parse_cents(currency)
|
70
|
+
end
|
230
71
|
end
|
231
72
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
class Hash
|
4
4
|
def to_money(currency = nil)
|
5
|
-
|
5
|
+
hash_currency = self[:currency].is_a?(Hash) ? self[:currency][:iso_code] : self[:currency]
|
6
|
+
Money.new(self[:cents] || self[:fractional], hash_currency || currency || Money.default_currency)
|
6
7
|
end
|
7
8
|
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Monetize
|
4
|
+
class Parser
|
5
|
+
CURRENCY_SYMBOLS = {
|
6
|
+
'$' => 'USD',
|
7
|
+
'€' => 'EUR',
|
8
|
+
'£' => 'GBP',
|
9
|
+
'₤' => 'GBP',
|
10
|
+
'R$' => 'BRL',
|
11
|
+
'R' => 'ZAR',
|
12
|
+
'¥' => 'JPY',
|
13
|
+
'C$' => 'CAD',
|
14
|
+
'₼' => 'AZN',
|
15
|
+
'元' => 'CNY',
|
16
|
+
'Kč' => 'CZK',
|
17
|
+
'Ft' => 'HUF',
|
18
|
+
'₹' => 'INR',
|
19
|
+
'₽' => 'RUB',
|
20
|
+
'₺' => 'TRY',
|
21
|
+
'₴' => 'UAH',
|
22
|
+
'Fr' => 'CHF',
|
23
|
+
'zł' => 'PLN',
|
24
|
+
'₸' => 'KZT',
|
25
|
+
"₩" => 'KRW',
|
26
|
+
}
|
27
|
+
|
28
|
+
MULTIPLIER_SUFFIXES = { 'K' => 3, 'M' => 6, 'B' => 9, 'T' => 12 }
|
29
|
+
MULTIPLIER_SUFFIXES.default = 0
|
30
|
+
MULTIPLIER_REGEXP = Regexp.new(format('^(.*?\d)(%s)\b([^\d]*)$', MULTIPLIER_SUFFIXES.keys.join('|')), 'i')
|
31
|
+
|
32
|
+
def initialize(input, fallback_currency = Money.default_currency, options = {})
|
33
|
+
@input = input.to_s.strip
|
34
|
+
@fallback_currency = fallback_currency
|
35
|
+
@options = options
|
36
|
+
end
|
37
|
+
|
38
|
+
def parse_cents(currency)
|
39
|
+
multiplier_exp, input = extract_multiplier
|
40
|
+
|
41
|
+
num = input.gsub(/(?:^#{currency.symbol}|[^\d.,'-]+)/, '')
|
42
|
+
|
43
|
+
negative, num = extract_sign(num)
|
44
|
+
|
45
|
+
num.chop! if num =~ /[\.|,]$/
|
46
|
+
|
47
|
+
major, minor = extract_major_minor(num, currency)
|
48
|
+
|
49
|
+
major, minor = apply_multiplier(multiplier_exp, major.to_i, minor)
|
50
|
+
|
51
|
+
cents = major.to_i * currency.subunit_to_unit
|
52
|
+
|
53
|
+
cents += set_minor_precision(minor, currency)
|
54
|
+
|
55
|
+
apply_sign(negative, cents)
|
56
|
+
end
|
57
|
+
|
58
|
+
def parse_currency
|
59
|
+
computed_currency = nil
|
60
|
+
computed_currency = compute_currency if assume_from_symbol?
|
61
|
+
computed_currency ||= input[/[A-Z]{2,3}/]
|
62
|
+
|
63
|
+
computed_currency || fallback_currency || Money.default_currency
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
attr_reader :input, :fallback_currency, :options
|
69
|
+
|
70
|
+
def assume_from_symbol?
|
71
|
+
options.fetch(:assume_from_symbol) { Monetize.assume_from_symbol }
|
72
|
+
end
|
73
|
+
|
74
|
+
def apply_multiplier(multiplier_exp, major, minor)
|
75
|
+
major *= 10**multiplier_exp
|
76
|
+
minor = minor.to_s + ('0' * multiplier_exp)
|
77
|
+
shift = minor[0...multiplier_exp].to_i
|
78
|
+
major += shift
|
79
|
+
minor = (minor[multiplier_exp..-1] || '')
|
80
|
+
[major, minor]
|
81
|
+
end
|
82
|
+
|
83
|
+
def apply_sign(negative, cents)
|
84
|
+
negative ? cents * -1 : cents
|
85
|
+
end
|
86
|
+
|
87
|
+
def compute_currency
|
88
|
+
matches = input.match(currency_symbol_regex)
|
89
|
+
CURRENCY_SYMBOLS[matches[:symbol]] if matches
|
90
|
+
end
|
91
|
+
|
92
|
+
def extract_major_minor(num, currency)
|
93
|
+
used_delimiters = num.scan(/[^\d]/).uniq
|
94
|
+
|
95
|
+
case used_delimiters.length
|
96
|
+
when 0
|
97
|
+
[num, 0]
|
98
|
+
when 2
|
99
|
+
thousands_separator, decimal_mark = used_delimiters
|
100
|
+
split_major_minor(num.gsub(thousands_separator, ''), decimal_mark)
|
101
|
+
when 1
|
102
|
+
extract_major_minor_with_single_delimiter(num, currency, used_delimiters.first)
|
103
|
+
else
|
104
|
+
fail ParseError, 'Invalid amount'
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def extract_major_minor_with_single_delimiter(num, currency, delimiter)
|
109
|
+
if delimiter == currency.decimal_mark
|
110
|
+
split_major_minor(num, delimiter)
|
111
|
+
elsif Monetize.enforce_currency_delimiters && delimiter == currency.thousands_separator
|
112
|
+
[num.gsub(delimiter, ''), 0]
|
113
|
+
else
|
114
|
+
extract_major_minor_with_tentative_delimiter(num, delimiter)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def extract_major_minor_with_tentative_delimiter(num, delimiter)
|
119
|
+
if num.scan(delimiter).length > 1
|
120
|
+
# Multiple matches; treat as thousands separator
|
121
|
+
[num.gsub(delimiter, ''), '00']
|
122
|
+
else
|
123
|
+
possible_major, possible_minor = split_major_minor(num, delimiter)
|
124
|
+
|
125
|
+
if possible_minor.length != 3 || possible_major.length > 3 || delimiter == '.'
|
126
|
+
# Doesn't look like thousands separator
|
127
|
+
[possible_major, possible_minor]
|
128
|
+
else
|
129
|
+
["#{possible_major}#{possible_minor}", '00']
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def extract_multiplier
|
135
|
+
if (matches = MULTIPLIER_REGEXP.match(input))
|
136
|
+
multiplier_suffix = matches[2].upcase
|
137
|
+
[MULTIPLIER_SUFFIXES[multiplier_suffix], "#{$1}#{$3}"]
|
138
|
+
else
|
139
|
+
[0, input]
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def extract_sign(input)
|
144
|
+
result = (input =~ /^-+(.*)$/ || input =~ /^(.*)-+$/) ? [true, $1] : [false, input]
|
145
|
+
fail ParseError, 'Invalid amount (hyphen)' if result[1].include?('-')
|
146
|
+
result
|
147
|
+
end
|
148
|
+
|
149
|
+
def regex_safe_symbols
|
150
|
+
CURRENCY_SYMBOLS.keys.map { |key| Regexp.escape(key) }.join('|')
|
151
|
+
end
|
152
|
+
|
153
|
+
def set_minor_precision(minor, currency)
|
154
|
+
if Money.infinite_precision
|
155
|
+
(BigDecimal(minor) / (10**minor.size)) * currency.subunit_to_unit
|
156
|
+
elsif minor.size < currency.decimal_places
|
157
|
+
(minor + ('0' * currency.decimal_places))[0, currency.decimal_places].to_i
|
158
|
+
elsif minor.size > currency.decimal_places
|
159
|
+
if minor[currency.decimal_places, 1].to_i >= 5
|
160
|
+
minor[0, currency.decimal_places].to_i + 1
|
161
|
+
else
|
162
|
+
minor[0, currency.decimal_places].to_i
|
163
|
+
end
|
164
|
+
else
|
165
|
+
minor.to_i
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def split_major_minor(num, delimiter)
|
170
|
+
major, minor = num.split(delimiter)
|
171
|
+
[major, minor || '00']
|
172
|
+
end
|
173
|
+
|
174
|
+
def currency_symbol_regex
|
175
|
+
/\A[\+|\-]?(?<symbol>#{regex_safe_symbols})/
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
data/lib/monetize/version.rb
CHANGED
data/monetize.gemspec
CHANGED
@@ -19,9 +19,15 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
20
|
spec.require_paths = ['lib']
|
21
21
|
|
22
|
-
spec.add_dependency 'money', '~> 6.
|
22
|
+
spec.add_dependency 'money', '~> 6.12'
|
23
23
|
|
24
|
-
spec.add_development_dependency 'bundler'
|
25
|
-
spec.add_development_dependency 'rake'
|
26
|
-
spec.add_development_dependency 'rspec', '~> 3.0
|
24
|
+
spec.add_development_dependency 'bundler'
|
25
|
+
spec.add_development_dependency 'rake', '~> 10.2'
|
26
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
27
|
+
|
28
|
+
if spec.respond_to?(:metadata)
|
29
|
+
spec.metadata['changelog_uri'] = 'https://github.com/RubyMoney/monetize/blob/master/CHANGELOG.md'
|
30
|
+
spec.metadata['source_code_uri'] = 'https://github.com/RubyMoney/monetize/'
|
31
|
+
spec.metadata['bug_tracker_uri'] = 'https://github.com/RubyMoney/monetize/issues'
|
32
|
+
end
|
27
33
|
end
|
@@ -31,7 +31,7 @@ describe Monetize, 'core extensions' do
|
|
31
31
|
expect(money.cents).to eq 100_37
|
32
32
|
expect(money.currency).to eq Money.default_currency
|
33
33
|
|
34
|
-
money = BigDecimal
|
34
|
+
money = BigDecimal('1234').to_money
|
35
35
|
expect(money.cents).to eq 1_234_00
|
36
36
|
expect(money.currency).to eq Money.default_currency
|
37
37
|
end
|
@@ -182,6 +182,14 @@ describe Monetize, 'core extensions' do
|
|
182
182
|
end
|
183
183
|
end
|
184
184
|
|
185
|
+
context 'when currency argument is a hash' do
|
186
|
+
subject(:hash) { {cents: 100, currency: {iso_code: 'EUR'}} }
|
187
|
+
|
188
|
+
it 'converts Hash to Money using iso_code from currency hash' do
|
189
|
+
expect(hash.to_money).to eq(Money.new(100, 'EUR'))
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
185
193
|
context 'when no currency is passed' do
|
186
194
|
subject(:hash) { {cents: 123} }
|
187
195
|
|
@@ -191,6 +199,14 @@ describe Monetize, 'core extensions' do
|
|
191
199
|
expect(hash.to_money('USD')).to eq(Money.new(123, 'USD'))
|
192
200
|
end
|
193
201
|
end
|
202
|
+
|
203
|
+
context "when key name is 'fractional'" do
|
204
|
+
subject(:hash) { {fractional: 100} }
|
205
|
+
|
206
|
+
it 'converts Hash to Money, interpreting fractional as cents' do
|
207
|
+
expect(hash.to_money).to eq(Money.new(100, 'USD'))
|
208
|
+
end
|
209
|
+
end
|
194
210
|
end
|
195
211
|
end
|
196
212
|
|
data/spec/monetize_spec.rb
CHANGED
@@ -56,76 +56,69 @@ describe Monetize do
|
|
56
56
|
Monetize.assume_from_symbol = false
|
57
57
|
end
|
58
58
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
59
|
+
Monetize::Parser::CURRENCY_SYMBOLS.each_pair do |symbol, iso_code|
|
60
|
+
context iso_code do
|
61
|
+
let(:currency) { Money::Currency.find(iso_code) }
|
62
|
+
let(:amount) { 5_95 }
|
63
|
+
let(:amount_in_units) { amount.to_f / currency.subunit_to_unit }
|
64
|
+
|
65
|
+
it 'ensures correct amount calculations for test' do
|
66
|
+
expect(amount_in_units * currency.subunit_to_unit).to eq(amount)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "parses formatted inputs with #{iso_code} passed as a symbol" do
|
70
|
+
expect(Monetize.parse("#{symbol}#{amount_in_units}")).to eq Money.new(amount, iso_code)
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'prefix' do
|
74
|
+
it 'parses formatted inputs with plus sign and currency as a symbol' do
|
75
|
+
expect(Monetize.parse("+#{symbol}#{amount_in_units}")).to eq Money.new(amount, iso_code)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'parses formatted inputs with minus sign and currency as a symbol' do
|
79
|
+
expect(Monetize.parse("-#{symbol}#{amount_in_units}")).to eq Money.new(-amount, iso_code)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'postfix' do
|
84
|
+
it 'parses formatted inputs with currency symbol and postfix minus sign' do
|
85
|
+
expect(Monetize.parse("#{symbol}#{amount_in_units}-")).to eq Money.new(-amount, iso_code)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'parses formatted inputs with currency symbol and postfix plus sign' do
|
89
|
+
expect(Monetize.parse("#{symbol}#{amount_in_units}+")).to eq Money.new(amount, iso_code)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'amount suffixes' do
|
94
|
+
it 'parses formatted inputs with amounts given with suffixes' do
|
95
|
+
expect(Monetize.parse("#{symbol}1.26K")).to eq Money.new(1_260 * currency.subunit_to_unit, iso_code)
|
96
|
+
expect(Monetize.parse("#{symbol}126.36M")).to eq Money.new(126_360_000 * currency.subunit_to_unit, iso_code)
|
97
|
+
expect(Monetize.parse("#{symbol}.45B")).to eq Money.new(450_000_000 * currency.subunit_to_unit, iso_code)
|
98
|
+
expect(Monetize.parse("-#{symbol}2.45B")).to eq Money.new(-2_450_000_000 * currency.subunit_to_unit, iso_code)
|
99
|
+
expect(Monetize.parse("#{symbol}1.65T")).to eq Money.new(1_650_000_000_000 * currency.subunit_to_unit, iso_code)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'parses formatted inputs with symbol and surrounding spaces' do
|
104
|
+
expect(Monetize.parse(" #{symbol}#{amount_in_units} ")).to eq Money.new(amount, iso_code)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'parses formatted inputs without currency detection when overridden' do
|
108
|
+
expect(Monetize.parse("#{symbol}5.95", nil, assume_from_symbol: false)).to eq Money.new(amount, 'USD')
|
109
|
+
end
|
110
|
+
end
|
89
111
|
end
|
90
112
|
|
91
113
|
it 'should assume default currency if not a recognised symbol' do
|
92
114
|
expect(Monetize.parse('L9.99')).to eq Money.new(999, 'USD')
|
93
115
|
end
|
94
116
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
expect(Monetize.parse('-€9.99')).to eq Money.new(-999, 'EUR')
|
101
|
-
expect(Monetize.parse('-£9.99')).to eq Money.new(-999, 'GBP')
|
102
|
-
expect(Monetize.parse('-R$R9.99')).to eq Money.new(-999, 'BRL')
|
103
|
-
expect(Monetize.parse('-¥999')).to eq Money.new(-999, 'JPY')
|
104
|
-
expect(Monetize.parse('-C$9.99')).to eq Money.new(-999, 'CAD')
|
105
|
-
end
|
106
|
-
|
107
|
-
it 'parses formatted inputs with plus and GBP passed as symbol' do
|
108
|
-
expect(Monetize.parse('+€9.99')).to eq Money.new(999, 'EUR')
|
109
|
-
expect(Monetize.parse('+£9.99')).to eq Money.new(999, 'GBP')
|
110
|
-
expect(Monetize.parse('+R$R9.99')).to eq Money.new(999, 'BRL')
|
111
|
-
expect(Monetize.parse('+¥999')).to eq Money.new(999, 'JPY')
|
112
|
-
expect(Monetize.parse('+C$9.99')).to eq Money.new(999, 'CAD')
|
113
|
-
end
|
114
|
-
|
115
|
-
it 'parses formatted inputs with currency symbol and postfix minus sign' do
|
116
|
-
expect(Monetize.parse('€9.99-')).to eq Money.new(-999, 'EUR')
|
117
|
-
end
|
118
|
-
|
119
|
-
it 'parses formatted inputs with currency symbol and postfix plus sign' do
|
120
|
-
expect(Monetize.parse('€9.99+')).to eq Money.new(999, 'EUR')
|
121
|
-
end
|
122
|
-
|
123
|
-
it 'parses formatted inputs with amounts given with suffixes' do
|
124
|
-
expect(Monetize.parse('$1.26K')).to eq Money.new(1_260_00, 'USD')
|
125
|
-
expect(Monetize.parse('$126.36M')).to eq Money.new(126_360_000_00, 'USD')
|
126
|
-
expect(Monetize.parse('€.45B')).to eq Money.new(450_000_000_00, 'EUR')
|
127
|
-
expect(Monetize.parse('-$2.45B')).to eq Money.new(-2_450_000_000_00, 'USD')
|
128
|
-
expect(Monetize.parse('€1.65T')).to eq Money.new(1_650_000_000_000_00, 'EUR')
|
117
|
+
context 'negatives' do
|
118
|
+
it 'ignores the ambiguous kr symbol' do
|
119
|
+
# Could mean either of DKK, EEK, ISK, NOK, SEK
|
120
|
+
expect(Monetize.parse('kr9.99')).to eq Money.new(999, 'USD')
|
121
|
+
end
|
129
122
|
end
|
130
123
|
end
|
131
124
|
|
@@ -158,6 +151,18 @@ describe Monetize do
|
|
158
151
|
it 'should opt out by default' do
|
159
152
|
expect(Monetize.assume_from_symbol).to be_falsy
|
160
153
|
end
|
154
|
+
|
155
|
+
context 'ISO code' do
|
156
|
+
it 'parses currency given as ISO code' do
|
157
|
+
expect('20.00 USD'.to_money).to eq Money.new(20_00, 'USD')
|
158
|
+
expect('20.00 EUR'.to_money).to eq Money.new(20_00, 'EUR')
|
159
|
+
expect('20.00 GBP'.to_money).to eq Money.new(20_00, 'GBP')
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'raises an error if currency code is invalid' do
|
163
|
+
expect { '20.00 OMG'.to_money }.to raise_error Monetize::ParseError
|
164
|
+
end
|
165
|
+
end
|
161
166
|
end
|
162
167
|
|
163
168
|
it 'parses USD-formatted inputs under $10' do
|
@@ -177,10 +182,16 @@ describe Monetize do
|
|
177
182
|
expect(Monetize.parse('1,111,234,567.89')).to eq Money.new(1_111_234_567_89, 'USD')
|
178
183
|
end
|
179
184
|
|
180
|
-
it '
|
181
|
-
expect
|
182
|
-
expect
|
183
|
-
expect
|
185
|
+
it 'parses DKK-formatted inputs' do
|
186
|
+
expect(Monetize.parse('kr.123,45', 'DKK')).to eq Money.new(123_45, 'DKK')
|
187
|
+
expect(Monetize.parse('kr.123.45', 'DKK')).to eq Money.new(123_45, 'DKK')
|
188
|
+
expect(Monetize.parse('kr.45k', 'DKK')).to eq Money.new(45_000_00, 'DKK')
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'returns nil if input is a price range' do
|
192
|
+
expect(Monetize.parse('$5.95-10.95')).to be_nil
|
193
|
+
expect(Monetize.parse('$5.95 - 10.95')).to be_nil
|
194
|
+
expect(Monetize.parse('$5.95 - $10.95')).to be_nil
|
184
195
|
end
|
185
196
|
|
186
197
|
it 'does not return a price for completely invalid input' do
|
@@ -197,8 +208,16 @@ describe Monetize do
|
|
197
208
|
expect(Monetize.parse('$5.95-')).to eq five_ninety_five
|
198
209
|
end
|
199
210
|
|
200
|
-
it '
|
201
|
-
expect
|
211
|
+
it 'returns nil when unable to detect polarity' do
|
212
|
+
expect(Monetize.parse('-$5.95-')).to be_nil
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'returns nil when more than 2 digit separators are used' do
|
216
|
+
expect(Monetize.parse("123.34,56'89 EUR")).to be_nil
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'parses correctly strings with repeated digit separator' do
|
220
|
+
expect(Monetize.parse('19.12.89', 'EUR')).to eq Money.new(191_289_00, 'EUR')
|
202
221
|
end
|
203
222
|
|
204
223
|
it 'parses correctly strings with exactly 3 decimal digits' do
|
@@ -210,6 +229,32 @@ describe Monetize do
|
|
210
229
|
Monetize.enforce_currency_delimiters = false
|
211
230
|
end
|
212
231
|
|
232
|
+
context 'Money object attempting to be parsed' do
|
233
|
+
let(:money) { Money.new(595, 'GBP') }
|
234
|
+
|
235
|
+
it 'returns the original Money object' do
|
236
|
+
expect(Monetize.parse(money)).to eq money
|
237
|
+
expect(Monetize.parse(money).currency).to eq 'GBP'
|
238
|
+
expect(Monetize.parse(money).cents).to eq 595
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
context 'parsing an instance of Numeric class' do
|
243
|
+
let(:integer) { 10 }
|
244
|
+
let(:float) { 10.0 }
|
245
|
+
let(:big_decimal) { BigDecimal('10') }
|
246
|
+
|
247
|
+
[:integer, :float, :big_decimal].each do |type|
|
248
|
+
it "returns a new Money object based on the #{type} input" do
|
249
|
+
money = Monetize.parse(send(type), 'USD')
|
250
|
+
|
251
|
+
expect(money).to be_instance_of(Money)
|
252
|
+
expect(money.currency).to eq('USD')
|
253
|
+
expect(money.cents).to eq(10_00)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
213
258
|
context 'custom currencies with 4 decimal places' do
|
214
259
|
before :each do
|
215
260
|
Money::Currency.register(JSON.parse(bar, symbolize_names: true))
|
@@ -265,6 +310,18 @@ describe Monetize do
|
|
265
310
|
end
|
266
311
|
end
|
267
312
|
|
313
|
+
describe '.parse!' do
|
314
|
+
it 'does not return a price if there is a price range' do
|
315
|
+
expect { Monetize.parse!('$5.95-10.95') }.to raise_error Monetize::ParseError
|
316
|
+
expect { Monetize.parse!('$5.95 - 10.95') }.to raise_error Monetize::ParseError
|
317
|
+
expect { Monetize.parse!('$5.95 - $10.95') }.to raise_error Monetize::ParseError
|
318
|
+
end
|
319
|
+
|
320
|
+
it 'raises ArgumentError when unable to detect polarity' do
|
321
|
+
expect { Monetize.parse!('-$5.95-') }.to raise_error Monetize::ParseError
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
268
325
|
describe '.parse_collection' do
|
269
326
|
it 'parses into a Money::Collection' do
|
270
327
|
expect(Monetize.parse_collection('$7')).to be_a Monetize::Collection
|
@@ -287,6 +344,10 @@ describe Monetize do
|
|
287
344
|
expect(collection.first).to eq Monetize.parse('$4')
|
288
345
|
expect(collection.last).to eq Monetize.parse('$10')
|
289
346
|
end
|
347
|
+
|
348
|
+
it 'raises an error if argument is invalid' do
|
349
|
+
expect { Monetize.parse_collection(nil) }.to raise_error Monetize::ArgumentError
|
350
|
+
end
|
290
351
|
end
|
291
352
|
|
292
353
|
describe '.from_string' do
|
@@ -337,6 +398,10 @@ describe Monetize do
|
|
337
398
|
m = Monetize.from_fixnum(1, 'EUR')
|
338
399
|
expect(m.currency).to eq Money::Currency.wrap('EUR')
|
339
400
|
end
|
401
|
+
|
402
|
+
it 'is aliased as from_integer' do
|
403
|
+
expect(Monetize.from_integer(1)).to eq(Monetize.from_fixnum(1))
|
404
|
+
end
|
340
405
|
end
|
341
406
|
|
342
407
|
describe '.from_float' do
|
@@ -366,25 +431,31 @@ describe Monetize do
|
|
366
431
|
|
367
432
|
describe '.from_bigdecimal' do
|
368
433
|
it 'converts given amount to cents' do
|
369
|
-
expect(Monetize.from_bigdecimal(BigDecimal
|
370
|
-
expect(Monetize.from_bigdecimal(BigDecimal
|
371
|
-
expect(Monetize.from_bigdecimal(BigDecimal
|
434
|
+
expect(Monetize.from_bigdecimal(BigDecimal('1'))).to eq Money.new(1_00)
|
435
|
+
expect(Monetize.from_bigdecimal(BigDecimal('1'))).to eq Money.new(1_00, 'USD')
|
436
|
+
expect(Monetize.from_bigdecimal(BigDecimal('1'), 'EUR')).to eq Money.new(1_00, 'EUR')
|
372
437
|
end
|
373
438
|
|
374
439
|
it 'respects :subunit_to_unit currency property' do
|
375
|
-
expect(Monetize.from_bigdecimal(BigDecimal
|
376
|
-
expect(Monetize.from_bigdecimal(BigDecimal
|
377
|
-
expect(Monetize.from_bigdecimal(BigDecimal
|
440
|
+
expect(Monetize.from_bigdecimal(BigDecimal('1'), 'USD')).to eq Money.new(1_00, 'USD')
|
441
|
+
expect(Monetize.from_bigdecimal(BigDecimal('1'), 'TND')).to eq Money.new(1_000, 'TND')
|
442
|
+
expect(Monetize.from_bigdecimal(BigDecimal('1'), 'JPY')).to eq Money.new(1, 'JPY')
|
443
|
+
end
|
444
|
+
|
445
|
+
it 'respects rounding mode when rounding amount to the nearest cent' do
|
446
|
+
amount = BigDecimal('1.005')
|
447
|
+
|
448
|
+
expect(Monetize.from_bigdecimal(amount, 'USD')).to eq Money.from_amount(amount, 'USD')
|
378
449
|
end
|
379
450
|
|
380
451
|
it 'accepts a currency options' do
|
381
|
-
m = Monetize.from_bigdecimal(BigDecimal
|
452
|
+
m = Monetize.from_bigdecimal(BigDecimal('1'))
|
382
453
|
expect(m.currency).to eq Money.default_currency
|
383
454
|
|
384
|
-
m = Monetize.from_bigdecimal(BigDecimal
|
455
|
+
m = Monetize.from_bigdecimal(BigDecimal('1'), Money::Currency.wrap('EUR'))
|
385
456
|
expect(m.currency).to eq Money::Currency.wrap('EUR')
|
386
457
|
|
387
|
-
m = Monetize.from_bigdecimal(BigDecimal
|
458
|
+
m = Monetize.from_bigdecimal(BigDecimal('1'), 'EUR')
|
388
459
|
expect(m.currency).to eq Money::Currency.wrap('EUR')
|
389
460
|
end
|
390
461
|
|
@@ -398,11 +469,11 @@ describe Monetize do
|
|
398
469
|
end
|
399
470
|
|
400
471
|
it 'keeps precision' do
|
401
|
-
expect(Monetize.from_bigdecimal(BigDecimal
|
402
|
-
expect(Monetize.from_bigdecimal(BigDecimal
|
403
|
-
expect(Monetize.from_bigdecimal(BigDecimal
|
404
|
-
expect(Monetize.from_bigdecimal(BigDecimal
|
405
|
-
expect(Monetize.from_bigdecimal(BigDecimal
|
472
|
+
expect(Monetize.from_bigdecimal(BigDecimal('1'))).to eq Money.new(100)
|
473
|
+
expect(Monetize.from_bigdecimal(BigDecimal('1.23456'))).to eq Money.new(123.456)
|
474
|
+
expect(Monetize.from_bigdecimal(BigDecimal('-1.23456'))).to eq Money.new(-123.456)
|
475
|
+
expect(Monetize.from_bigdecimal(BigDecimal('1.23456'))).to eq Money.new(123.456, 'USD')
|
476
|
+
expect(Monetize.from_bigdecimal(BigDecimal('1.23456'), 'EUR')).to eq Money.new(123.456, 'EUR')
|
406
477
|
|
407
478
|
expect('1'.to_money).to eq Money.new(100)
|
408
479
|
expect('1.23456'.to_money).to eq Money.new(123.456)
|
@@ -417,19 +488,11 @@ describe Monetize do
|
|
417
488
|
it 'converts given amount to cents' do
|
418
489
|
expect(Monetize.from_numeric(1)).to eq Money.new(1_00)
|
419
490
|
expect(Monetize.from_numeric(1.0)).to eq Money.new(1_00)
|
420
|
-
expect(Monetize.from_numeric(BigDecimal
|
491
|
+
expect(Monetize.from_numeric(BigDecimal('1'))).to eq Money.new(1_00)
|
421
492
|
end
|
422
493
|
|
423
494
|
it 'raises ArgumentError with unsupported argument' do
|
424
|
-
expect { Monetize.from_numeric('100') }.to raise_error(ArgumentError)
|
425
|
-
end
|
426
|
-
|
427
|
-
it 'optimizes workload' do
|
428
|
-
expect(Monetize).to receive(:from_fixnum).with(1, 'USD').and_return(Money.new(1_00, 'USD'))
|
429
|
-
expect(Monetize.from_numeric(1, 'USD')).to eq Money.new(1_00, 'USD')
|
430
|
-
expect(Monetize).to receive(:from_bigdecimal).with(BigDecimal.new('1.0'), 'USD').
|
431
|
-
and_return(Money.new(1_00, 'USD'))
|
432
|
-
expect(Monetize.from_numeric(1.0, 'USD')).to eq Money.new(1_00, 'USD')
|
495
|
+
expect { Monetize.from_numeric('100') }.to raise_error(Monetize::ArgumentError)
|
433
496
|
end
|
434
497
|
|
435
498
|
it 'respects :subunit_to_unit currency property' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: monetize
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.9.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shane Emmons
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-02-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: money
|
@@ -16,56 +16,56 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '6.
|
19
|
+
version: '6.12'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '6.
|
26
|
+
version: '6.12'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '10.2'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '10.2'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rspec
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 3.0
|
61
|
+
version: '3.0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 3.0
|
68
|
+
version: '3.0'
|
69
69
|
description: A library for converting various objects into `Money` objects.
|
70
70
|
email:
|
71
71
|
- shane@emmons.io
|
@@ -83,14 +83,16 @@ files:
|
|
83
83
|
- LICENSE.txt
|
84
84
|
- README.md
|
85
85
|
- Rakefile
|
86
|
-
- lib/collection.rb
|
87
86
|
- lib/monetize.rb
|
87
|
+
- lib/monetize/collection.rb
|
88
88
|
- lib/monetize/core_extensions.rb
|
89
89
|
- lib/monetize/core_extensions/hash.rb
|
90
90
|
- lib/monetize/core_extensions/nil_class.rb
|
91
91
|
- lib/monetize/core_extensions/numeric.rb
|
92
92
|
- lib/monetize/core_extensions/string.rb
|
93
93
|
- lib/monetize/core_extensions/symbol.rb
|
94
|
+
- lib/monetize/errors.rb
|
95
|
+
- lib/monetize/parser.rb
|
94
96
|
- lib/monetize/version.rb
|
95
97
|
- monetize.gemspec
|
96
98
|
- spec/core_extensions_spec.rb
|
@@ -99,7 +101,10 @@ files:
|
|
99
101
|
homepage: https://github.com/RubyMoney/monetize
|
100
102
|
licenses:
|
101
103
|
- MIT
|
102
|
-
metadata:
|
104
|
+
metadata:
|
105
|
+
changelog_uri: https://github.com/RubyMoney/monetize/blob/master/CHANGELOG.md
|
106
|
+
source_code_uri: https://github.com/RubyMoney/monetize/
|
107
|
+
bug_tracker_uri: https://github.com/RubyMoney/monetize/issues
|
103
108
|
post_install_message:
|
104
109
|
rdoc_options: []
|
105
110
|
require_paths:
|
@@ -116,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
116
121
|
version: '0'
|
117
122
|
requirements: []
|
118
123
|
rubyforge_project:
|
119
|
-
rubygems_version: 2.
|
124
|
+
rubygems_version: 2.6.8
|
120
125
|
signing_key:
|
121
126
|
specification_version: 4
|
122
127
|
summary: A library for converting various objects into `Money` objects.
|
@@ -124,4 +129,3 @@ test_files:
|
|
124
129
|
- spec/core_extensions_spec.rb
|
125
130
|
- spec/monetize_spec.rb
|
126
131
|
- spec/spec_helper.rb
|
127
|
-
has_rdoc:
|