money 6.7.0 → 6.7.1
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 +4 -4
- data/.travis.yml +8 -0
- data/CHANGELOG.md +11 -0
- data/README.md +6 -6
- data/config/currency_iso.json +4 -3
- data/lib/money/currency.rb +8 -5
- data/lib/money/money.rb +15 -13
- data/lib/money/money/arithmetic.rb +30 -28
- data/lib/money/money/formatting.rb +31 -30
- data/lib/money/version.rb +1 -1
- data/spec/currency_spec.rb +1 -1
- data/spec/money/arithmetic_spec.rb +36 -17
- data/spec/money/formatting_spec.rb +28 -4
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cf8496911c1ac6ef2fdb34ad3e0b9f458bf6e836
|
4
|
+
data.tar.gz: 70ed919de03069d7a92883d46b890d60194eae1a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dabd711f4ba2737ee735c8e29569b56d0650686802fd56e27d0df34afd26865bfd11630deacb64cb74d22c7b97a25fd8a4bfa49ed3dcfa5195b8bf324edd2a53
|
7
|
+
data.tar.gz: 03e66b3f5639b64baf44082e075e6c2e275ce8bd9911cb0e1152ccf4449d840043b9a233a81b51ef6cf66783986e600a3d7c57840287a398f5d52e45f56bbb4f
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 6.7.1
|
4
|
+
- Changed DKK symbol from 'kr' to 'kr.'
|
5
|
+
- Improved Money::Formatting#format docs
|
6
|
+
- Updated VEF symbol from 'Bs F' to 'Bs'
|
7
|
+
- `Currency#exponent` now returns Fixnum
|
8
|
+
- Fixed coercion issues
|
9
|
+
- Fixed edge case with explicit override of thousands separator and decimal mark
|
10
|
+
- `Money#==` will now raise error for non-zero numeric values
|
11
|
+
- Fixed divmod
|
12
|
+
- Added disambiguation symbol to USD Dollar
|
13
|
+
|
3
14
|
## 6.7.0
|
4
15
|
- Changed `Money#<=>` to return `nil` if the comparison is inappropriate. (#584)
|
5
16
|
- Remove implicit conversion of values being compared. Only accept `Money` and
|
data/README.md
CHANGED
@@ -28,7 +28,7 @@ A Ruby Library for dealing with money and currency conversion.
|
|
28
28
|
a monetary unit.
|
29
29
|
- Represents monetary values as integers, in cents. This avoids floating point
|
30
30
|
rounding errors.
|
31
|
-
- Represents currency as `Money::Currency` instances providing
|
31
|
+
- Represents currency as `Money::Currency` instances providing a high level of
|
32
32
|
flexibility.
|
33
33
|
- Provides APIs for exchanging money from one currency to another.
|
34
34
|
|
@@ -203,12 +203,12 @@ If you use Rails, then `environment.rb` is a very good place to put this.
|
|
203
203
|
The exponent of a money value is the number of digits after the decimal
|
204
204
|
separator (which separates the major unit from the minor unit). See e.g.
|
205
205
|
[ISO 4217](http://www.currency-iso.org/en/shared/amendments/iso-4217-amendment.html) for more
|
206
|
-
information. You can find the exponent (as
|
206
|
+
information. You can find the exponent (as an `Integer`) by
|
207
207
|
|
208
208
|
``` ruby
|
209
|
-
Money::Currency.new("USD").exponent # => 2
|
210
|
-
Money::Currency.new("JPY").exponent # => 0
|
211
|
-
Money::Currency.new("MGA").exponent # =>
|
209
|
+
Money::Currency.new("USD").exponent # => 2
|
210
|
+
Money::Currency.new("JPY").exponent # => 0
|
211
|
+
Money::Currency.new("MGA").exponent # => 1
|
212
212
|
```
|
213
213
|
|
214
214
|
### Currency Lookup
|
@@ -369,7 +369,7 @@ implementations.
|
|
369
369
|
|
370
370
|
- [eu_central_bank](https://github.com/RubyMoney/eu_central_bank)
|
371
371
|
- [google_currency](https://github.com/RubyMoney/google_currency)
|
372
|
-
- [
|
372
|
+
- [currencylayer](https://github.com/askuratovsky/currencylayer)
|
373
373
|
- [nordea](https://github.com/matiaskorhonen/nordea)
|
374
374
|
- [nbrb_currency](https://github.com/slbug/nbrb_currency)
|
375
375
|
- [money-currencylayer-bank](https://github.com/phlegx/money-currencylayer-bank)
|
data/config/currency_iso.json
CHANGED
@@ -604,7 +604,7 @@
|
|
604
604
|
"priority": 100,
|
605
605
|
"iso_code": "DKK",
|
606
606
|
"name": "Danish Krone",
|
607
|
-
"symbol": "kr",
|
607
|
+
"symbol": "kr.",
|
608
608
|
"disambiguate_symbol": "DKK",
|
609
609
|
"alternate_symbols": [",-"],
|
610
610
|
"subunit": "Øre",
|
@@ -2259,6 +2259,7 @@
|
|
2259
2259
|
"iso_code": "USD",
|
2260
2260
|
"name": "United States Dollar",
|
2261
2261
|
"symbol": "$",
|
2262
|
+
"disambiguate_symbol": "US$",
|
2262
2263
|
"alternate_symbols": ["US$"],
|
2263
2264
|
"subunit": "Cent",
|
2264
2265
|
"subunit_to_unit": 100,
|
@@ -2303,8 +2304,8 @@
|
|
2303
2304
|
"priority": 100,
|
2304
2305
|
"iso_code": "VEF",
|
2305
2306
|
"name": "Venezuelan Bolívar",
|
2306
|
-
"symbol": "Bs
|
2307
|
-
"alternate_symbols": ["Bs.F"
|
2307
|
+
"symbol": "Bs",
|
2308
|
+
"alternate_symbols": ["Bs.F"],
|
2308
2309
|
"subunit": "Céntimo",
|
2309
2310
|
"subunit_to_unit": 100,
|
2310
2311
|
"symbol_first": true,
|
data/lib/money/currency.rb
CHANGED
@@ -374,7 +374,7 @@ class Money
|
|
374
374
|
id.to_s.upcase.to_sym
|
375
375
|
end
|
376
376
|
|
377
|
-
#
|
377
|
+
# Conversion to +self+.
|
378
378
|
#
|
379
379
|
# @return [self]
|
380
380
|
def to_currency
|
@@ -392,14 +392,17 @@ class Money
|
|
392
392
|
!!@symbol_first
|
393
393
|
end
|
394
394
|
|
395
|
-
# Returns the
|
395
|
+
# Returns the relation between subunit and unit as a base 10 exponent.
|
396
396
|
#
|
397
|
-
#
|
397
|
+
# Note that MGA and MRO are exceptions and are rounded to 1
|
398
|
+
# @see https://en.wikipedia.org/wiki/ISO_4217#Active_codes
|
399
|
+
#
|
400
|
+
# @return [Fixnum]
|
398
401
|
def exponent
|
399
|
-
Math.log10(@subunit_to_unit)
|
402
|
+
Math.log10(@subunit_to_unit).round
|
400
403
|
end
|
401
404
|
|
402
|
-
# Cache decimal places for subunit_to_unit values.
|
405
|
+
# Cache decimal places for subunit_to_unit values. Common ones pre-cached.
|
403
406
|
def self.decimal_places_cache
|
404
407
|
@decimal_places_cache ||= {1 => 0, 10 => 1, 100 => 2, 1000 => 3}
|
405
408
|
end
|
data/lib/money/money.rb
CHANGED
@@ -15,7 +15,9 @@ require "money/money/formatting"
|
|
15
15
|
#
|
16
16
|
# @see http://en.wikipedia.org/wiki/Money
|
17
17
|
class Money
|
18
|
-
include Comparable
|
18
|
+
include Comparable
|
19
|
+
include Money::Arithmetic
|
20
|
+
include Money::Formatting
|
19
21
|
extend Constructors
|
20
22
|
|
21
23
|
# Raised when smallest denomination of a currency is not defined
|
@@ -34,17 +36,17 @@ class Money
|
|
34
36
|
# The value of the monetary amount represented in the fractional or subunit
|
35
37
|
# of the currency.
|
36
38
|
#
|
37
|
-
# For example, in the US
|
38
|
-
# there are 100 cents in one US
|
39
|
+
# For example, in the US dollar currency the fractional unit is cents, and
|
40
|
+
# there are 100 cents in one US dollar. So given the Money representation of
|
39
41
|
# one US dollar, the fractional interpretation is 100.
|
40
42
|
#
|
41
|
-
# Another example is that of the Kuwaiti
|
42
|
-
# unit is the
|
43
|
-
# Money representation of one Kuwaiti
|
43
|
+
# Another example is that of the Kuwaiti dinar. In this case the fractional
|
44
|
+
# unit is the fils and there 1000 fils to one Kuwaiti dinar. So given the
|
45
|
+
# Money representation of one Kuwaiti dinar, the fractional interpretation is
|
44
46
|
# 1000.
|
45
47
|
#
|
46
48
|
# @return [Integer] when infinite_precision is false
|
47
|
-
# @return [BigDecimal] when
|
49
|
+
# @return [BigDecimal] when infinite_precision is true
|
48
50
|
#
|
49
51
|
# @see infinite_precision
|
50
52
|
def fractional
|
@@ -56,7 +58,7 @@ class Money
|
|
56
58
|
end
|
57
59
|
|
58
60
|
# Round a given amount of money to the nearest possible amount in cash value. For
|
59
|
-
# example, in Swiss
|
61
|
+
# example, in Swiss franc (CHF), the smallest possible amount of cash value is
|
60
62
|
# CHF 0.05. Therefore, this method rounds CHF 0.07 to CHF 0.05, and CHF 0.08 to
|
61
63
|
# CHF 0.10.
|
62
64
|
#
|
@@ -78,7 +80,7 @@ class Money
|
|
78
80
|
|
79
81
|
# @!attribute [r] currency
|
80
82
|
# @return [Currency] The money's currency.
|
81
|
-
# @!attribute [r] bank
|
83
|
+
# @!attribute [r] bank
|
82
84
|
# @return [Money::Bank::Base] The +Money::Bank+-based object which currency
|
83
85
|
# exchanges are performed with.
|
84
86
|
|
@@ -95,7 +97,7 @@ class Money
|
|
95
97
|
# one to specify custom exchange rates.
|
96
98
|
#
|
97
99
|
# @!attribute default_formatting_rules
|
98
|
-
# @return [Hash] Use this to define a default hash of rules for
|
100
|
+
# @return [Hash] Use this to define a default hash of rules for every time
|
99
101
|
# +Money#format+ is called. Rules provided on method call will be
|
100
102
|
# merged with the default ones. To overwrite a rule, just provide the
|
101
103
|
# intended value while calling +format+.
|
@@ -166,7 +168,7 @@ class Money
|
|
166
168
|
setup_defaults
|
167
169
|
|
168
170
|
# Use this to return the rounding mode. You may also pass a
|
169
|
-
# rounding mode and a block to
|
171
|
+
# rounding mode and a block to temporarily change it. It will
|
170
172
|
# then return the results of the block instead.
|
171
173
|
#
|
172
174
|
# @param [BigDecimal::ROUND_MODE] mode
|
@@ -436,7 +438,7 @@ class Money
|
|
436
438
|
end
|
437
439
|
|
438
440
|
# Receive a money object with the same amount as the current Money object
|
439
|
-
# in
|
441
|
+
# in United States dollar.
|
440
442
|
#
|
441
443
|
# @return [Money]
|
442
444
|
#
|
@@ -448,7 +450,7 @@ class Money
|
|
448
450
|
end
|
449
451
|
|
450
452
|
# Receive a money object with the same amount as the current Money object
|
451
|
-
# in
|
453
|
+
# in Canadian dollar.
|
452
454
|
#
|
453
455
|
# @return [Money]
|
454
456
|
#
|
@@ -1,18 +1,13 @@
|
|
1
1
|
class Money
|
2
|
-
CoercedNumber = Struct.new(:value) do
|
3
|
-
include Comparable
|
4
|
-
|
5
|
-
def +(other) raise TypeError; end
|
6
|
-
def -(other) raise TypeError; end
|
7
|
-
def /(other) raise TypeError; end
|
8
|
-
def <=>(other) raise TypeError; end
|
9
|
-
|
10
|
-
def *(other)
|
11
|
-
other * value
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
2
|
module Arithmetic
|
3
|
+
# Wrapper for coerced numeric values to distinguish
|
4
|
+
# when numeric was on the 1st place in operation.
|
5
|
+
CoercedNumeric = Struct.new(:value) do
|
6
|
+
# Proxy #zero? method to skip unnecessary typecasts. See #- and #+.
|
7
|
+
def zero?
|
8
|
+
value.zero?
|
9
|
+
end
|
10
|
+
end
|
16
11
|
|
17
12
|
# Returns a money object with changed polarity.
|
18
13
|
#
|
@@ -57,14 +52,23 @@ class Money
|
|
57
52
|
#
|
58
53
|
# @raise [TypeError] when other object is not Money
|
59
54
|
#
|
60
|
-
def <=>(
|
61
|
-
|
62
|
-
|
63
|
-
other_money = other_money.exchange_to(currency)
|
55
|
+
def <=>(other)
|
56
|
+
if other.respond_to?(:zero?) && other.zero?
|
57
|
+
return other.is_a?(CoercedNumeric) ? 0 <=> fractional : fractional <=> 0
|
64
58
|
end
|
65
|
-
|
59
|
+
return unless other.is_a?(Money)
|
60
|
+
other = other.exchange_to(currency) if nonzero? && currency != other.currency
|
61
|
+
fractional <=> other.fractional
|
66
62
|
rescue Money::Bank::UnknownRate
|
67
|
-
|
63
|
+
end
|
64
|
+
|
65
|
+
# Uses Comparable's implementation but raises ArgumentError if non-zero
|
66
|
+
# numeric value is given.
|
67
|
+
def ==(other)
|
68
|
+
if other.is_a?(Numeric) && !other.zero?
|
69
|
+
raise ArgumentError, 'Money#== supports only zero numerics'
|
70
|
+
end
|
71
|
+
super
|
68
72
|
end
|
69
73
|
|
70
74
|
# Test if the amount is positive. Returns +true+ if the money amount is
|
@@ -137,16 +141,17 @@ class Money
|
|
137
141
|
#
|
138
142
|
# @return [Money] The resulting money.
|
139
143
|
#
|
140
|
-
# @raise [
|
144
|
+
# @raise [TypeError] If +value+ is NOT a number.
|
141
145
|
#
|
142
146
|
# @example
|
143
147
|
# Money.new(100) * 2 #=> #<Money @fractional=200>
|
144
148
|
#
|
145
149
|
def *(value)
|
150
|
+
value = value.value if value.is_a?(CoercedNumeric)
|
146
151
|
if value.is_a? Numeric
|
147
152
|
self.class.new(fractional * value, currency)
|
148
153
|
else
|
149
|
-
raise
|
154
|
+
raise TypeError, "Can't multiply a #{self.class.name} by a #{value.class.name}'s value"
|
150
155
|
end
|
151
156
|
end
|
152
157
|
|
@@ -169,6 +174,7 @@ class Money
|
|
169
174
|
if value.is_a?(self.class)
|
170
175
|
fractional / as_d(value.exchange_to(currency).fractional).to_f
|
171
176
|
else
|
177
|
+
raise TypeError, 'Can not divide by Money' if value.is_a?(CoercedNumeric)
|
172
178
|
self.class.new(fractional / as_d(value), currency)
|
173
179
|
end
|
174
180
|
end
|
@@ -212,12 +218,8 @@ class Money
|
|
212
218
|
private :divmod_money
|
213
219
|
|
214
220
|
def divmod_other(val)
|
215
|
-
|
216
|
-
|
217
|
-
[self.class.new(quotient, currency), self.class.new(remainder, currency)]
|
218
|
-
else
|
219
|
-
[div(val), self.class.new(fractional.modulo(val), currency)]
|
220
|
-
end
|
221
|
+
quotient, remainder = fractional.divmod(as_d(val))
|
222
|
+
[self.class.new(quotient, currency), self.class.new(remainder, currency)]
|
221
223
|
end
|
222
224
|
private :divmod_other
|
223
225
|
|
@@ -304,7 +306,7 @@ class Money
|
|
304
306
|
# @example
|
305
307
|
# 2 * Money.new(10) #=> #<Money @fractional=20>
|
306
308
|
def coerce(other)
|
307
|
-
[
|
309
|
+
[self, CoercedNumeric.new(other)]
|
308
310
|
end
|
309
311
|
end
|
310
312
|
end
|
@@ -7,7 +7,7 @@ class Money
|
|
7
7
|
#
|
8
8
|
# @return [String]
|
9
9
|
#
|
10
|
-
# @option
|
10
|
+
# @option rules [Boolean, String] :display_free (false) Whether a zero
|
11
11
|
# amount of money should be formatted of "free" or as the supplied string.
|
12
12
|
#
|
13
13
|
# @example
|
@@ -15,7 +15,7 @@ class Money
|
|
15
15
|
# Money.us_dollar(0).format(:display_free => "gratis") #=> "gratis"
|
16
16
|
# Money.us_dollar(0).format #=> "$0.00"
|
17
17
|
#
|
18
|
-
# @option
|
18
|
+
# @option rules [Boolean] :with_currency (false) Whether the currency name
|
19
19
|
# should be appended to the result string.
|
20
20
|
#
|
21
21
|
# @example
|
@@ -23,28 +23,28 @@ class Money
|
|
23
23
|
# Money.ca_dollar(100).format(:with_currency => true) #=> "$1.00 CAD"
|
24
24
|
# Money.us_dollar(85).format(:with_currency => true) #=> "$0.85 USD"
|
25
25
|
#
|
26
|
-
# @option
|
27
|
-
# amount of money should be rounded when using infinite_precision
|
26
|
+
# @option rules [Boolean] :rounded_infinite_precision (false) Whether the
|
27
|
+
# amount of money should be rounded when using {infinite_precision}
|
28
28
|
#
|
29
29
|
# @example
|
30
30
|
# Money.us_dollar(100.1).format #=> "$1.001"
|
31
31
|
# Money.us_dollar(100.1).format(:rounded_infinite_precision => true) #=> "$1"
|
32
32
|
# Money.us_dollar(100.9).format(:rounded_infinite_precision => true) #=> "$1.01"
|
33
33
|
#
|
34
|
-
# @option
|
34
|
+
# @option rules [Boolean] :no_cents (false) Whether cents should be omitted.
|
35
35
|
#
|
36
36
|
# @example
|
37
37
|
# Money.ca_dollar(100).format(:no_cents => true) #=> "$1"
|
38
38
|
# Money.ca_dollar(599).format(:no_cents => true) #=> "$5"
|
39
39
|
#
|
40
|
-
# @option
|
40
|
+
# @option rules [Boolean] :no_cents_if_whole (false) Whether cents should be
|
41
41
|
# omitted if the cent value is zero
|
42
42
|
#
|
43
43
|
# @example
|
44
44
|
# Money.ca_dollar(10000).format(:no_cents_if_whole => true) #=> "$100"
|
45
45
|
# Money.ca_dollar(10034).format(:no_cents_if_whole => true) #=> "$100.34"
|
46
46
|
#
|
47
|
-
# @option
|
47
|
+
# @option rules [Boolean, String, nil] :symbol (true) Whether a money symbol
|
48
48
|
# should be prepended to the result string. The default is true. This method
|
49
49
|
# attempts to pick a symbol that's suitable for the given currency.
|
50
50
|
#
|
@@ -75,10 +75,10 @@ class Money
|
|
75
75
|
# Money.new(10000000, "INR").format(:south_asian_number_formatting => true) #=> "1,00,000.00"
|
76
76
|
# Money.new(10000000).format(:south_asian_number_formatting => true) #=> "$1,00,000.00"
|
77
77
|
#
|
78
|
-
# @option
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
78
|
+
# @option rules [Boolean, nil] :symbol_before_without_space (true) Whether
|
79
|
+
# a space between the money symbol and the amount should be inserted when
|
80
|
+
# +:symbol_position+ is +:before+. The default is true (meaning no space). Ignored
|
81
|
+
# if +:symbol+ is false or +:symbol_position+ is not +:before+.
|
82
82
|
#
|
83
83
|
# @example
|
84
84
|
# # Default is to not insert a space.
|
@@ -90,10 +90,10 @@ class Money
|
|
90
90
|
# # If set to false, will insert a space.
|
91
91
|
# Money.new(100, "USD").format(:symbol_before_without_space => false) #=> "$ 1.00"
|
92
92
|
#
|
93
|
-
# @option
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
93
|
+
# @option rules [Boolean, nil] :symbol_after_without_space (false) Whether
|
94
|
+
# a space between the amount and the money symbol should be inserted when
|
95
|
+
# +:symbol_position+ is +:after+. The default is false (meaning space). Ignored
|
96
|
+
# if +:symbol+ is false or +:symbol_position+ is not +:after+.
|
97
97
|
#
|
98
98
|
# @example
|
99
99
|
# # Default is to insert a space.
|
@@ -102,7 +102,7 @@ class Money
|
|
102
102
|
# # If set to true, will not insert a space.
|
103
103
|
# Money.new(100, "USD").format(:symbol_position => :after, :symbol_after_without_space => true) #=> "1.00$"
|
104
104
|
#
|
105
|
-
# @option
|
105
|
+
# @option rules [Boolean, String, nil] :decimal_mark (true) Whether the
|
106
106
|
# currency should be separated by the specified character or '.'
|
107
107
|
#
|
108
108
|
# @example
|
@@ -113,7 +113,7 @@ class Money
|
|
113
113
|
# # to "." as decimal_mark.
|
114
114
|
# Money.new(100, "FOO").format #=> "$1.00"
|
115
115
|
#
|
116
|
-
# @option
|
116
|
+
# @option rules [Boolean, String, nil] :thousands_separator (true) Whether
|
117
117
|
# the currency should be delimited by the specified character or ','
|
118
118
|
#
|
119
119
|
# @example
|
@@ -129,14 +129,14 @@ class Money
|
|
129
129
|
# # default to "," as thousands_separator.
|
130
130
|
# Money.new(100000, "FOO").format #=> "$1,000.00"
|
131
131
|
#
|
132
|
-
# @option
|
132
|
+
# @option rules [Boolean] :html (false) Whether the currency should be
|
133
133
|
# HTML-formatted. Only useful in combination with +:with_currency+.
|
134
134
|
#
|
135
135
|
# @example
|
136
|
-
#
|
137
|
-
#
|
136
|
+
# Money.ca_dollar(570).format(:html => true, :with_currency => true)
|
137
|
+
# #=> "$5.70 <span class=\"currency\">CAD</span>"
|
138
138
|
#
|
139
|
-
# @option
|
139
|
+
# @option rules [Boolean] :sign_before_symbol (false) Whether the sign should be
|
140
140
|
# before the currency symbol.
|
141
141
|
#
|
142
142
|
# @example
|
@@ -145,7 +145,7 @@ class Money
|
|
145
145
|
# Money.new(-100, "GBP").format(:sign_before_symbol => false) #=> "£-1.00"
|
146
146
|
# Money.new(-100, "GBP").format #=> "£-1.00"
|
147
147
|
#
|
148
|
-
# @option
|
148
|
+
# @option rules [Boolean] :sign_positive (false) Whether positive numbers should be
|
149
149
|
# signed, too.
|
150
150
|
#
|
151
151
|
# @example
|
@@ -156,7 +156,7 @@ class Money
|
|
156
156
|
# Money.new(100, "GBP").format(:sign_positive => false, :sign_before_symbol => false) #=> "£1.00"
|
157
157
|
# Money.new(100, "GBP").format #=> "£+1.00"
|
158
158
|
#
|
159
|
-
# @option
|
159
|
+
# @option rules [Boolean] :disambiguate (false) Prevents the result from being ambiguous
|
160
160
|
# due to equal symbols for different currencies. Uses the `disambiguate_symbol`.
|
161
161
|
#
|
162
162
|
# @example
|
@@ -165,21 +165,21 @@ class Money
|
|
165
165
|
# Money.new(10000, "USD").format(:disambiguate => true) #=> "$100.00"
|
166
166
|
# Money.new(10000, "CAD").format(:disambiguate => true) #=> "C$100.00"
|
167
167
|
#
|
168
|
-
# @option
|
168
|
+
# @option rules [Boolean] :html_wrap_symbol (false) Wraps the currency symbol
|
169
169
|
# in a html <span> tag.
|
170
170
|
#
|
171
171
|
# @example
|
172
172
|
# Money.new(10000, "USD").format(:disambiguate => false)
|
173
173
|
# #=> "<span class=\"currency_symbol\">$100.00</span>
|
174
174
|
#
|
175
|
-
# @option
|
175
|
+
# @option rules [Symbol] :symbol_position (:before) `:before` if the currency
|
176
176
|
# symbol goes before the amount, `:after` if it goes after.
|
177
177
|
#
|
178
178
|
# @example
|
179
179
|
# Money.new(10000, "USD").format(:symbol_position => :before) #=> "$100.00"
|
180
180
|
# Money.new(10000, "USD").format(:symbol_position => :after) #=> "100.00 $"
|
181
181
|
#
|
182
|
-
# @option
|
182
|
+
# @option rules [Boolean] :translate (true) `true` Checks for custom
|
183
183
|
# symbol definitions using I18n.
|
184
184
|
#
|
185
185
|
# @example
|
@@ -195,9 +195,9 @@ class Money
|
|
195
195
|
# Money.new(89000, :btc).format(:drop_trailing_zeros => true) #=> B⃦0.00089
|
196
196
|
# Money.new(110, :usd).format(:drop_trailing_zeros => true) #=> $1.1
|
197
197
|
#
|
198
|
-
# Note that the default rules can be defined through
|
198
|
+
# Note that the default rules can be defined through {Money.default_formatting_rules} hash.
|
199
199
|
#
|
200
|
-
# @see
|
200
|
+
# @see Money.default_formatting_rules Money.default_formatting_rules for more information.
|
201
201
|
def format(*rules)
|
202
202
|
# support for old format parameters
|
203
203
|
rules = normalize_formatting_rules(rules)
|
@@ -205,6 +205,7 @@ class Money
|
|
205
205
|
rules = default_formatting_rules.merge(rules)
|
206
206
|
rules = localize_formatting_rules(rules)
|
207
207
|
rules = translate_formatting_rules(rules) if rules[:translate]
|
208
|
+
escaped_decimal_mark = Regexp.escape(decimal_mark)
|
208
209
|
|
209
210
|
if fractional == 0
|
210
211
|
if rules[:display_free].respond_to?(:to_str)
|
@@ -236,9 +237,9 @@ class Money
|
|
236
237
|
|
237
238
|
# Inspiration: https://github.com/rails/rails/blob/16214d1108c31174c94503caced3855b0f6bad95/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb#L72-L79
|
238
239
|
if rules[:drop_trailing_zeros]
|
239
|
-
escaped_decimal_mark = Regexp.escape(decimal_mark)
|
240
240
|
formatted = formatted.sub(/(#{escaped_decimal_mark})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_decimal_mark}\z/, '')
|
241
241
|
end
|
242
|
+
has_decimal_value = !!(formatted =~ /#{escaped_decimal_mark}/)
|
242
243
|
|
243
244
|
thousands_separator_value = thousands_separator
|
244
245
|
# Determine thousands_separator
|
@@ -275,7 +276,7 @@ class Money
|
|
275
276
|
formatted="#{sign_before}#{sign}#{formatted}"
|
276
277
|
end
|
277
278
|
|
278
|
-
apply_decimal_mark_from_rules(formatted, rules)
|
279
|
+
apply_decimal_mark_from_rules(formatted, rules) if has_decimal_value
|
279
280
|
|
280
281
|
if rules[:with_currency]
|
281
282
|
formatted << " "
|
data/lib/money/version.rb
CHANGED
data/spec/currency_spec.rb
CHANGED
@@ -291,7 +291,7 @@ class Money
|
|
291
291
|
|
292
292
|
describe "#inspect" do
|
293
293
|
it "works as documented" do
|
294
|
-
expect(Currency.new(:usd).inspect).to eq %Q{#<Money::Currency id: usd, priority: 1, symbol_first: true, thousands_separator: ,, html_entity: $, decimal_mark: ., name: United States Dollar, symbol: $, subunit_to_unit: 100, exponent: 2
|
294
|
+
expect(Currency.new(:usd).inspect).to eq %Q{#<Money::Currency id: usd, priority: 1, symbol_first: true, thousands_separator: ,, html_entity: $, decimal_mark: ., name: United States Dollar, symbol: $, subunit_to_unit: 100, exponent: 2, iso_code: USD, iso_numeric: 840, subunit: Cent, smallest_denomination: 1>}
|
295
295
|
end
|
296
296
|
end
|
297
297
|
|
@@ -45,6 +45,19 @@ describe Money do
|
|
45
45
|
expect(Money.new(2_50, "USD")).not_to eq klass.new(3_00, "USD")
|
46
46
|
expect(Money.new(1_00, "GBP")).not_to eq klass.new(1_00, "USD")
|
47
47
|
end
|
48
|
+
|
49
|
+
it 'allows comparison with zero' do
|
50
|
+
expect(Money.new(0, :usd)).to eq 0
|
51
|
+
expect(Money.new(0, :usd)).to eq 0.0
|
52
|
+
expect(Money.new(0, :usd)).to eq BigDecimal.new(0)
|
53
|
+
expect(Money.new(1, :usd)).to_not eq 0
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'raises error for non-zero numerics' do
|
57
|
+
expect { Money.new(1_00, :usd) == 1 }.to raise_error ArgumentError
|
58
|
+
expect { Money.new(1_00, :usd) == -2.0 }.to raise_error ArgumentError
|
59
|
+
expect { Money.new(1_00, :usd) == Float::INFINITY }.to raise_error ArgumentError
|
60
|
+
end
|
48
61
|
end
|
49
62
|
|
50
63
|
describe "#eql?" do
|
@@ -108,17 +121,19 @@ describe Money do
|
|
108
121
|
expect(Money.new(1_00) <=> klass.new(2_00)).to be < 0
|
109
122
|
end
|
110
123
|
|
111
|
-
it "
|
124
|
+
it "returns nill when comparing with an object that doesn't inherit from Money" do
|
112
125
|
expect(Money.new(1_00) <=> 100).to be_nil
|
113
|
-
|
114
126
|
expect(Money.new(1_00) <=> Object.new).to be_nil
|
115
|
-
|
116
127
|
expect(Money.new(1_00) <=> Class).to be_nil
|
117
|
-
|
118
128
|
expect(Money.new(1_00) <=> Kernel).to be_nil
|
119
|
-
|
120
129
|
expect(Money.new(1_00) <=> /foo/).to be_nil
|
121
130
|
end
|
131
|
+
|
132
|
+
it 'compares with numeric 0' do
|
133
|
+
expect(Money.usd(1) < 0).to eq false
|
134
|
+
expect(Money.usd(1) > 0.0).to eq true
|
135
|
+
expect(Money.usd(0) >= 0.0).to eq true
|
136
|
+
end
|
122
137
|
end
|
123
138
|
|
124
139
|
describe "#positive?" do
|
@@ -205,15 +220,15 @@ describe Money do
|
|
205
220
|
end
|
206
221
|
|
207
222
|
it "does not multiply Money by Money (same currency)" do
|
208
|
-
expect { Money.new(
|
223
|
+
expect { Money.new(10, :USD) * Money.new(4, :USD) }.to raise_error(TypeError)
|
209
224
|
end
|
210
225
|
|
211
226
|
it "does not multiply Money by Money (different currency)" do
|
212
|
-
expect { Money.new(
|
227
|
+
expect { Money.new(10, :USD) * Money.new(4, :EUR) }.to raise_error(TypeError)
|
213
228
|
end
|
214
229
|
|
215
230
|
it "does not multiply Money by an object which is NOT a number" do
|
216
|
-
expect { Money.new(
|
231
|
+
expect { Money.new(10, :USD) * 'abc' }.to raise_error(TypeError)
|
217
232
|
end
|
218
233
|
|
219
234
|
it "preserves the class in the result when using a subclass of Money" do
|
@@ -375,8 +390,8 @@ describe Money do
|
|
375
390
|
it "calculates division and modulo with Fixnum" do
|
376
391
|
ts = [
|
377
392
|
{:a => Money.new( 13, :USD), :b => 4, :c => [Money.new( 3, :USD), Money.new( 1, :USD)]},
|
378
|
-
{:a => Money.new( 13, :USD), :b => -4, :c => [Money.new(-
|
379
|
-
{:a => Money.new(-13, :USD), :b => 4, :c => [Money.new(-
|
393
|
+
{:a => Money.new( 13, :USD), :b => -4, :c => [Money.new(-4, :USD), Money.new(-3, :USD)]},
|
394
|
+
{:a => Money.new(-13, :USD), :b => 4, :c => [Money.new(-4, :USD), Money.new( 3, :USD)]},
|
380
395
|
{:a => Money.new(-13, :USD), :b => -4, :c => [Money.new( 3, :USD), Money.new(-1, :USD)]},
|
381
396
|
]
|
382
397
|
ts.each do |t|
|
@@ -607,23 +622,27 @@ describe Money do
|
|
607
622
|
it "correctly handles <=>" do
|
608
623
|
expect {
|
609
624
|
2 < Money.new(2, 'USD')
|
610
|
-
}.to raise_exception(
|
625
|
+
}.to raise_exception(ArgumentError)
|
611
626
|
|
612
627
|
expect {
|
613
628
|
2 > Money.new(2, 'USD')
|
614
|
-
}.to raise_exception(
|
629
|
+
}.to raise_exception(ArgumentError)
|
615
630
|
|
616
631
|
expect {
|
617
632
|
2 <= Money.new(2, 'USD')
|
618
|
-
}.to raise_exception(
|
633
|
+
}.to raise_exception(ArgumentError)
|
619
634
|
|
620
635
|
expect {
|
621
636
|
2 >= Money.new(2, 'USD')
|
622
|
-
}.to raise_exception(
|
637
|
+
}.to raise_exception(ArgumentError)
|
623
638
|
|
624
|
-
expect
|
625
|
-
|
626
|
-
|
639
|
+
expect(2 <=> Money.new(2, 'USD')).to be_nil
|
640
|
+
end
|
641
|
+
|
642
|
+
it 'compares with numeric 0' do
|
643
|
+
expect(0 < Money.usd(1)).to eq true
|
644
|
+
expect(0.0 > Money.usd(1)).to eq false
|
645
|
+
expect(0.0 >= Money.usd(0)).to eq true
|
627
646
|
end
|
628
647
|
|
629
648
|
it "raises exceptions for all numeric types, not just Integer" do
|
@@ -110,6 +110,16 @@ describe Money, "formatting" do
|
|
110
110
|
expect(money.format(:translate => true)).to eq("CAD$0.00")
|
111
111
|
end
|
112
112
|
end
|
113
|
+
|
114
|
+
context "with overridden i18n settings" do
|
115
|
+
it "should respect explicit overriding of thousands_separator/delimiter when decimal_mark/separator collide and there’s no decimal component for currencies that have no subunit" do
|
116
|
+
expect(Money.new(300_000, 'ISK').format(:thousands_separator => ".", decimal_mark: ',')).to eq "kr300.000"
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should respect explicit overriding of thousands_separator/delimiter when decimal_mark/separator collide and there’s no decimal component for currencies with subunits that drop_trailing_zeros" do
|
120
|
+
expect(Money.new(300_000, 'USD').format(:thousands_separator => ".", decimal_mark: ',', drop_trailing_zeros: true)).to eq "$3.000"
|
121
|
+
end
|
122
|
+
end
|
113
123
|
end
|
114
124
|
|
115
125
|
describe "#format" do
|
@@ -418,6 +428,20 @@ describe Money, "formatting" do
|
|
418
428
|
it "defaults to ',' if currency isn't recognized" do
|
419
429
|
expect(Money.new(100000, "ZWD").format).to eq "$1,000.00"
|
420
430
|
end
|
431
|
+
|
432
|
+
context "without i18n" do
|
433
|
+
before { Money.use_i18n = false }
|
434
|
+
|
435
|
+
it "should respect explicit overriding of thousands_separator/delimiter when decimal_mark/separator collide and there’s no decimal component for currencies that have no subunit" do
|
436
|
+
expect(Money.new(300_000, 'ISK').format(:thousands_separator => ",", decimal_mark: '.')).to eq "kr300,000"
|
437
|
+
end
|
438
|
+
|
439
|
+
it "should respect explicit overriding of thousands_separator/delimiter when decimal_mark/separator collide and there’s no decimal component for currencies with subunits that drop_trailing_zeros" do
|
440
|
+
expect(Money.new(300_000, 'USD').format(:thousands_separator => ".", decimal_mark: ',', drop_trailing_zeros: true)).to eq "$3.000"
|
441
|
+
end
|
442
|
+
|
443
|
+
after { Money.use_i18n = true}
|
444
|
+
end
|
421
445
|
end
|
422
446
|
|
423
447
|
describe ":thousands_separator and :decimal_mark option" do
|
@@ -435,7 +459,7 @@ describe Money, "formatting" do
|
|
435
459
|
|
436
460
|
specify "should fallback to symbol if entity is not available" do
|
437
461
|
string = Money.new(570, 'DKK').format(:html => true)
|
438
|
-
expect(string).to eq "5,70 kr"
|
462
|
+
expect(string).to eq "5,70 kr."
|
439
463
|
end
|
440
464
|
end
|
441
465
|
|
@@ -662,7 +686,7 @@ describe Money, "formatting" do
|
|
662
686
|
it "returns ambiguous signs when disambiguate is not set" do
|
663
687
|
expect(Money.new(1999_98, "USD").format).to eq("$1,999.98")
|
664
688
|
expect(Money.new(1999_98, "CAD").format).to eq("$1,999.98")
|
665
|
-
expect(Money.new(1999_98, "DKK").format).to eq("1.999,98 kr")
|
689
|
+
expect(Money.new(1999_98, "DKK").format).to eq("1.999,98 kr.")
|
666
690
|
expect(Money.new(1999_98, "NOK").format).to eq("1.999,98 kr")
|
667
691
|
expect(Money.new(1999_98, "SEK").format).to eq("1 999,98 kr")
|
668
692
|
end
|
@@ -670,13 +694,13 @@ describe Money, "formatting" do
|
|
670
694
|
it "returns ambiguous signs when disambiguate is false" do
|
671
695
|
expect(Money.new(1999_98, "USD").format(disambiguate: false)).to eq("$1,999.98")
|
672
696
|
expect(Money.new(1999_98, "CAD").format(disambiguate: false)).to eq("$1,999.98")
|
673
|
-
expect(Money.new(1999_98, "DKK").format(disambiguate: false)).to eq("1.999,98 kr")
|
697
|
+
expect(Money.new(1999_98, "DKK").format(disambiguate: false)).to eq("1.999,98 kr.")
|
674
698
|
expect(Money.new(1999_98, "NOK").format(disambiguate: false)).to eq("1.999,98 kr")
|
675
699
|
expect(Money.new(1999_98, "SEK").format(disambiguate: false)).to eq("1 999,98 kr")
|
676
700
|
end
|
677
701
|
|
678
702
|
it "returns disambiguate signs when disambiguate: true" do
|
679
|
-
expect(Money.new(1999_98, "USD").format(disambiguate: true)).to eq("$1,999.98")
|
703
|
+
expect(Money.new(1999_98, "USD").format(disambiguate: true)).to eq("US$1,999.98")
|
680
704
|
expect(Money.new(1999_98, "CAD").format(disambiguate: true)).to eq("C$1,999.98")
|
681
705
|
expect(Money.new(1999_98, "DKK").format(disambiguate: true)).to eq("1.999,98 DKK")
|
682
706
|
expect(Money.new(1999_98, "NOK").format(disambiguate: true)).to eq("1.999,98 NOK")
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: money
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.7.
|
4
|
+
version: 6.7.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: 2016-
|
11
|
+
date: 2016-05-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: i18n
|
@@ -195,7 +195,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
195
195
|
version: '0'
|
196
196
|
requirements: []
|
197
197
|
rubyforge_project:
|
198
|
-
rubygems_version: 2.
|
198
|
+
rubygems_version: 2.5.1
|
199
199
|
signing_key:
|
200
200
|
specification_version: 4
|
201
201
|
summary: A Ruby Library for dealing with money and currency conversion.
|
@@ -212,4 +212,3 @@ test_files:
|
|
212
212
|
- spec/money_spec.rb
|
213
213
|
- spec/rates_store/memory_spec.rb
|
214
214
|
- spec/spec_helper.rb
|
215
|
-
has_rdoc:
|