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 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: