money 6.0.0.pre2 → 6.0.0.pre3

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: db3de84c7fca4fad50f28617c05aa96b0a8cd2f9
4
- data.tar.gz: 3a22bb6c242e6b96660f78add455217a5eac3e5d
3
+ metadata.gz: b9dae4831f4901cf906ae3d6f155c9bac6e3f67f
4
+ data.tar.gz: 43718a7d7edfce6329053cd90a7b61ec2d4d3a78
5
5
  SHA512:
6
- metadata.gz: c55f42b4d76f62ba787b54ef929d202f1edd873d9abc7139fc1cb8e5276f59263d293f4b1c316e35cf814493c211598adee7812b83d23f60e51d276d7bbe6919
7
- data.tar.gz: c6b9250d167858e374ab2ae18da527aa4d3c06017a60cb8574190da4afca629020bdf18d4e0005abd2fd48b80dbced701b61e16bce81dbf78aee87b83933437a
6
+ metadata.gz: a13f5e9078a642608bc4d224639b27ca74b44952c6cba8790515534c5e09d50d77eba86c4f0fc0540fb4d840cf8b9c3cef6ef8af6a06fb5c81740850862e971e
7
+ data.tar.gz: 652d159f7d083c9975f15ad14f3f92cd2aea19c475cacc3dead90711771d5ed04b32e96a66b97b08ee3153816670037088a8ad8fb49f2c5b552b8336a2dde2af
data/CHANGELOG.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Changelog
2
2
 
3
3
  ## master
4
+ - New option :sign_positive to add a + sign to positive numbers
5
+ - Only allow to multiply a money by a number (int, float)
4
6
  - Fix typo
5
7
  - Wrap the currency symbol in a span if :html is specified in the rules
6
8
  - Added Money::Currency.all method
@@ -9,6 +11,14 @@
9
11
  - Works on Ruby 1.8.7
10
12
  - Update deps
11
13
  - Depreciate Money.parse
14
+ - Passing :symbol => false when formatting 'JPY' currency in :ja locale
15
+ will work as expected
16
+ - Divide now obeys the specified rounding mode
17
+ - Add Money#round method. This is helpful when working in infinite_precision mode and would like to perform rounding at specific points in your work flow.
18
+ - In infinite precision mode, deserialized Money objects no longer return Float values from the `fractional` method.
19
+ - Changed `thousands_separator` for Swedish Krona from dot to blank space.
20
+ - Allow mathematical operations with first argument being not an instance of Money (eg. 2 * money instead of money * 2).
21
+ - Money#dollars and Money#amount methods return numbers of type BigDecimal.
12
22
 
13
23
  ## 5.1.1
14
24
 
data/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/money.png)](http://badge.fury.io/rb/money) [![Build Status](https://travis-ci.org/RubyMoney/money.png?branch=master)](https://travis-ci.org/RubyMoney/money) [![Code Climate](https://codeclimate.com/github/RubyMoney/money.png)](https://codeclimate.com/github/RubyMoney/money)
4
4
 
5
+ :warning: Please read the [migration notes](#migration-notes) before upgrading to a new major version.
6
+
5
7
  ## Contributing
6
8
 
7
9
  See the [Contribution Guidelines](https://github.com/RubyMoney/money/blob/master/CONTRIBUTING.md)
@@ -249,9 +251,26 @@ implementations.
249
251
  - [nbrb_currency](https://github.com/slbug/nbrb_currency)
250
252
  - [money-open-exchange-rates](https://github.com/spk/money-open-exchange-rates)
251
253
  - [money-historical-bank](https://github.com/atwam/money-historical-bank)
254
+ - [russian_central_bank](https://github.com/rmustafin/russian_central_bank)
252
255
 
253
256
  ## Ruby on Rails
254
257
 
255
258
  To integrate money in a Rails application use [money-rails](http://github.com/RubyMoney/money-rails).
256
259
 
257
260
  For deprecated methods of integrating with Rails, check [the wiki](https://github.com/RubyMoney/money/wiki).
261
+
262
+ ## Migration Notes
263
+
264
+ #### Version 6.0.0.pre3
265
+
266
+ - The `Money#dollars` and `Money#amount` methods now return instances of
267
+ `BigDecimal` rather than `Float`. We should avoid representing monetary
268
+ values with floating point types so to avoid a whole class of errors relating
269
+ to lack of precision. There are two migration options for this change:
270
+ * The first is to test your application and where applicable update the
271
+ application to accept a `BigDecimal` return value. This is the recommended
272
+ path.
273
+ * The second is to migrate from the `#amount` and `#dollars` methods to use
274
+ the `#to_f` method instead. This option should only be used where `Float`
275
+ is the desired type and nothing else will do for your application's
276
+ requirements.
@@ -1731,7 +1731,7 @@
1731
1731
  "symbol_first": false,
1732
1732
  "html_entity": "",
1733
1733
  "decimal_mark": ",",
1734
- "thousands_separator": ".",
1734
+ "thousands_separator": " ",
1735
1735
  "iso_numeric": "752"
1736
1736
  },
1737
1737
  "sgd": {
data/lib/money/money.rb CHANGED
@@ -22,16 +22,27 @@ class Money
22
22
  #
23
23
  # @return [Integer]
24
24
  def fractional
25
+ # Ensure we have a BigDecimal. If the Money object is created
26
+ # from YAML, @fractional can end up being set to a Float.
27
+ fractional = as_d(@fractional)
28
+
25
29
  if self.class.infinite_precision
26
- @fractional
30
+ fractional
31
+ else
32
+ fractional.round(0, self.class.rounding_mode).to_i
33
+ end
34
+ end
35
+
36
+ def as_d(num)
37
+ if num.is_a?(Rational)
38
+ num.to_d(self.class.conversion_precision)
39
+ elsif num.respond_to?(:to_d)
40
+ num.to_d
27
41
  else
28
- # If the Money object is created from a serialized YAML string,
29
- # @fractional can end up being set to a Float. We need to ensure
30
- # it is BigDecimal before calling #round with two paramers.
31
- # Float class only provides #round with 0 or 1 parameter.
32
- BigDecimal.new(@fractional.to_s, 0).round(0, self.class.rounding_mode).to_i
42
+ BigDecimal.new(num.to_s)
33
43
  end
34
44
  end
45
+ private :as_d
35
46
 
36
47
  # The currency the money is in.
37
48
  #
@@ -238,13 +249,7 @@ class Money
238
249
  # @see Money.new_with_dollars
239
250
  #
240
251
  def initialize(fractional, currency = Money.default_currency, bank = Money.default_bank)
241
- @fractional = if fractional.is_a?(Rational)
242
- fractional.to_d(self.class.conversion_precision)
243
- elsif fractional.respond_to?(:to_d)
244
- fractional.to_d
245
- else
246
- BigDecimal.new(fractional.to_s)
247
- end
252
+ @fractional = as_d(fractional)
248
253
  @currency = Currency.wrap(currency)
249
254
  @bank = bank
250
255
  end
@@ -255,14 +260,14 @@ class Money
255
260
  #
256
261
  # Synonym of #amount
257
262
  #
258
- # @return [Float]
263
+ # @return [BigDecimal]
259
264
  #
260
265
  # @example
261
266
  # Money.new(100).dollars # => 1.0
262
267
  # Money.new_with_dollars(1).dollar # => 1.0
263
268
  #
264
269
  # @see #amount
265
- # @see #to_f
270
+ # @see #to_d
266
271
  # @see #cents
267
272
  #
268
273
  def dollars
@@ -271,17 +276,17 @@ class Money
271
276
 
272
277
  # Returns the numerical value of the money
273
278
  #
274
- # @return [Float]
279
+ # @return [BigDecimal]
275
280
  #
276
281
  # @example
277
282
  # Money.new(100).amount # => 1.0
278
283
  # Money.new_with_amount(1).amount # => 1.0
279
284
  #
280
- # @see #to_f
285
+ # @see #to_d
281
286
  # @see #fractional
282
287
  #
283
288
  def amount
284
- to_f
289
+ to_d
285
290
  end
286
291
 
287
292
  # Return string representation of currency object
@@ -385,13 +390,13 @@ class Money
385
390
  # @example
386
391
  # Money.us_dollar(100).to_d => BigDecimal.new("1.0")
387
392
  def to_d
388
- BigDecimal.new(fractional.to_s) / BigDecimal.new(currency.subunit_to_unit.to_s)
393
+ as_d(fractional) / as_d(currency.subunit_to_unit)
389
394
  end
390
395
 
391
396
  # Return the amount of money as a float. Floating points cannot guarantee
392
397
  # precision. Therefore, this function should only be used when you no longer
393
398
  # need to represent currency or working with another system that requires
394
- # decimals.
399
+ # floats.
395
400
  #
396
401
  # @return [Float]
397
402
  #
@@ -476,10 +481,7 @@ class Money
476
481
  # Money.new(5, "USD").allocate([0.3,0.7)) #=> [Money.new(2), Money.new(3)]
477
482
  # Money.new(100, "USD").allocate([0.33,0.33,0.33]) #=> [Money.new(34), Money.new(33), Money.new(33)]
478
483
  def allocate(splits)
479
- allocations = splits.inject(BigDecimal("0")) do |sum, n|
480
- n = BigDecimal(n.to_s) unless n.is_a?(BigDecimal)
481
- sum + n
482
- end
484
+ allocations = splits.inject(0) { |sum, n| sum + as_d(n) }
483
485
 
484
486
  if (allocations - BigDecimal("1")) > Float::EPSILON
485
487
  raise ArgumentError, "splits add to more then 100%"
@@ -516,12 +518,12 @@ class Money
516
518
  raise ArgumentError, "need at least one party" if num < 1
517
519
 
518
520
  if self.class.infinite_precision
519
- amt = self.div(BigDecimal(num.to_s))
521
+ amt = div(as_d(num))
520
522
  return 1.upto(num).map{amt}
521
523
  end
522
524
 
523
- low = Money.new(fractional / num, self.currency)
524
- high = Money.new(low.fractional + 1, self.currency)
525
+ low = Money.new(fractional / num, currency)
526
+ high = Money.new(low.fractional + 1, currency)
525
527
 
526
528
  remainder = fractional % num
527
529
  result = []
@@ -533,4 +535,23 @@ class Money
533
535
  result
534
536
  end
535
537
 
538
+ # Round the monetary amount to smallest unit of coinage.
539
+ #
540
+ # This method is only useful when operating with infinite_precision turned
541
+ # on. Without infinite_precision values are rounded to the smallest unit of
542
+ # coinage automatically.
543
+ #
544
+ # @return [Money]
545
+ #
546
+ # @example
547
+ # Money.new(10.1, 'USD').round #=> Money.new(10, 'USD')
548
+ #
549
+ def round(rounding_mode = self.class.rounding_mode)
550
+ if self.class.infinite_precision
551
+ return Money.new(fractional.round(0, rounding_mode), self.currency)
552
+ else
553
+ return self
554
+ end
555
+ end
556
+
536
557
  end
@@ -26,7 +26,7 @@ class Money
26
26
  def ==(other_money)
27
27
  if other_money.respond_to?(:to_money)
28
28
  other_money = other_money.to_money
29
- fractional == other_money.fractional && self.currency == other_money.currency
29
+ fractional == other_money.fractional && currency == other_money.currency
30
30
  else
31
31
  false
32
32
  end
@@ -93,11 +93,8 @@ class Money
93
93
  # @example
94
94
  # Money.new(100) + Money.new(100) #=> #<Money @fractional=200>
95
95
  def +(other_money)
96
- if currency == other_money.currency
97
- Money.new(fractional + other_money.fractional, other_money.currency)
98
- else
99
- Money.new(fractional + other_money.exchange_to(currency).fractional, currency)
100
- end
96
+ other_money = other_money.exchange_to(currency)
97
+ Money.new(fractional + other_money.fractional, currency)
101
98
  end
102
99
 
103
100
  # Returns a new Money object containing the difference between the two
@@ -112,11 +109,8 @@ class Money
112
109
  # @example
113
110
  # Money.new(100) - Money.new(99) #=> #<Money @fractional=1>
114
111
  def -(other_money)
115
- if currency == other_money.currency
116
- Money.new(fractional - other_money.fractional, other_money.currency)
117
- else
118
- Money.new(fractional - other_money.exchange_to(currency).fractional, currency)
119
- end
112
+ other_money = other_money.exchange_to(currency)
113
+ Money.new(fractional - other_money.fractional, currency)
120
114
  end
121
115
 
122
116
  # Multiplies the monetary value with the given number and returns a new
@@ -128,16 +122,16 @@ class Money
128
122
  #
129
123
  # @return [Money] The resulting money.
130
124
  #
131
- # @raise [ArgumentError] If +value+ is a Money instance.
125
+ # @raise [ArgumentError] If +value+ is NOT a number.
132
126
  #
133
127
  # @example
134
128
  # Money.new(100) * 2 #=> #<Money @fractional=200>
135
129
  #
136
130
  def *(value)
137
- if value.is_a?(Money)
138
- raise ArgumentError, "Can't multiply a Money by a Money"
139
- else
131
+ if value.is_a? Numeric
140
132
  Money.new(fractional * value, currency)
133
+ else
134
+ raise ArgumentError, "Can't multiply a Money by a #{value.class.name}'s value"
141
135
  end
142
136
  end
143
137
 
@@ -158,13 +152,9 @@ class Money
158
152
  #
159
153
  def /(value)
160
154
  if value.is_a?(Money)
161
- if currency == value.currency
162
- (fractional / BigDecimal.new(value.fractional.to_s)).to_f
163
- else
164
- (fractional / BigDecimal(value.exchange_to(currency).fractional.to_s)).to_f
165
- end
155
+ fractional / as_d(value.exchange_to(currency).fractional).to_f
166
156
  else
167
- Money.new(fractional / value, currency)
157
+ Money.new(fractional / as_d(value), currency)
168
158
  end
169
159
  end
170
160
 
@@ -193,16 +183,16 @@ class Money
193
183
  # Money.new(100).divmod(Money.new(9)) #=> [11, #<Money @fractional=1>]
194
184
  def divmod(val)
195
185
  if val.is_a?(Money)
196
- a = self.fractional
197
- b = self.currency == val.currency ? val.fractional : val.exchange_to(self.currency).cents
186
+ a = fractional
187
+ b = val.exchange_to(currency).cents
198
188
  q, m = a.divmod(b)
199
- return [q, Money.new(m, self.currency)]
189
+ return [q, Money.new(m, currency)]
200
190
  else
201
191
  if self.class.infinite_precision
202
- q, m = self.fractional.divmod(BigDecimal(val.to_s))
203
- return [Money.new(q, self.currency), Money.new(m, self.currency)]
192
+ q, m = fractional.divmod(as_d(val))
193
+ return [Money.new(q, currency), Money.new(m, currency)]
204
194
  else
205
- return [self.div(val), Money.new(self.fractional.modulo(val), self.currency)]
195
+ return [div(val), Money.new(fractional.modulo(val), currency)]
206
196
  end
207
197
  end
208
198
  end
@@ -217,7 +207,7 @@ class Money
217
207
  # Money.new(100).modulo(9) #=> #<Money @fractional=1>
218
208
  # Money.new(100).modulo(Money.new(9)) #=> #<Money @fractional=1>
219
209
  def modulo(val)
220
- self.divmod(val)[1]
210
+ divmod(val)[1]
221
211
  end
222
212
 
223
213
  # Synonym for +#modulo+.
@@ -228,7 +218,7 @@ class Money
228
218
  #
229
219
  # @see #modulo
230
220
  def %(val)
231
- self.modulo(val)
221
+ modulo(val)
232
222
  end
233
223
 
234
224
  # If different signs +self.modulo(val) - val+ otherwise +self.modulo(val)+
@@ -258,7 +248,7 @@ class Money
258
248
  # @example
259
249
  # Money.new(-100).abs #=> #<Money @fractional=100>
260
250
  def abs
261
- Money.new(self.fractional.abs, self.currency)
251
+ Money.new(fractional.abs, currency)
262
252
  end
263
253
 
264
254
  # Test if the money amount is zero.
@@ -284,5 +274,13 @@ class Money
284
274
  fractional != 0 ? self : nil
285
275
  end
286
276
 
277
+ # Used to make Money instance handle the operations when arguments order is reversed
278
+ # @return [Array]
279
+ #
280
+ # @example
281
+ # 2 * Money.new(10) #=> #<Money @fractional=20>
282
+ def coerce(other)
283
+ [self, other]
284
+ end
287
285
  end
288
286
  end
@@ -180,6 +180,18 @@ class Money
180
180
  # Money.new(-100, "GBP").format(:sign_before_symbol => true) #=> "-£1.00"
181
181
  # Money.new(-100, "GBP").format(:sign_before_symbol => false) #=> "£-1.00"
182
182
  # Money.new(-100, "GBP").format #=> "£-1.00"
183
+ #
184
+ # @option *rules [Boolean] :sign_positive (false) Whether positive numbers should be
185
+ # signed, too.
186
+ #
187
+ # @example
188
+ # # You can specify to display the sign with positive numbers
189
+ # Money.new(100, "GBP").format(:sign_positive => true, :sign_before_symbol => true) #=> "+£1.00"
190
+ # Money.new(100, "GBP").format(:sign_positive => true, :sign_before_symbol => false) #=> "£+1.00"
191
+ # Money.new(100, "GBP").format(:sign_positive => false, :sign_before_symbol => true) #=> "£1.00"
192
+ # Money.new(100, "GBP").format(:sign_positive => false, :sign_before_symbol => false) #=> "£1.00"
193
+ # Money.new(100, "GBP").format #=> "£+1.00"
194
+
183
195
  def format(*rules)
184
196
  # support for old format parameters
185
197
  rules = normalize_formatting_rules(rules)
@@ -208,7 +220,9 @@ class Money
208
220
  symbol
209
221
  end
210
222
 
211
- formatted = rules[:no_cents] ? "#{self.to_s.to_i}" : self.to_s
223
+ sign = self.negative? ? '-' : ''
224
+ formatted = rules[:no_cents] ? "#{self.abs.to_s.to_i}" : self.abs.to_s
225
+
212
226
 
213
227
  if rules[:no_cents_if_whole] && cents % currency.subunit_to_unit == 0
214
228
  formatted = "#{self.to_s.to_i}"
@@ -233,10 +247,13 @@ class Money
233
247
  :after
234
248
  end
235
249
 
236
- sign = ""
237
- if rules[:sign_before_symbol] == true && self.negative?
238
- formatted.tr!("-", "")
239
- sign = "-"
250
+ if rules[:sign_positive] == true && self.positive?
251
+ sign = '+'
252
+ end
253
+
254
+ if rules[:sign_before_symbol] == true
255
+ sign_before = sign
256
+ sign = ''
240
257
  end
241
258
 
242
259
  if symbol_value && !symbol_value.empty?
@@ -244,10 +261,10 @@ class Money
244
261
 
245
262
  formatted = if symbol_position == :before
246
263
  symbol_space = rules[:symbol_before_without_space] === false ? " " : ""
247
- "#{sign}#{symbol_value}#{symbol_space}#{formatted}"
264
+ "#{sign_before}#{symbol_value}#{symbol_space}#{sign}#{formatted}"
248
265
  else
249
266
  symbol_space = rules[:symbol_after_without_space] ? "" : " "
250
- "#{sign}#{formatted}#{symbol_space}#{symbol_value}"
267
+ "#{sign_before}#{formatted}#{symbol_space}#{sign}#{symbol_value}"
251
268
  end
252
269
  end
253
270
 
@@ -306,7 +323,7 @@ class Money
306
323
 
307
324
  def localize_formatting_rules(rules)
308
325
  if currency.iso_code == "JPY" && I18n.locale == :ja
309
- rules[:symbol] = "円"
326
+ rules[:symbol] = "円" unless rules[:symbol] == false
310
327
  rules[:symbol_position] = :after
311
328
  rules[:symbol_after_without_space] = true
312
329
  end
data/money.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |s|
3
3
  s.name = "money"
4
- s.version = "6.0.0.pre2"
4
+ s.version = "6.0.0.pre3"
5
5
  s.platform = Gem::Platform::RUBY
6
6
  s.authors = ["Tobias Luetke", "Hongli Lai", "Jeremy McNevin",
7
7
  "Shane Emmons", "Simone Carletti"]
@@ -10,6 +10,17 @@ Gem::Specification.new do |s|
10
10
  s.summary = "Money and currency exchange support library."
11
11
  s.description = "This library aids one in handling money and different currencies."
12
12
 
13
+ s.post_install_message = '''
14
+ Please note the following API changes in Money version 6
15
+
16
+ - Money#amount, Money#dollars methods now return instances of BigDecimal (rather than Float).
17
+
18
+ Please read the migration notes at https://github.com/RubyMoney/money#migration-notes
19
+ and choose the migration that best suits your application.
20
+
21
+ Test responsibly :-)
22
+ '''
23
+
13
24
  s.required_ruby_version = ">= 1.8.7"
14
25
 
15
26
  s.add_dependency "i18n", "~> 0.6.4"
@@ -259,14 +259,18 @@ describe Money do
259
259
  it "does not multiply Money by Money (different currency)" do
260
260
  expect { Money.new( 10, :USD) * Money.new( 4, :EUR) }.to raise_error(ArgumentError)
261
261
  end
262
+
263
+ it "does not multiply Money by an object which is NOT a number" do
264
+ expect { Money.new( 10, :USD) * 'abc' }.to raise_error(ArgumentError)
265
+ end
262
266
  end
263
267
 
264
268
  describe "#/" do
265
269
  it "divides Money by Fixnum and returns Money" do
266
270
  ts = [
267
271
  {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 3, :USD)},
268
- {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-4, :USD)},
269
- {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-4, :USD)},
272
+ {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-3, :USD)},
273
+ {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-3, :USD)},
270
274
  {:a => Money.new(-13, :USD), :b => -4, :c => Money.new( 3, :USD)},
271
275
  ]
272
276
  ts.each do |t|
@@ -274,6 +278,44 @@ describe Money do
274
278
  end
275
279
  end
276
280
 
281
+ context 'rounding preference' do
282
+ before do
283
+ Money.stub(:rounding_mode => rounding_mode)
284
+ end
285
+
286
+ after do
287
+ Money.unstub(:rounding_mode)
288
+ end
289
+
290
+ context 'ceiling rounding' do
291
+ let(:rounding_mode) { BigDecimal::ROUND_CEILING }
292
+ it "obeys the rounding preference" do
293
+ (Money.new(10) / 3).should == Money.new(4)
294
+ end
295
+ end
296
+
297
+ context 'floor rounding' do
298
+ let(:rounding_mode) { BigDecimal::ROUND_FLOOR }
299
+ it "obeys the rounding preference" do
300
+ (Money.new(10) / 6).should == Money.new(1)
301
+ end
302
+ end
303
+
304
+ context 'half up rounding' do
305
+ let(:rounding_mode) { BigDecimal::ROUND_HALF_UP }
306
+ it "obeys the rounding preference" do
307
+ (Money.new(10) / 4).should == Money.new(3)
308
+ end
309
+ end
310
+
311
+ context 'half down rounding' do
312
+ let(:rounding_mode) { BigDecimal::ROUND_HALF_DOWN }
313
+ it "obeys the rounding preference" do
314
+ (Money.new(10) / 4).should == Money.new(2)
315
+ end
316
+ end
317
+ end
318
+
277
319
  it "divides Money by Money (same currency) and returns Float" do
278
320
  ts = [
279
321
  {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => 3.25},
@@ -326,8 +368,8 @@ describe Money do
326
368
  it "divides Money by Fixnum and returns Money" do
327
369
  ts = [
328
370
  {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 3, :USD)},
329
- {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-4, :USD)},
330
- {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-4, :USD)},
371
+ {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-3, :USD)},
372
+ {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-3, :USD)},
331
373
  {:a => Money.new(-13, :USD), :b => -4, :c => Money.new( 3, :USD)},
332
374
  ]
333
375
  ts.each do |t|
@@ -387,8 +429,8 @@ describe Money do
387
429
  it "calculates division and modulo with Fixnum" do
388
430
  ts = [
389
431
  {:a => Money.new( 13, :USD), :b => 4, :c => [Money.new( 3, :USD), Money.new( 1, :USD)]},
390
- {:a => Money.new( 13, :USD), :b => -4, :c => [Money.new(-4, :USD), Money.new(-3, :USD)]},
391
- {:a => Money.new(-13, :USD), :b => 4, :c => [Money.new(-4, :USD), Money.new( 3, :USD)]},
432
+ {:a => Money.new( 13, :USD), :b => -4, :c => [Money.new(-3, :USD), Money.new(-3, :USD)]},
433
+ {:a => Money.new(-13, :USD), :b => 4, :c => [Money.new(-3, :USD), Money.new( 3, :USD)]},
392
434
  {:a => Money.new(-13, :USD), :b => -4, :c => [Money.new( 3, :USD), Money.new(-1, :USD)]},
393
435
  ]
394
436
  ts.each do |t|
@@ -595,4 +637,11 @@ describe Money do
595
637
  money.nonzero?.should be_equal(money)
596
638
  end
597
639
  end
640
+
641
+ describe "#coerce" do
642
+ it "allows mathematical operations by coercing arguments" do
643
+ result = 2 * Money.new(4, 'USD')
644
+ result.should == Money.new(8, 'USD')
645
+ end
646
+ end
598
647
  end
@@ -82,7 +82,9 @@ describe Money, "formatting" do
82
82
  before { @_locale = I18n.locale; I18n.locale = :ja }
83
83
 
84
84
  it "formats Japanese currency in Japanese properly" do
85
- Money.new(1000, "JPY").format.should == "1,000円"
85
+ money = Money.new(1000, "JPY")
86
+ money.format.should == "1,000円"
87
+ money.format(:symbol => false).should == "1,000"
86
88
  end
87
89
 
88
90
  after { I18n.locale = @_locale }
@@ -133,7 +135,7 @@ describe Money, "formatting" do
133
135
  one_thousand["BRL"].should == "R$ 1.000,00"
134
136
 
135
137
  # Other
136
- one_thousand["SEK"].should == "1.000,00 kr"
138
+ one_thousand["SEK"].should == "1 000,00 kr"
137
139
  one_thousand["GHC"].should == "₵1,000.00"
138
140
  end
139
141
 
@@ -265,6 +267,9 @@ describe Money, "formatting" do
265
267
  money.format(:symbol => "").should == "1.00"
266
268
  money.format(:symbol => nil).should == "1.00"
267
269
  money.format(:symbol => false).should == "1.00"
270
+
271
+ money = Money.new(100, "JPY")
272
+ money.format(:symbol => false).should == "100"
268
273
  end
269
274
 
270
275
  it "defaults :symbol to true" do
@@ -406,6 +411,34 @@ describe Money, "formatting" do
406
411
  end
407
412
  end
408
413
 
414
+ describe ":sign_positive option" do
415
+ specify "(:sign_positive => true, :sign_before_symbol => true) works as documented" do
416
+ Money.us_dollar( 0).format(:sign_positive => true, :sign_before_symbol => true).should == "$0.00"
417
+ Money.us_dollar( 100000).format(:sign_positive => true, :sign_before_symbol => true).should == "+$1,000.00"
418
+ Money.us_dollar(-100000).format(:sign_positive => true, :sign_before_symbol => true).should == "-$1,000.00"
419
+ end
420
+
421
+ specify "(:sign_positive => true, :sign_before_symbol => false) works as documented" do
422
+ Money.us_dollar( 0).format(:sign_positive => true, :sign_before_symbol => false).should == "$0.00"
423
+ Money.us_dollar( 100000).format(:sign_positive => true, :sign_before_symbol => false).should == "$+1,000.00"
424
+ Money.us_dollar( 100000).format(:sign_positive => true, :sign_before_symbol => nil).should == "$+1,000.00"
425
+ Money.us_dollar(-100000).format(:sign_positive => true, :sign_before_symbol => false).should == "$-1,000.00"
426
+ Money.us_dollar(-100000).format(:sign_positive => true, :sign_before_symbol => nil).should == "$-1,000.00"
427
+ end
428
+
429
+ specify "(:sign_positive => false, :sign_before_symbol => true) works as documented" do
430
+ Money.us_dollar( 100000).format(:sign_positive => false, :sign_before_symbol => true).should == "$1,000.00"
431
+ Money.us_dollar(-100000).format(:sign_positive => false, :sign_before_symbol => true).should == "-$1,000.00"
432
+ end
433
+
434
+ specify "(:sign_positive => false, :sign_before_symbol => false) works as documented" do
435
+ Money.us_dollar( 100000).format(:sign_positive => false, :sign_before_symbol => false).should == "$1,000.00"
436
+ Money.us_dollar( 100000).format(:sign_positive => false, :sign_before_symbol => nil).should == "$1,000.00"
437
+ Money.us_dollar(-100000).format(:sign_positive => false, :sign_before_symbol => false).should == "$-1,000.00"
438
+ Money.us_dollar(-100000).format(:sign_positive => false, :sign_before_symbol => nil).should == "$-1,000.00"
439
+ end
440
+ end
441
+
409
442
  context "when the monetary value is 0" do
410
443
  let(:money) { Money.us_dollar(0) }
411
444
 
@@ -9,7 +9,7 @@ describe Money, "parsing" do
9
9
 
10
10
  describe ".parse" do
11
11
  it "is depreciated" do
12
- Money.should_receive(:deprecate)
12
+ Money.should_receive(:deprecate).at_least(1).times
13
13
  Money.parse("1.95")
14
14
  end
15
15
 
@@ -32,7 +32,7 @@ describe Money, "parsing" do
32
32
  before do
33
33
  Money.assume_from_symbol = true
34
34
  end
35
- it "parses formatted inputs with the currency passed as a symbol" do
35
+ it "parses formatted inputs with the currency passed as a symbol" do
36
36
  with_default_currency("EUR") do
37
37
  Money.parse("$5.95").should == Money.new(595, 'USD')
38
38
  end
data/spec/money_spec.rb CHANGED
@@ -157,8 +157,8 @@ describe Money do
157
157
  end
158
158
 
159
159
  context "loading a serialized Money via YAML" do
160
- it "uses BigDecimal when rounding" do
161
- serialized = <<YAML
160
+
161
+ let(:serialized) { <<YAML
162
162
  !ruby/object:Money
163
163
  fractional: 249.5
164
164
  currency: !ruby/object:Money::Currency
@@ -178,12 +178,30 @@ describe Money do
178
178
  mutex: !ruby/object:Mutex {}
179
179
  last_updated: 2012-11-23 20:41:47.454438399 +02:00
180
180
  YAML
181
+ }
182
+
183
+ it "uses BigDecimal when rounding" do
181
184
  m = YAML::load serialized
182
185
  m.should be_a(Money)
183
186
  m.class.infinite_precision.should == false
184
187
  m.fractional.should == 250 # 249.5 rounded up
185
188
  m.fractional.should be_a(Integer)
186
189
  end
190
+
191
+ context "with infinite_precision" do
192
+ before do
193
+ Money.infinite_precision = true
194
+ end
195
+
196
+ after do
197
+ Money.infinite_precision = false
198
+ end
199
+
200
+ it "is a BigDecimal" do
201
+ money = YAML::load serialized
202
+ money.fractional.should be_a BigDecimal
203
+ end
204
+ end
187
205
  end
188
206
 
189
207
  context "user changes rounding_mode" do
@@ -239,6 +257,10 @@ YAML
239
257
  Money.new(100_37).amount.should == 100.37
240
258
  Money.new_with_amount(100.37).amount.should == 100.37
241
259
  end
260
+
261
+ it 'produces a BigDecimal' do
262
+ Money.new(1_00).amount.should be_a BigDecimal
263
+ end
242
264
  end
243
265
 
244
266
  describe "#dollars" do
@@ -494,4 +516,49 @@ YAML
494
516
  end
495
517
  end
496
518
  end
519
+
520
+ describe "#round" do
521
+
522
+ let(:money) { Money.new(15.75, 'NZD') }
523
+ subject(:rounded) { money.round }
524
+
525
+ context "without infinite_precision" do
526
+ before do
527
+ Money.infinite_precision = false
528
+ end
529
+
530
+ it "returns self (as it is already rounded)" do
531
+ rounded = money.round
532
+ rounded.should be money
533
+ rounded.cents.should eq 16
534
+ end
535
+ end
536
+
537
+ context "with infinite_precision" do
538
+ before do
539
+ Money.infinite_precision = true
540
+ end
541
+
542
+ after do
543
+ Money.infinite_precision = false
544
+ end
545
+
546
+ it "returns a different money" do
547
+ rounded.should_not be money
548
+ end
549
+
550
+ it "rounds the cents" do
551
+ rounded.cents.should eq 16
552
+ end
553
+
554
+ it "maintains the currency" do
555
+ rounded.currency.should eq Money::Currency.new('NZD')
556
+ end
557
+
558
+ it "uses a provided rounding strategy" do
559
+ rounded = money.round(BigDecimal::ROUND_DOWN)
560
+ rounded.cents.should eq 15
561
+ end
562
+ end
563
+ end
497
564
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: money
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.0.pre2
4
+ version: 6.0.0.pre3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Luetke
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2013-07-27 00:00:00.000000000 Z
15
+ date: 2013-09-04 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: i18n
@@ -80,18 +80,18 @@ files:
80
80
  - config/currency_backwards_compatible.json
81
81
  - config/currency_iso.json
82
82
  - config/currency_non_iso.json
83
+ - lib/money.rb
83
84
  - lib/money/bank/base.rb
84
85
  - lib/money/bank/variable_exchange.rb
85
86
  - lib/money/core_extensions.rb
87
+ - lib/money/currency.rb
86
88
  - lib/money/currency/heuristics.rb
87
89
  - lib/money/currency/loader.rb
88
- - lib/money/currency.rb
89
90
  - lib/money/deprecations.rb
91
+ - lib/money/money.rb
90
92
  - lib/money/money/arithmetic.rb
91
93
  - lib/money/money/formatting.rb
92
94
  - lib/money/money/parsing.rb
93
- - lib/money/money.rb
94
- - lib/money.rb
95
95
  - spec/bank/base_spec.rb
96
96
  - spec/bank/variable_exchange_spec.rb
97
97
  - spec/core_extensions_spec.rb
@@ -112,7 +112,16 @@ homepage: http://rubymoney.github.com/money
112
112
  licenses:
113
113
  - MIT
114
114
  metadata: {}
115
- post_install_message:
115
+ post_install_message: |2
116
+
117
+ Please note the following API changes in Money version 6
118
+
119
+ - Money#amount, Money#dollars methods now return instances of BigDecimal (rather than Float).
120
+
121
+ Please read the migration notes at https://github.com/RubyMoney/money#migration-notes
122
+ and choose the migration that best suits your application.
123
+
124
+ Test responsibly :-)
116
125
  rdoc_options: []
117
126
  require_paths:
118
127
  - lib
@@ -128,7 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
128
137
  version: 1.3.1
129
138
  requirements: []
130
139
  rubyforge_project:
131
- rubygems_version: 2.0.2
140
+ rubygems_version: 2.0.3
132
141
  signing_key:
133
142
  specification_version: 4
134
143
  summary: Money and currency exchange support library.