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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9cffd9f173701f8599fae9244a9de6b4aef0a95f
4
- data.tar.gz: 30080c0c9743507a615598ab80c8235d7313f769
3
+ metadata.gz: cf8496911c1ac6ef2fdb34ad3e0b9f458bf6e836
4
+ data.tar.gz: 70ed919de03069d7a92883d46b890d60194eae1a
5
5
  SHA512:
6
- metadata.gz: 60307b13ad66a684ff833d58441093b58eb7730ccb108b6804a68f935a91dcc0921153e7c2ce0c8543af0851239b4c7289dcc23f71c60361e875d0e71f5f26fb
7
- data.tar.gz: b435062afea1d2a798502354347b757dc5c4f84a835449d39d411c9ea6400e52fa99eeeded5322a92e00b0956d41d9d3003134b25f49c72b18b4fa1f195acf01
6
+ metadata.gz: dabd711f4ba2737ee735c8e29569b56d0650686802fd56e27d0df34afd26865bfd11630deacb64cb74d22c7b97a25fd8a4bfa49ed3dcfa5195b8bf324edd2a53
7
+ data.tar.gz: 03e66b3f5639b64baf44082e075e6c2e275ce8bd9911cb0e1152ccf4449d840043b9a233a81b51ef6cf66783986e600a3d7c57840287a398f5d52e45f56bbb4f
@@ -7,6 +7,14 @@ rvm:
7
7
  - 2.2.4
8
8
  - 2.3.0
9
9
  - rbx-2
10
+ - jruby-9.0.4.0
11
+ - ruby-head
12
+ - jruby-head
13
+ matrix:
14
+ allow_failures:
15
+ - rvm: ruby-head
16
+ - rvm: jruby-head
17
+ fast_finish: true
10
18
  script: bundle exec rspec spec
11
19
  notifications:
12
20
  email:
@@ -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 an high level of
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 a `Float`) by
206
+ information. You can find the exponent (as an `Integer`) by
207
207
 
208
208
  ``` ruby
209
- Money::Currency.new("USD").exponent # => 2.0
210
- Money::Currency.new("JPY").exponent # => 0.0
211
- Money::Currency.new("MGA").exponent # => 0.6989700043360189
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
- - [money-json-rates](https://github.com/askuratovsky/money-json-rates)
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)
@@ -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 F",
2307
- "alternate_symbols": ["Bs.F", "Bs"],
2307
+ "symbol": "Bs",
2308
+ "alternate_symbols": ["Bs.F"],
2308
2309
  "subunit": "Céntimo",
2309
2310
  "subunit_to_unit": 100,
2310
2311
  "symbol_first": true,
@@ -374,7 +374,7 @@ class Money
374
374
  id.to_s.upcase.to_sym
375
375
  end
376
376
 
377
- # Conversation to +self+.
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 number of digits after the decimal separator.
395
+ # Returns the relation between subunit and unit as a base 10 exponent.
396
396
  #
397
- # @return [Float]
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. Common ones pre-cached.
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
@@ -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, Money::Arithmetic, Money::Formatting
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 Dollar currency the fractional unit is cents, and
38
- # there are 100 cents in one US Dollar. So given the Money representation of
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 Dinar. In this case the fractional
42
- # unit is the Fils and there 1000 Fils to one Kuwaiti Dinar. So given the
43
- # Money representation of one Kuwaiti Dinar, the fractional interpretation is
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 infintie_precision is true
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 francs (CHF), the smallest possible amount of cash value is
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 everytime
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 temporatly change it. It will
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 american dollars.
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 canadian dollar.
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 <=>(other_money)
61
- return nil unless other_money.is_a?(Money)
62
- if fractional != 0 && other_money.fractional != 0 && currency != other_money.currency
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
- fractional <=> other_money.fractional
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
- nil
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 [ArgumentError] If +value+ is NOT a number.
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 ArgumentError, "Can't multiply a #{self.class.name} by a #{value.class.name}'s value"
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
- if self.class.infinite_precision
216
- quotient, remainder = fractional.divmod(as_d(val))
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
- [CoercedNumber.new(other), self]
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 *rules [Boolean, String] :display_free (false) Whether a zero
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 *rules [Boolean] :with_currency (false) Whether the currency name
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 *rules [Boolean] :rounded_infinite_precision (false) Whether the
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 *rules [Boolean] :no_cents (false) Whether cents should be omitted.
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 *rules [Boolean] :no_cents_if_whole (false) Whether cents should be
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 *rules [Boolean, String, nil] :symbol (true) Whether a money symbol
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 *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+.
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 *rules [Boolean, nil] :symbol_after_without_space (false) Whether
94
- # a space between the 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+.
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 *rules [Boolean, String, nil] :decimal_mark (true) Whether the
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 *rules [Boolean, String, nil] :thousands_separator (true) Whether
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 *rules [Boolean] :html (false) Whether the currency should be
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
- # s = Money.ca_dollar(570).format(:html => true, :with_currency => true)
137
- # s #=> "$5.70 <span class=\"currency\">CAD</span>"
136
+ # Money.ca_dollar(570).format(:html => true, :with_currency => true)
137
+ # #=> "$5.70 <span class=\"currency\">CAD</span>"
138
138
  #
139
- # @option *rules [Boolean] :sign_before_symbol (false) Whether the sign should be
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 *rules [Boolean] :sign_positive (false) Whether positive numbers should be
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 *rules [Boolean] :disambiguate (false) Prevents the result from being ambiguous
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 *rules [Boolean] :html_wrap_symbol (false) Wraps the currency symbol
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 *rules [Symbol] :symbol_position (:before) `:before` if the currency
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 *rules [Boolean] :translate (true) `true` Checks for custom
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 +Money.default_formatting_rules+ hash.
198
+ # Note that the default rules can be defined through {Money.default_formatting_rules} hash.
199
199
  #
200
- # @see +Money.default_formatting_rules+ for more information.
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 << " "
@@ -1,3 +1,3 @@
1
1
  class Money
2
- VERSION = "6.7.0"
2
+ VERSION = "6.7.1"
3
3
  end
@@ -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.0, iso_code: USD, iso_numeric: 840, subunit: Cent, smallest_denomination: 1>}
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 "raises TypeError when used to compare with an object that doesn't inherit from Money" do
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( 10, :USD) * Money.new( 4, :USD) }.to raise_error(ArgumentError)
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( 10, :USD) * Money.new( 4, :EUR) }.to raise_error(ArgumentError)
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( 10, :USD) * 'abc' }.to raise_error(ArgumentError)
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(-3, :USD), Money.new(-3, :USD)]},
379
- {:a => Money.new(-13, :USD), :b => 4, :c => [Money.new(-3, :USD), Money.new( 3, :USD)]},
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(TypeError)
625
+ }.to raise_exception(ArgumentError)
611
626
 
612
627
  expect {
613
628
  2 > Money.new(2, 'USD')
614
- }.to raise_exception(TypeError)
629
+ }.to raise_exception(ArgumentError)
615
630
 
616
631
  expect {
617
632
  2 <= Money.new(2, 'USD')
618
- }.to raise_exception(TypeError)
633
+ }.to raise_exception(ArgumentError)
619
634
 
620
635
  expect {
621
636
  2 >= Money.new(2, 'USD')
622
- }.to raise_exception(TypeError)
637
+ }.to raise_exception(ArgumentError)
623
638
 
624
- expect {
625
- 2 <=> Money.new(2, 'USD')
626
- }.to raise_exception(TypeError)
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.0
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-01-15 00:00:00.000000000 Z
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.4.5.1
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: