monetize 1.4.0 → 1.9.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 7f96f9f99c2fc04ab625a2977f370eff77d33696
4
- data.tar.gz: 75817ce67a91ae35019f6ef3a3b290b937b64749
2
+ SHA256:
3
+ metadata.gz: 6268692fea7908fbc268790bf98cca9795df28eed380b07d2683eed6f5dad4d1
4
+ data.tar.gz: 8d795add425b915dc88ecf910505af69b7c1f340ae412083e4c230f0622c2e27
5
5
  SHA512:
6
- metadata.gz: 657c4f4be74370f9a8b2b1f4fcb91e60a013e9d2e01f39f95258a48c47710c5418767770af32ca61c19d52b0a94ccaa875fd3a4b7d8f21023ff7f4b036700c90
7
- data.tar.gz: 4cb6265937f209b0797cc4c0d2e78b4fa27a9f27f9f045cfac8d00812dcb2ccb86072672897b7fb36f7337dab52cbb62c3e58739b9cdcdc9ec32b73393bedd9a
6
+ metadata.gz: e4291ebf0a43a4bea5a2973186b1dca2d9d9fa08729acb956073efb2628d6898620f5eb1110ade3bba5dbac313894babd4ab59c0d1db92b8cb8e041974a0d402
7
+ data.tar.gz: 06d080183a460c5777b9f7443655bcb00d214ee18a6294f0838a3ac4bfec95715ab1ad5704001d286a6bc1ed0966a4a031942bd946ef9d249372ea527a120785
@@ -1,8 +1,20 @@
1
- language: ruby
1
+ sudo: false
2
+ language:
3
+ - ruby
4
+ - java
2
5
  rvm:
3
6
  - 1.9.3
4
7
  - 2.0.0
5
- - 2.1.2
8
+ - 2.1.10
9
+ - 2.2.10
10
+ - 2.3.8
11
+ - 2.4.6
12
+ - 2.5.5
13
+ - 2.6.3
14
+ - jruby-9.0.5.0
15
+ jdk: openjdk8
16
+ before_install:
17
+ - gem install bundler --version '~> 1.17'
6
18
  script: bundle exec rspec spec
7
19
  notifications:
8
20
  recipients:
@@ -1,21 +1,96 @@
1
1
  # Changelog
2
2
 
3
- ## 1.4.0
4
- - Required Forwardable on Collection to resolve NameError [\#44](https://github.com/RubyMoney/monetize/issues/44)
5
- - Add capability to parse currency amounts given with suffixes (K, M, B, and T)
3
+ ## 1.9.4
4
+ - Fix symbol parsing that are surrounded by other characters
6
5
 
7
- ## 1.3.0
8
- - Add NilClass extension
9
- - Added correct parsing of Brazilian Real $R symbol
10
- - Add testing task for Brazilian Real parsing
11
- - Add Lira Sign (₤) as a symbol for GBP
6
+ ## 1.9.3
7
+ - Fix input parsing when currency symbol after the amount
12
8
 
13
- ## 1.3.1
14
- - Updated Money version dependency to 6.6
9
+ ## 1.9.2
10
+ - Respect Money.rounding_mode when parsing strings
11
+ - Deprecate Monetize.extract_cents
12
+
13
+ ## 1.9.1
14
+ - Ruby 2.6 support
15
+
16
+ ## 1.9.0
17
+ - Relax Money gem dependency to ~> 6.12
18
+ - Refactor `Monetize::Parser`
19
+ - Ruby 2.5 support
20
+
21
+ ## 1.8.0
22
+ - Money version updated to 6.11.2
23
+ - Fix rounding problem in `.from_bigdecimal`
15
24
 
16
- ## master
25
+ ## 1.7.0
26
+ - Add South Korean Won currency
27
+ - Money version updated to 6.9
28
+ - Coveralls version update to 0.8.20
29
+ - Add South Korean Won currency
30
+ - Improve conversion to Money from Hash
31
+
32
+ ## 1.6.0
33
+ - Ruby 2.4.0 support
34
+ - Money version updated to 6.8
35
+
36
+ ## 1.5.0
37
+ - Fix issue where parsing a Money object resulted in a Money object with its currency set to `Money.default_currency`,
38
+ rather than the currency that it was sent in as.
39
+ - Add extra currencies:
40
+ - Azerbaijani manat
41
+ - Chinese yuan
42
+ - Czech koruna
43
+ - Hungarian forint
44
+ - Indian rupee
45
+ - Russian ruble
46
+ - Turkish Lira
47
+ - Ukrainian Hryvnia
48
+ - Swiss Frank
49
+ - Polish Zloty
50
+ - Kazakhstani Tenge
51
+ - Fix issue with losing precision on BigDecimal input
52
+ - Add Swedish krona
53
+ - Exclude ambiguous kr symbol from parsing
54
+ - Fix JPY parsing
55
+ - Subclass all errors to Monetize::Error
56
+ - Fix ruby 1.9.3 compatibility
57
+ - Suppress errors when using parse. Use `parse!` instead
58
+ - Strip currency symbol prefix when parsing input
59
+
60
+ ## 1.4.0
17
61
  - Fixed support for <code>Money.infinite_precision = true</code> in .to_money
18
62
  - Add Rubocop config to project
19
63
  - Reformat code to adapt to Rubocop guidelines
20
64
  - Add config setting to always enforce currency delimiters
21
65
  - Add rake console task
66
+ - Required Forwardable on Collection to resolve NameError [\#44](https://github.com/RubyMoney/monetize/issues/44)
67
+ - Add capability to parse currency amounts given with suffixes (K, M, B, and T)
68
+
69
+ ## 1.3.1
70
+ - Updated Money version dependency to 6.6
71
+
72
+ ## 1.3.0
73
+ - Add Lira Sign (₤) as a symbol for GBP
74
+
75
+ ## 1.2.0
76
+ - Add support for parsing Yen symbol
77
+ - Add `Monetize.parse_collection` and `Monetize::Collection` class for parsing multiple values
78
+ - Add parsing of C$ for Canadian Dollar
79
+ - Add NilClass extension
80
+ - Add Hash extension
81
+
82
+ ## 1.1.0
83
+ - Add :assume_from_symbol option to #parse
84
+ - Enable #parse to detect currency with signed amounts
85
+ - Updated Money version dependency to 6.5.0
86
+
87
+ ## 1.0.0
88
+ - Updated Money version dependency to 6.4.0
89
+
90
+ ## 0.4.1
91
+ - Updated Money version dependency to 6.2.1
92
+
93
+ ## 0.4.0
94
+ - Added correct parsing of Brazilian Real $R symbol
95
+ - Add testing task for Brazilian Real parsing
96
+ - 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.png)](http://badge.fury.io/rb/monetize)
4
- [![Build Status](https://travis-ci.org/RubyMoney/monetize.png?branch=master)](https://travis-ci.org/RubyMoney/monetize)
5
- [![Code Climate](https://codeclimate.com/github/RubyMoney/monetize.png)](https://codeclimate.com/github/RubyMoney/monetize)
6
- [![Coverage Status](https://coveralls.io/repos/RubyMoney/monetize/badge.png)](https://coveralls.io/r/RubyMoney/monetize)
7
- [![Dependency Status](https://gemnasium.com/RubyMoney/monetize.png)](https://gemnasium.com/RubyMoney/monetize)
8
- [![License](http://img.shields.io/license/MIT.png?color=green)](http://opensource.org/licenses/MIT)
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
@@ -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 'collection'
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,57 @@ 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
-
45
- computed_currency = if options.fetch(:assume_from_symbol) { assume_from_symbol }
46
- compute_currency(input)
47
- else
48
- input[/[A-Z]{2,3}/]
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
22
 
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
28
 
108
- cents = major.to_i * currency.subunit_to_unit
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)
109
32
 
110
- cents, minor = apply_multiplier(multiplier_exp, cents, minor)
33
+ parser = Monetize::Parser.new(input, currency, options)
34
+ amount, currency = parser.parse
111
35
 
112
- cents += set_minor_precision(minor, currency)
113
-
114
- apply_sign(negative, cents)
115
- end
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.from_amount(amount, currency)
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
- case used_delimiters.length
149
- when 0
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
- def self.extract_major_minor_with_single_delimiter(num, currency, delimiter)
162
- if delimiter == currency.decimal_mark
163
- split_major_minor(num, delimiter)
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
- if possible_minor.length != 3 or possible_major.length > 3 or delimiter == '.'
179
- # Doesn't look like thousands separator
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
- end
53
+ alias_method :from_integer, :from_fixnum
186
54
 
187
- def self.extract_multiplier(input)
188
- if (matches = MULTIPLIER_REGEXP.match(input))
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
- def self.regex_safe_symbols
203
- CURRENCY_SYMBOLS.keys.map { |key| Regexp.escape(key) }.join('|')
204
- end
59
+ def from_bigdecimal(value, currency = Money.default_currency)
60
+ Money.from_amount(value, currency)
61
+ end
205
62
 
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
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)
219
66
  end
220
- end
221
67
 
222
- def self.split_major_minor(num, delimiter)
223
- major, minor = num.split(delimiter)
224
- minor = '00' unless minor
225
- [major, minor]
226
- end
68
+ def extract_cents(input, currency = Money.default_currency)
69
+ warn '[DEPRECATION] Monetize.extract_cents is deprecated. Use Monetize.parse().cents'
227
70
 
228
- def self.currency_symbol_regex
229
- /\A[\+|\-]?(?<symbol>#{regex_safe_symbols})/
71
+ money = parse(input, currency)
72
+ money.cents if money
73
+ end
230
74
  end
231
75
  end
@@ -1,6 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'monetize'
4
3
  require 'forwardable'
5
4
 
6
5
  module Monetize
@@ -2,6 +2,7 @@
2
2
 
3
3
  class Hash
4
4
  def to_money(currency = nil)
5
- Money.new(self[:cents], self[:currency] || currency || Money.default_currency)
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
@@ -2,7 +2,7 @@
2
2
 
3
3
  class String
4
4
  def to_money(currency = nil)
5
- Monetize.parse(self, currency)
5
+ Monetize.parse!(self, currency)
6
6
  end
7
7
 
8
8
  def to_currency
@@ -0,0 +1,6 @@
1
+ module Monetize
2
+ class Error < StandardError; end
3
+
4
+ class ParseError < Error; end
5
+ class ArgumentError < Error; end
6
+ end
@@ -0,0 +1,159 @@
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
+ DEFAULT_DECIMAL_MARK = '.'.freeze
33
+
34
+ def initialize(input, fallback_currency = Money.default_currency, options = {})
35
+ @input = input.to_s.strip
36
+ @fallback_currency = fallback_currency
37
+ @options = options
38
+ end
39
+
40
+ def parse
41
+ currency = Money::Currency.wrap(parse_currency)
42
+
43
+ multiplier_exp, input = extract_multiplier
44
+
45
+ num = input.gsub(/(?:^#{currency.symbol}|[^\d.,'-]+)/, '')
46
+
47
+ negative, num = extract_sign(num)
48
+
49
+ num.chop! if num =~ /[\.|,]$/
50
+
51
+ major, minor = extract_major_minor(num, currency)
52
+
53
+ amount = BigDecimal([major, minor].join(DEFAULT_DECIMAL_MARK))
54
+ amount = apply_multiplier(multiplier_exp, amount)
55
+ amount = apply_sign(negative, amount)
56
+
57
+ [amount, currency]
58
+ end
59
+
60
+ private
61
+
62
+ attr_reader :input, :fallback_currency, :options
63
+
64
+ def parse_currency
65
+ computed_currency = nil
66
+ computed_currency = compute_currency if assume_from_symbol?
67
+ computed_currency ||= input[/[A-Z]{2,3}/]
68
+
69
+ computed_currency || fallback_currency || Money.default_currency
70
+ end
71
+
72
+ def assume_from_symbol?
73
+ options.fetch(:assume_from_symbol) { Monetize.assume_from_symbol }
74
+ end
75
+
76
+ def apply_multiplier(multiplier_exp, amount)
77
+ amount * 10**multiplier_exp
78
+ end
79
+
80
+ def apply_sign(negative, amount)
81
+ negative ? amount * -1 : amount
82
+ end
83
+
84
+ def compute_currency
85
+ match = input.match(currency_symbol_regex)
86
+ CURRENCY_SYMBOLS[match.to_s] if match
87
+ end
88
+
89
+ def extract_major_minor(num, currency)
90
+ used_delimiters = num.scan(/[^\d]/).uniq
91
+
92
+ case used_delimiters.length
93
+ when 0
94
+ [num, 0]
95
+ when 2
96
+ thousands_separator, decimal_mark = used_delimiters
97
+ split_major_minor(num.gsub(thousands_separator, ''), decimal_mark)
98
+ when 1
99
+ extract_major_minor_with_single_delimiter(num, currency, used_delimiters.first)
100
+ else
101
+ fail ParseError, 'Invalid amount'
102
+ end
103
+ end
104
+
105
+ def extract_major_minor_with_single_delimiter(num, currency, delimiter)
106
+ if delimiter == currency.decimal_mark
107
+ split_major_minor(num, delimiter)
108
+ elsif Monetize.enforce_currency_delimiters && delimiter == currency.thousands_separator
109
+ [num.gsub(delimiter, ''), 0]
110
+ else
111
+ extract_major_minor_with_tentative_delimiter(num, delimiter)
112
+ end
113
+ end
114
+
115
+ def extract_major_minor_with_tentative_delimiter(num, delimiter)
116
+ if num.scan(delimiter).length > 1
117
+ # Multiple matches; treat as thousands separator
118
+ [num.gsub(delimiter, ''), '00']
119
+ else
120
+ possible_major, possible_minor = split_major_minor(num, delimiter)
121
+
122
+ if possible_minor.length != 3 || possible_major.length > 3 || delimiter == '.'
123
+ # Doesn't look like thousands separator
124
+ [possible_major, possible_minor]
125
+ else
126
+ ["#{possible_major}#{possible_minor}", '00']
127
+ end
128
+ end
129
+ end
130
+
131
+ def extract_multiplier
132
+ if (matches = MULTIPLIER_REGEXP.match(input))
133
+ multiplier_suffix = matches[2].upcase
134
+ [MULTIPLIER_SUFFIXES[multiplier_suffix], "#{$1}#{$3}"]
135
+ else
136
+ [0, input]
137
+ end
138
+ end
139
+
140
+ def extract_sign(input)
141
+ result = (input =~ /^-+(.*)$/ || input =~ /^(.*)-+$/) ? [true, $1] : [false, input]
142
+ fail ParseError, 'Invalid amount (hyphen)' if result[1].include?('-')
143
+ result
144
+ end
145
+
146
+ def regex_safe_symbols
147
+ CURRENCY_SYMBOLS.keys.map { |key| Regexp.escape(key) }.join('|')
148
+ end
149
+
150
+ def split_major_minor(num, delimiter)
151
+ major, minor = num.split(delimiter)
152
+ [major, minor || '00']
153
+ end
154
+
155
+ def currency_symbol_regex
156
+ /(?<![A-Z])(#{regex_safe_symbols})(?![A-Z])/i
157
+ end
158
+ end
159
+ end
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Monetize
4
- VERSION = '1.4.0'
4
+ VERSION = '1.9.4'
5
5
  end
@@ -7,8 +7,8 @@ require 'English'
7
7
  Gem::Specification.new do |spec|
8
8
  spec.name = 'monetize'
9
9
  spec.version = Monetize::VERSION
10
- spec.authors = ['Shane Emmons']
11
- spec.email = ['shane@emmons.io']
10
+ spec.authors = ['Shane Emmons', 'Anthony Dmitriyev']
11
+ spec.email = ['shane@emmons.io', 'anthony.dmitriyev@gmail.com']
12
12
  spec.description = 'A library for converting various objects into `Money` objects.'
13
13
  spec.summary = 'A library for converting various objects into `Money` objects.'
14
14
  spec.homepage = 'https://github.com/RubyMoney/monetize'
@@ -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.7'
22
+ spec.add_dependency 'money', '~> 6.12'
23
23
 
24
- spec.add_development_dependency 'bundler', '~> 1.3'
25
- spec.add_development_dependency 'rake'
26
- spec.add_development_dependency 'rspec', '~> 3.0.0.beta1'
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.new('1234').to_money
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
@@ -67,7 +67,8 @@ describe Monetize, 'core extensions' do
67
67
  '-1,000' => Money.new(-1_000_00),
68
68
  '1,000.5' => Money.new(1_000_50),
69
69
  '1,000.51' => Money.new(1_000_51),
70
- '1,000.505' => Money.new(1_000_51),
70
+ '1,000.505' => Money.new(1_000_50), # ROUND_HALF_EVEN default bankers rounding
71
+ '1,000.515' => Money.new(1_000_52), # ROUND_HALF_EVEN default bankers rounding
71
72
  '1,000.504' => Money.new(1_000_50),
72
73
  '1,000.0000' => Money.new(1_000_00),
73
74
  '1,000.5000' => Money.new(1_000_50),
@@ -149,6 +150,28 @@ describe Monetize, 'core extensions' do
149
150
  expect('1'.to_money('JPY')).to eq Money.new(1, 'JPY')
150
151
  expect('1.5'.to_money('KWD').cents).to eq 1_500
151
152
  end
153
+
154
+ it 'respects Money.rounding_mode' do
155
+ expect('1.009'.to_money).to eq(Money.new(1_01))
156
+
157
+ Money.rounding_mode(BigDecimal::ROUND_DOWN) do
158
+ expect('1.009'.to_money).to eq(Money.new(1_00))
159
+ end
160
+
161
+ expect('1.001'.to_money).to eq(Money.new(1_00))
162
+
163
+ Money.rounding_mode(BigDecimal::ROUND_UP) do
164
+ expect('1.001'.to_money).to eq(Money.new(1_01))
165
+ end
166
+ end
167
+
168
+ it 'produces results similar to Money.from_amount for all the rounding edge cases' do
169
+ (1_000..1_010).each do |amount|
170
+ amount = amount.to_f / 1000
171
+
172
+ expect(amount.to_s.to_money).to eq(Money.from_amount(amount))
173
+ end
174
+ end
152
175
  end
153
176
 
154
177
  describe '#to_currency' do
@@ -182,6 +205,14 @@ describe Monetize, 'core extensions' do
182
205
  end
183
206
  end
184
207
 
208
+ context 'when currency argument is a hash' do
209
+ subject(:hash) { {cents: 100, currency: {iso_code: 'EUR'}} }
210
+
211
+ it 'converts Hash to Money using iso_code from currency hash' do
212
+ expect(hash.to_money).to eq(Money.new(100, 'EUR'))
213
+ end
214
+ end
215
+
185
216
  context 'when no currency is passed' do
186
217
  subject(:hash) { {cents: 123} }
187
218
 
@@ -191,6 +222,14 @@ describe Monetize, 'core extensions' do
191
222
  expect(hash.to_money('USD')).to eq(Money.new(123, 'USD'))
192
223
  end
193
224
  end
225
+
226
+ context "when key name is 'fractional'" do
227
+ subject(:hash) { {fractional: 100} }
228
+
229
+ it 'converts Hash to Money, interpreting fractional as cents' do
230
+ expect(hash.to_money).to eq(Money.new(100, 'USD'))
231
+ end
232
+ end
194
233
  end
195
234
  end
196
235
 
@@ -56,76 +56,78 @@ describe Monetize do
56
56
  Monetize.assume_from_symbol = false
57
57
  end
58
58
 
59
- it 'parses formatted inputs with Euros passed as a symbol' do
60
- expect(Monetize.parse('€5.95')).to eq Money.new(595, 'EUR')
61
- end
62
-
63
- it 'parses formatted inputs with Euros passed as a symbol with surrounding space' do
64
- expect(Monetize.parse(' €5.95 ')).to eq Money.new(595, 'EUR')
65
- end
66
-
67
- it 'parses formatted inputs with British Pounds Sterling passed as a symbol' do
68
- expect(Monetize.parse('£9.99')).to eq Money.new(999, 'GBP')
69
- end
70
-
71
- it 'parses formatted inputs with British Pounds Sterling passed as a lira sign symbol' do
72
- expect(Monetize.parse('₤9.99')).to eq Money.new(999, 'GBP')
73
- end
74
-
75
- it 'parses formatted inputs with South African Rand passed as a symbol' do
76
- expect(Monetize.parse('R9.99')).to eq Money.new(999, 'ZAR')
77
- end
78
-
79
- it 'parses formatted inputs with Brazilian real passed as a symbol' do
80
- expect(Monetize.parse('R$R9.99')).to eq Money.new(999, 'BRL')
81
- end
82
-
83
- it 'parses formatted inputs with Japanese Yen passed as a symbol' do
84
- expect(Monetize.parse('¥999')).to eq Money.new(999, 'JPY')
85
- end
86
-
87
- it 'parses formatted inputs with Canadian Dollar passed as a symbol' do
88
- expect(Monetize.parse('C$9.99')).to eq Money.new(999, 'CAD')
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
+ it "parses formatted inputs with #{iso_code} symbol is after the amount" do
74
+ expect(Monetize.parse("#{amount_in_units}#{symbol}")).to eq Money.new(amount, iso_code)
75
+ end
76
+
77
+ context 'prefix' do
78
+ it 'parses formatted inputs with plus 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
+
82
+ it 'parses formatted inputs with minus sign and currency as a symbol' do
83
+ expect(Monetize.parse("-#{symbol}#{amount_in_units}")).to eq Money.new(-amount, iso_code)
84
+ end
85
+ end
86
+
87
+ context 'postfix' do
88
+ it 'parses formatted inputs with currency symbol and postfix minus sign' do
89
+ expect(Monetize.parse("#{symbol}#{amount_in_units}-")).to eq Money.new(-amount, iso_code)
90
+ end
91
+
92
+ it 'parses formatted inputs with currency symbol and postfix plus sign' do
93
+ expect(Monetize.parse("#{symbol}#{amount_in_units}+")).to eq Money.new(amount, iso_code)
94
+ end
95
+ end
96
+
97
+ context 'amount suffixes' do
98
+ it 'parses formatted inputs with amounts given with suffixes' do
99
+ expect(Monetize.parse("#{symbol}1.26K")).to eq Money.new(1_260 * currency.subunit_to_unit, iso_code)
100
+ expect(Monetize.parse("#{symbol}126.36M")).to eq Money.new(126_360_000 * currency.subunit_to_unit, iso_code)
101
+ expect(Monetize.parse("#{symbol}.45B")).to eq Money.new(450_000_000 * currency.subunit_to_unit, iso_code)
102
+ expect(Monetize.parse("-#{symbol}2.45B")).to eq Money.new(-2_450_000_000 * currency.subunit_to_unit, iso_code)
103
+ expect(Monetize.parse("#{symbol}1.65T")).to eq Money.new(1_650_000_000_000 * currency.subunit_to_unit, iso_code)
104
+ end
105
+ end
106
+
107
+ it 'parses formatted inputs with symbol and surrounding spaces' do
108
+ expect(Monetize.parse(" #{symbol}#{amount_in_units} ")).to eq Money.new(amount, iso_code)
109
+ end
110
+
111
+ it 'parses formatted inputs without currency detection when overridden' do
112
+ expect(Monetize.parse("#{symbol}5.95", nil, assume_from_symbol: false)).to eq Money.new(amount, 'USD')
113
+ end
114
+ end
89
115
  end
90
116
 
91
117
  it 'should assume default currency if not a recognised symbol' do
92
118
  expect(Monetize.parse('L9.99')).to eq Money.new(999, 'USD')
93
119
  end
94
120
 
95
- it 'parses formatted inputs without currency detection when overridden' do
96
- expect(Monetize.parse('£9.99', nil, assume_from_symbol: false)).to eq Money.new(999, 'USD')
97
- end
98
-
99
- it 'parses formatted inputs with minus sign and currency symbol' do
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
+ it 'ignores ZAR symbols that is part of a text' do
122
+ expect(Monetize.parse('EUR 9.99')).to eq Money.new(999, 'EUR')
123
+ expect(Monetize.parse('9.99 EUR')).to eq Money.new(999, 'EUR')
121
124
  end
122
125
 
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')
126
+ context 'negatives' do
127
+ it 'ignores the ambiguous kr symbol' do
128
+ # Could mean either of DKK, EEK, ISK, NOK, SEK
129
+ expect(Monetize.parse('kr9.99')).to eq Money.new(999, 'USD')
130
+ end
129
131
  end
130
132
  end
131
133
 
@@ -158,6 +160,18 @@ describe Monetize do
158
160
  it 'should opt out by default' do
159
161
  expect(Monetize.assume_from_symbol).to be_falsy
160
162
  end
163
+
164
+ context 'ISO code' do
165
+ it 'parses currency given as ISO code' do
166
+ expect('20.00 USD'.to_money).to eq Money.new(20_00, 'USD')
167
+ expect('20.00 EUR'.to_money).to eq Money.new(20_00, 'EUR')
168
+ expect('20.00 GBP'.to_money).to eq Money.new(20_00, 'GBP')
169
+ end
170
+
171
+ it 'raises an error if currency code is invalid' do
172
+ expect { '20.00 OMG'.to_money }.to raise_error Monetize::ParseError
173
+ end
174
+ end
161
175
  end
162
176
 
163
177
  it 'parses USD-formatted inputs under $10' do
@@ -177,10 +191,16 @@ describe Monetize do
177
191
  expect(Monetize.parse('1,111,234,567.89')).to eq Money.new(1_111_234_567_89, 'USD')
178
192
  end
179
193
 
180
- it 'does not return a price if there is a price range' do
181
- expect { Monetize.parse('$5.95-10.95') }.to raise_error ArgumentError
182
- expect { Monetize.parse('$5.95 - 10.95') }.to raise_error ArgumentError
183
- expect { Monetize.parse('$5.95 - $10.95') }.to raise_error ArgumentError
194
+ it 'parses DKK-formatted inputs' do
195
+ expect(Monetize.parse('kr.123,45', 'DKK')).to eq Money.new(123_45, 'DKK')
196
+ expect(Monetize.parse('kr.123.45', 'DKK')).to eq Money.new(123_45, 'DKK')
197
+ expect(Monetize.parse('kr.45k', 'DKK')).to eq Money.new(45_000_00, 'DKK')
198
+ end
199
+
200
+ it 'returns nil if input is a price range' do
201
+ expect(Monetize.parse('$5.95-10.95')).to be_nil
202
+ expect(Monetize.parse('$5.95 - 10.95')).to be_nil
203
+ expect(Monetize.parse('$5.95 - $10.95')).to be_nil
184
204
  end
185
205
 
186
206
  it 'does not return a price for completely invalid input' do
@@ -197,8 +217,16 @@ describe Monetize do
197
217
  expect(Monetize.parse('$5.95-')).to eq five_ninety_five
198
218
  end
199
219
 
200
- it 'raises ArgumentError when unable to detect polarity' do
201
- expect { Monetize.parse('-$5.95-') }.to raise_error ArgumentError
220
+ it 'returns nil when unable to detect polarity' do
221
+ expect(Monetize.parse('-$5.95-')).to be_nil
222
+ end
223
+
224
+ it 'returns nil when more than 2 digit separators are used' do
225
+ expect(Monetize.parse("123.34,56'89 EUR")).to be_nil
226
+ end
227
+
228
+ it 'parses correctly strings with repeated digit separator' do
229
+ expect(Monetize.parse('19.12.89', 'EUR')).to eq Money.new(191_289_00, 'EUR')
202
230
  end
203
231
 
204
232
  it 'parses correctly strings with exactly 3 decimal digits' do
@@ -210,6 +238,32 @@ describe Monetize do
210
238
  Monetize.enforce_currency_delimiters = false
211
239
  end
212
240
 
241
+ context 'Money object attempting to be parsed' do
242
+ let(:money) { Money.new(595, 'GBP') }
243
+
244
+ it 'returns the original Money object' do
245
+ expect(Monetize.parse(money)).to eq money
246
+ expect(Monetize.parse(money).currency).to eq 'GBP'
247
+ expect(Monetize.parse(money).cents).to eq 595
248
+ end
249
+ end
250
+
251
+ context 'parsing an instance of Numeric class' do
252
+ let(:integer) { 10 }
253
+ let(:float) { 10.0 }
254
+ let(:big_decimal) { BigDecimal('10') }
255
+
256
+ [:integer, :float, :big_decimal].each do |type|
257
+ it "returns a new Money object based on the #{type} input" do
258
+ money = Monetize.parse(send(type), 'USD')
259
+
260
+ expect(money).to be_instance_of(Money)
261
+ expect(money.currency).to eq('USD')
262
+ expect(money.cents).to eq(10_00)
263
+ end
264
+ end
265
+ end
266
+
213
267
  context 'custom currencies with 4 decimal places' do
214
268
  before :each do
215
269
  Money::Currency.register(JSON.parse(bar, symbolize_names: true))
@@ -265,6 +319,18 @@ describe Monetize do
265
319
  end
266
320
  end
267
321
 
322
+ describe '.parse!' do
323
+ it 'does not return a price if there is a price range' do
324
+ expect { Monetize.parse!('$5.95-10.95') }.to raise_error Monetize::ParseError
325
+ expect { Monetize.parse!('$5.95 - 10.95') }.to raise_error Monetize::ParseError
326
+ expect { Monetize.parse!('$5.95 - $10.95') }.to raise_error Monetize::ParseError
327
+ end
328
+
329
+ it 'raises ArgumentError when unable to detect polarity' do
330
+ expect { Monetize.parse!('-$5.95-') }.to raise_error Monetize::ParseError
331
+ end
332
+ end
333
+
268
334
  describe '.parse_collection' do
269
335
  it 'parses into a Money::Collection' do
270
336
  expect(Monetize.parse_collection('$7')).to be_a Monetize::Collection
@@ -287,6 +353,10 @@ describe Monetize do
287
353
  expect(collection.first).to eq Monetize.parse('$4')
288
354
  expect(collection.last).to eq Monetize.parse('$10')
289
355
  end
356
+
357
+ it 'raises an error if argument is invalid' do
358
+ expect { Monetize.parse_collection(nil) }.to raise_error Monetize::ArgumentError
359
+ end
290
360
  end
291
361
 
292
362
  describe '.from_string' do
@@ -337,6 +407,10 @@ describe Monetize do
337
407
  m = Monetize.from_fixnum(1, 'EUR')
338
408
  expect(m.currency).to eq Money::Currency.wrap('EUR')
339
409
  end
410
+
411
+ it 'is aliased as from_integer' do
412
+ expect(Monetize.from_integer(1)).to eq(Monetize.from_fixnum(1))
413
+ end
340
414
  end
341
415
 
342
416
  describe '.from_float' do
@@ -366,25 +440,31 @@ describe Monetize do
366
440
 
367
441
  describe '.from_bigdecimal' do
368
442
  it 'converts given amount to cents' do
369
- expect(Monetize.from_bigdecimal(BigDecimal.new('1'))).to eq Money.new(1_00)
370
- expect(Monetize.from_bigdecimal(BigDecimal.new('1'))).to eq Money.new(1_00, 'USD')
371
- expect(Monetize.from_bigdecimal(BigDecimal.new('1'), 'EUR')).to eq Money.new(1_00, 'EUR')
443
+ expect(Monetize.from_bigdecimal(BigDecimal('1'))).to eq Money.new(1_00)
444
+ expect(Monetize.from_bigdecimal(BigDecimal('1'))).to eq Money.new(1_00, 'USD')
445
+ expect(Monetize.from_bigdecimal(BigDecimal('1'), 'EUR')).to eq Money.new(1_00, 'EUR')
372
446
  end
373
447
 
374
448
  it 'respects :subunit_to_unit currency property' do
375
- expect(Monetize.from_bigdecimal(BigDecimal.new('1'), 'USD')).to eq Money.new(1_00, 'USD')
376
- expect(Monetize.from_bigdecimal(BigDecimal.new('1'), 'TND')).to eq Money.new(1_000, 'TND')
377
- expect(Monetize.from_bigdecimal(BigDecimal.new('1'), 'JPY')).to eq Money.new(1, 'JPY')
449
+ expect(Monetize.from_bigdecimal(BigDecimal('1'), 'USD')).to eq Money.new(1_00, 'USD')
450
+ expect(Monetize.from_bigdecimal(BigDecimal('1'), 'TND')).to eq Money.new(1_000, 'TND')
451
+ expect(Monetize.from_bigdecimal(BigDecimal('1'), 'JPY')).to eq Money.new(1, 'JPY')
452
+ end
453
+
454
+ it 'respects rounding mode when rounding amount to the nearest cent' do
455
+ amount = BigDecimal('1.005')
456
+
457
+ expect(Monetize.from_bigdecimal(amount, 'USD')).to eq Money.from_amount(amount, 'USD')
378
458
  end
379
459
 
380
460
  it 'accepts a currency options' do
381
- m = Monetize.from_bigdecimal(BigDecimal.new('1'))
461
+ m = Monetize.from_bigdecimal(BigDecimal('1'))
382
462
  expect(m.currency).to eq Money.default_currency
383
463
 
384
- m = Monetize.from_bigdecimal(BigDecimal.new('1'), Money::Currency.wrap('EUR'))
464
+ m = Monetize.from_bigdecimal(BigDecimal('1'), Money::Currency.wrap('EUR'))
385
465
  expect(m.currency).to eq Money::Currency.wrap('EUR')
386
466
 
387
- m = Monetize.from_bigdecimal(BigDecimal.new('1'), 'EUR')
467
+ m = Monetize.from_bigdecimal(BigDecimal('1'), 'EUR')
388
468
  expect(m.currency).to eq Money::Currency.wrap('EUR')
389
469
  end
390
470
 
@@ -398,11 +478,11 @@ describe Monetize do
398
478
  end
399
479
 
400
480
  it 'keeps precision' do
401
- expect(Monetize.from_bigdecimal(BigDecimal.new('1'))).to eq Money.new(100)
402
- expect(Monetize.from_bigdecimal(BigDecimal.new('1.23456'))).to eq Money.new(123.456)
403
- expect(Monetize.from_bigdecimal(BigDecimal.new('-1.23456'))).to eq Money.new(-123.456)
404
- expect(Monetize.from_bigdecimal(BigDecimal.new('1.23456'))).to eq Money.new(123.456, 'USD')
405
- expect(Monetize.from_bigdecimal(BigDecimal.new('1.23456'), 'EUR')).to eq Money.new(123.456, 'EUR')
481
+ expect(Monetize.from_bigdecimal(BigDecimal('1'))).to eq Money.new(100)
482
+ expect(Monetize.from_bigdecimal(BigDecimal('1.23456'))).to eq Money.new(123.456)
483
+ expect(Monetize.from_bigdecimal(BigDecimal('-1.23456'))).to eq Money.new(-123.456)
484
+ expect(Monetize.from_bigdecimal(BigDecimal('1.23456'))).to eq Money.new(123.456, 'USD')
485
+ expect(Monetize.from_bigdecimal(BigDecimal('1.23456'), 'EUR')).to eq Money.new(123.456, 'EUR')
406
486
 
407
487
  expect('1'.to_money).to eq Money.new(100)
408
488
  expect('1.23456'.to_money).to eq Money.new(123.456)
@@ -417,19 +497,11 @@ describe Monetize do
417
497
  it 'converts given amount to cents' do
418
498
  expect(Monetize.from_numeric(1)).to eq Money.new(1_00)
419
499
  expect(Monetize.from_numeric(1.0)).to eq Money.new(1_00)
420
- expect(Monetize.from_numeric(BigDecimal.new('1'))).to eq Money.new(1_00)
500
+ expect(Monetize.from_numeric(BigDecimal('1'))).to eq Money.new(1_00)
421
501
  end
422
502
 
423
503
  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')
504
+ expect { Monetize.from_numeric('100') }.to raise_error(Monetize::ArgumentError)
433
505
  end
434
506
 
435
507
  it 'respects :subunit_to_unit currency property' do
@@ -457,6 +529,20 @@ describe Monetize do
457
529
  end
458
530
 
459
531
  describe '.extract_cents' do
532
+ it 'is deprecated' do
533
+ allow(Monetize).to receive(:warn)
534
+
535
+ Monetize.extract_cents('100')
536
+
537
+ expect(Monetize)
538
+ .to have_received(:warn)
539
+ .with('[DEPRECATION] Monetize.extract_cents is deprecated. Use Monetize.parse().cents')
540
+ end
541
+
542
+ it 'extracts cents from a given string' do
543
+ expect(Monetize.extract_cents('10.99')).to eq(1099)
544
+ end
545
+
460
546
  it "correctly treats pipe marks '|' in input (regression test)" do
461
547
  expect(Monetize.extract_cents('100|0')).to eq Monetize.extract_cents('100!0')
462
548
  end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: monetize
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.9.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shane Emmons
8
+ - Anthony Dmitriyev
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2016-01-15 00:00:00.000000000 Z
12
+ date: 2020-01-07 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: money
@@ -16,59 +17,60 @@ dependencies:
16
17
  requirements:
17
18
  - - "~>"
18
19
  - !ruby/object:Gem::Version
19
- version: '6.7'
20
+ version: '6.12'
20
21
  type: :runtime
21
22
  prerelease: false
22
23
  version_requirements: !ruby/object:Gem::Requirement
23
24
  requirements:
24
25
  - - "~>"
25
26
  - !ruby/object:Gem::Version
26
- version: '6.7'
27
+ version: '6.12'
27
28
  - !ruby/object:Gem::Dependency
28
29
  name: bundler
29
30
  requirement: !ruby/object:Gem::Requirement
30
31
  requirements:
31
- - - "~>"
32
+ - - ">="
32
33
  - !ruby/object:Gem::Version
33
- version: '1.3'
34
+ version: '0'
34
35
  type: :development
35
36
  prerelease: false
36
37
  version_requirements: !ruby/object:Gem::Requirement
37
38
  requirements:
38
- - - "~>"
39
+ - - ">="
39
40
  - !ruby/object:Gem::Version
40
- version: '1.3'
41
+ version: '0'
41
42
  - !ruby/object:Gem::Dependency
42
43
  name: rake
43
44
  requirement: !ruby/object:Gem::Requirement
44
45
  requirements:
45
- - - ">="
46
+ - - "~>"
46
47
  - !ruby/object:Gem::Version
47
- version: '0'
48
+ version: '10.2'
48
49
  type: :development
49
50
  prerelease: false
50
51
  version_requirements: !ruby/object:Gem::Requirement
51
52
  requirements:
52
- - - ">="
53
+ - - "~>"
53
54
  - !ruby/object:Gem::Version
54
- version: '0'
55
+ version: '10.2'
55
56
  - !ruby/object:Gem::Dependency
56
57
  name: rspec
57
58
  requirement: !ruby/object:Gem::Requirement
58
59
  requirements:
59
60
  - - "~>"
60
61
  - !ruby/object:Gem::Version
61
- version: 3.0.0.beta1
62
+ version: '3.0'
62
63
  type: :development
63
64
  prerelease: false
64
65
  version_requirements: !ruby/object:Gem::Requirement
65
66
  requirements:
66
67
  - - "~>"
67
68
  - !ruby/object:Gem::Version
68
- version: 3.0.0.beta1
69
+ version: '3.0'
69
70
  description: A library for converting various objects into `Money` objects.
70
71
  email:
71
72
  - shane@emmons.io
73
+ - anthony.dmitriyev@gmail.com
72
74
  executables: []
73
75
  extensions: []
74
76
  extra_rdoc_files: []
@@ -83,14 +85,16 @@ files:
83
85
  - LICENSE.txt
84
86
  - README.md
85
87
  - Rakefile
86
- - lib/collection.rb
87
88
  - lib/monetize.rb
89
+ - lib/monetize/collection.rb
88
90
  - lib/monetize/core_extensions.rb
89
91
  - lib/monetize/core_extensions/hash.rb
90
92
  - lib/monetize/core_extensions/nil_class.rb
91
93
  - lib/monetize/core_extensions/numeric.rb
92
94
  - lib/monetize/core_extensions/string.rb
93
95
  - lib/monetize/core_extensions/symbol.rb
96
+ - lib/monetize/errors.rb
97
+ - lib/monetize/parser.rb
94
98
  - lib/monetize/version.rb
95
99
  - monetize.gemspec
96
100
  - spec/core_extensions_spec.rb
@@ -99,7 +103,10 @@ files:
99
103
  homepage: https://github.com/RubyMoney/monetize
100
104
  licenses:
101
105
  - MIT
102
- metadata: {}
106
+ metadata:
107
+ changelog_uri: https://github.com/RubyMoney/monetize/blob/master/CHANGELOG.md
108
+ source_code_uri: https://github.com/RubyMoney/monetize/
109
+ bug_tracker_uri: https://github.com/RubyMoney/monetize/issues
103
110
  post_install_message:
104
111
  rdoc_options: []
105
112
  require_paths:
@@ -115,8 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
122
  - !ruby/object:Gem::Version
116
123
  version: '0'
117
124
  requirements: []
118
- rubyforge_project:
119
- rubygems_version: 2.4.5.1
125
+ rubygems_version: 3.0.3
120
126
  signing_key:
121
127
  specification_version: 4
122
128
  summary: A library for converting various objects into `Money` objects.
@@ -124,4 +130,3 @@ test_files:
124
130
  - spec/core_extensions_spec.rb
125
131
  - spec/monetize_spec.rb
126
132
  - spec/spec_helper.rb
127
- has_rdoc: