money 6.7.0 → 6.7.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 +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:
|