money 6.7.1 → 6.8.0

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: cf8496911c1ac6ef2fdb34ad3e0b9f458bf6e836
4
- data.tar.gz: 70ed919de03069d7a92883d46b890d60194eae1a
3
+ metadata.gz: f9d58da811f0d0d652d931abc3e027c4ac29f194
4
+ data.tar.gz: eb6e25dcd90e03488b99913bcbedfed44b9370f3
5
5
  SHA512:
6
- metadata.gz: dabd711f4ba2737ee735c8e29569b56d0650686802fd56e27d0df34afd26865bfd11630deacb64cb74d22c7b97a25fd8a4bfa49ed3dcfa5195b8bf324edd2a53
7
- data.tar.gz: 03e66b3f5639b64baf44082e075e6c2e275ce8bd9911cb0e1152ccf4449d840043b9a233a81b51ef6cf66783986e600a3d7c57840287a398f5d52e45f56bbb4f
6
+ metadata.gz: 672f61e940c74f7818db5dcfb0b98cf23976a91e4cd7b40aeb20cfdb365f0ce4b591b94829c913fed9235e653bb3e9b454e9412a183e35df9ad5ff7ffa798197
7
+ data.tar.gz: d3987957ca8e363e66dd909bc2489f94d47be3ba92e8aa2411470d5541390068ccc40d4df3d3cfda89359d5848ff83dbaaa31260a469e679260852a2584d6119
@@ -3,17 +3,20 @@ sudo: false
3
3
  rvm:
4
4
  - 1.9.3
5
5
  - 2.0.0
6
- - 2.1.8
7
- - 2.2.4
8
- - 2.3.0
6
+ - 2.1.10
7
+ - 2.2.5
8
+ - 2.3.1
9
+ - 2.4.0
9
10
  - rbx-2
10
- - jruby-9.0.4.0
11
+ - jruby-9.0.5.0
12
+ - jruby-9.1.2.0
11
13
  - ruby-head
12
14
  - jruby-head
13
15
  matrix:
14
16
  allow_failures:
15
17
  - rvm: ruby-head
16
18
  - rvm: jruby-head
19
+ - rvm: rbx-2
17
20
  fast_finish: true
18
21
  script: bundle exec rspec spec
19
22
  notifications:
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## 6.8.0
4
+ - Ruby 2.4.0 support
5
+ - Fixed UZS syntax
6
+ - Fixed HUF smallest denomination
7
+ - Fixed ruby 1.9 issues
8
+ - Fixed html entity for COP
9
+ - Updated all currency decimals to ISO-4217
10
+ - Fixed money allocation for negative amounts
11
+ - Fixed symbol_first for RON
12
+ - Fixed disambiguate option when symbol is set to true
13
+ - Fixed thousands separator for CZK
14
+ - Improved formatter performance by precaching I18n calls
15
+
3
16
  ## 6.7.1
4
17
  - Changed DKK symbol from 'kr' to 'kr.'
5
18
  - Improved Money::Formatting#format docs
@@ -10,6 +23,7 @@
10
23
  - `Money#==` will now raise error for non-zero numeric values
11
24
  - Fixed divmod
12
25
  - Added disambiguation symbol to USD Dollar
26
+ - Use disambiguation symbol when both disambiguate and symbol are true in `format` method
13
27
 
14
28
  ## 6.7.0
15
29
  - Changed `Money#<=>` to return `nil` if the comparison is inappropriate. (#584)
data/Gemfile CHANGED
@@ -1,7 +1,16 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
- gem "coveralls", :require => false
4
- gem "json", :platform => :jruby
5
- gem "pry", :require => false
3
+ gem 'coveralls', '>= 0.8.17', :require => false
4
+ gem 'pry', :require => false
5
+
6
+ # JSON gem no longer supports ruby < 2.0.0
7
+ if defined?(JRUBY_VERSION)
8
+ gem 'json'
9
+ elsif RUBY_VERSION =~ /^1/
10
+ # Legacy gem locks for ruby 1.9.x
11
+ gem 'json', '~> 1.8.3'
12
+ gem 'tins', '~> 1.6.0'
13
+ gem 'term-ansicolor', '< 1.4'
14
+ end
6
15
 
7
16
  gemspec
data/LICENSE CHANGED
@@ -1,3 +1,5 @@
1
+ The MIT License (MIT)
2
+
1
3
  Copyright (c) 2005 Tobias Lutke
2
4
  Copyright (c) 2008 Phusion
3
5
 
data/README.md CHANGED
@@ -316,12 +316,12 @@ The following example implements an `ActiveRecord` store to save exchange rates
316
316
 
317
317
  class ExchangeRate < ActiveRecord::Base
318
318
  def self.get_rate(from_iso_code, to_iso_code)
319
- rate = find_by_from_and_to(from_iso_code, to_iso_code)
319
+ rate = find_by(:from => from_iso_code, :to => to_iso_code)
320
320
  rate.present? ? rate.rate : nil
321
321
  end
322
322
 
323
323
  def self.add_rate(from_iso_code, to_iso_code, rate)
324
- exrate = find_or_initialize_by_from_and_to(from_iso_code, to_iso_code)
324
+ exrate = find_or_initialize_by(:from => from_iso_code, :to => to_iso_code)
325
325
  exrate.rate = rate
326
326
  exrate.save!
327
327
  end
@@ -376,6 +376,7 @@ implementations.
376
376
  - [money-open-exchange-rates](https://github.com/spk/money-open-exchange-rates)
377
377
  - [money-historical-bank](https://github.com/atwam/money-historical-bank)
378
378
  - [russian_central_bank](https://github.com/rmustafin/russian_central_bank)
379
+ - [money-uphold-bank](https://github.com/subvisual/money-uphold-bank)
379
380
 
380
381
  ## Ruby on Rails
381
382
 
@@ -236,7 +236,7 @@
236
236
  "disambiguate_symbol": "FBu",
237
237
  "alternate_symbols": ["FBu"],
238
238
  "subunit": "Centime",
239
- "subunit_to_unit": 100,
239
+ "subunit_to_unit": 1,
240
240
  "symbol_first": false,
241
241
  "html_entity": "",
242
242
  "decimal_mark": ".",
@@ -501,7 +501,7 @@
501
501
  "subunit": "Centavo",
502
502
  "subunit_to_unit": 100,
503
503
  "symbol_first": true,
504
- "html_entity": "&#x20B1;",
504
+ "html_entity": "&#36;",
505
505
  "decimal_mark": ",",
506
506
  "thousands_separator": ".",
507
507
  "iso_numeric": "170",
@@ -581,7 +581,7 @@
581
581
  "symbol_first": false,
582
582
  "html_entity": "",
583
583
  "decimal_mark": ",",
584
- "thousands_separator": ".",
584
+ "thousands_separator": " ",
585
585
  "iso_numeric": "203",
586
586
  "smallest_denomination": 100
587
587
  },
@@ -592,7 +592,7 @@
592
592
  "symbol": "Fdj",
593
593
  "alternate_symbols": [],
594
594
  "subunit": "Centime",
595
- "subunit_to_unit": 100,
595
+ "subunit_to_unit": 1,
596
596
  "symbol_first": false,
597
597
  "html_entity": "",
598
598
  "decimal_mark": ".",
@@ -824,7 +824,7 @@
824
824
  "disambiguate_symbol": "FG",
825
825
  "alternate_symbols": ["FG", "GFr"],
826
826
  "subunit": "Centime",
827
- "subunit_to_unit": 100,
827
+ "subunit_to_unit": 1,
828
828
  "symbol_first": false,
829
829
  "html_entity": "",
830
830
  "decimal_mark": ".",
@@ -938,7 +938,7 @@
938
938
  "decimal_mark": ",",
939
939
  "thousands_separator": ".",
940
940
  "iso_numeric": "348",
941
- "smallest_denomination": 500
941
+ "smallest_denomination": 5
942
942
  },
943
943
  "idr": {
944
944
  "priority": 100,
@@ -1007,7 +1007,7 @@
1007
1007
  "symbol": "﷼",
1008
1008
  "alternate_symbols": [],
1009
1009
  "subunit": null,
1010
- "subunit_to_unit": 1,
1010
+ "subunit_to_unit": 100,
1011
1011
  "symbol_first": true,
1012
1012
  "html_entity": "&#xFDFC;",
1013
1013
  "decimal_mark": ".",
@@ -1129,7 +1129,7 @@
1129
1129
  "disambiguate_symbol": "CF",
1130
1130
  "alternate_symbols": ["CF"],
1131
1131
  "subunit": "Centime",
1132
- "subunit_to_unit": 100,
1132
+ "subunit_to_unit": 1,
1133
1133
  "symbol_first": false,
1134
1134
  "html_entity": "",
1135
1135
  "decimal_mark": ".",
@@ -1756,7 +1756,7 @@
1756
1756
  "symbol": "₲",
1757
1757
  "alternate_symbols": [],
1758
1758
  "subunit": "Céntimo",
1759
- "subunit_to_unit": 100,
1759
+ "subunit_to_unit": 1,
1760
1760
  "symbol_first": true,
1761
1761
  "html_entity": "&#x20B2;",
1762
1762
  "decimal_mark": ".",
@@ -1787,7 +1787,7 @@
1787
1787
  "alternate_symbols": [],
1788
1788
  "subunit": "Bani",
1789
1789
  "subunit_to_unit": 100,
1790
- "symbol_first": true,
1790
+ "symbol_first": false,
1791
1791
  "html_entity": "",
1792
1792
  "decimal_mark": ",",
1793
1793
  "thousands_separator": ".",
@@ -1831,7 +1831,7 @@
1831
1831
  "symbol": "FRw",
1832
1832
  "alternate_symbols": ["RF", "R₣"],
1833
1833
  "subunit": "Centime",
1834
- "subunit_to_unit": 100,
1834
+ "subunit_to_unit": 1,
1835
1835
  "symbol_first": false,
1836
1836
  "html_entity": "",
1837
1837
  "decimal_mark": ".",
@@ -2246,7 +2246,7 @@
2246
2246
  "symbol": "USh",
2247
2247
  "alternate_symbols": [],
2248
2248
  "subunit": "Cent",
2249
- "subunit_to_unit": 100,
2249
+ "subunit_to_unit": 1,
2250
2250
  "symbol_first": false,
2251
2251
  "html_entity": "",
2252
2252
  "decimal_mark": ".",
@@ -2288,9 +2288,9 @@
2288
2288
  "uzs": {
2289
2289
  "priority": 100,
2290
2290
  "iso_code": "UZS",
2291
- "name": "Uzbekistani Som",
2291
+ "name": "Uzbekistan Som",
2292
2292
  "symbol": null,
2293
- "alternate_symbols": [],
2293
+ "alternate_symbols": ["so‘m", "сўм", "сум", "s", "с"],
2294
2294
  "subunit": "Tiyin",
2295
2295
  "subunit_to_unit": 100,
2296
2296
  "symbol_first": false,
@@ -2369,7 +2369,7 @@
2369
2369
  "disambiguate_symbol": "FCFA",
2370
2370
  "alternate_symbols": ["FCFA"],
2371
2371
  "subunit": "Centime",
2372
- "subunit_to_unit": 100,
2372
+ "subunit_to_unit": 1,
2373
2373
  "symbol_first": false,
2374
2374
  "html_entity": "",
2375
2375
  "decimal_mark": ".",
@@ -2407,6 +2407,66 @@
2407
2407
  "thousands_separator": ",",
2408
2408
  "iso_numeric": "959"
2409
2409
  },
2410
+ "xba": {
2411
+ "priority": 100,
2412
+ "iso_code": "XBA",
2413
+ "name": "European Composite Unit",
2414
+ "symbol": "",
2415
+ "disambiguate_symbol": "XBA",
2416
+ "alternate_symbols": [],
2417
+ "subunit": "",
2418
+ "subunit_to_unit": 1,
2419
+ "symbol_first": false,
2420
+ "html_entity": "",
2421
+ "decimal_mark": ".",
2422
+ "thousands_separator": ",",
2423
+ "iso_numeric": "955"
2424
+ },
2425
+ "xbb": {
2426
+ "priority": 100,
2427
+ "iso_code": "XBB",
2428
+ "name": "European Monetary Unit",
2429
+ "symbol": "",
2430
+ "disambiguate_symbol": "XBB",
2431
+ "alternate_symbols": [],
2432
+ "subunit": "",
2433
+ "subunit_to_unit": 1,
2434
+ "symbol_first": false,
2435
+ "html_entity": "",
2436
+ "decimal_mark": ".",
2437
+ "thousands_separator": ",",
2438
+ "iso_numeric": "956"
2439
+ },
2440
+ "xbc": {
2441
+ "priority": 100,
2442
+ "iso_code": "XBC",
2443
+ "name": "European Unit of Account 9",
2444
+ "symbol": "",
2445
+ "disambiguate_symbol": "XBC",
2446
+ "alternate_symbols": [],
2447
+ "subunit": "",
2448
+ "subunit_to_unit": 1,
2449
+ "symbol_first": false,
2450
+ "html_entity": "",
2451
+ "decimal_mark": ".",
2452
+ "thousands_separator": ",",
2453
+ "iso_numeric": "957"
2454
+ },
2455
+ "xbd": {
2456
+ "priority": 100,
2457
+ "iso_code": "XBD",
2458
+ "name": "European Unit of Account 17",
2459
+ "symbol": "",
2460
+ "disambiguate_symbol": "XBD",
2461
+ "alternate_symbols": [],
2462
+ "subunit": "",
2463
+ "subunit_to_unit": 1,
2464
+ "symbol_first": false,
2465
+ "html_entity": "",
2466
+ "decimal_mark": ".",
2467
+ "thousands_separator": ",",
2468
+ "iso_numeric": "958"
2469
+ },
2410
2470
  "xcd": {
2411
2471
  "priority": 100,
2412
2472
  "iso_code": "XCD",
@@ -2445,7 +2505,7 @@
2445
2505
  "disambiguate_symbol": "CFA",
2446
2506
  "alternate_symbols": ["CFA"],
2447
2507
  "subunit": "Centime",
2448
- "subunit_to_unit": 100,
2508
+ "subunit_to_unit": 1,
2449
2509
  "symbol_first": false,
2450
2510
  "html_entity": "",
2451
2511
  "decimal_mark": ".",
@@ -2453,6 +2513,21 @@
2453
2513
  "iso_numeric": "952",
2454
2514
  "smallest_denomination": 100
2455
2515
  },
2516
+ "xpd": {
2517
+ "priority": 100,
2518
+ "iso_code": "XPD",
2519
+ "name": "Palladium",
2520
+ "symbol": "oz t",
2521
+ "disambiguate_symbol": "XPD",
2522
+ "alternate_symbols": [],
2523
+ "subunit": "oz",
2524
+ "subunit_to_unit": 1,
2525
+ "symbol_first": false,
2526
+ "html_entity": "",
2527
+ "decimal_mark": ".",
2528
+ "thousands_separator": ",",
2529
+ "iso_numeric": "964"
2530
+ },
2456
2531
  "xpf": {
2457
2532
  "priority": 100,
2458
2533
  "iso_code": "XPF",
@@ -2460,7 +2535,7 @@
2460
2535
  "symbol": "Fr",
2461
2536
  "alternate_symbols": ["F"],
2462
2537
  "subunit": "Centime",
2463
- "subunit_to_unit": 100,
2538
+ "subunit_to_unit": 1,
2464
2539
  "symbol_first": false,
2465
2540
  "html_entity": "",
2466
2541
  "decimal_mark": ".",
@@ -2468,6 +2543,36 @@
2468
2543
  "iso_numeric": "953",
2469
2544
  "smallest_denomination": 100
2470
2545
  },
2546
+ "xpt": {
2547
+ "priority": 100,
2548
+ "iso_code": "XPT",
2549
+ "name": "Platinum",
2550
+ "symbol": "oz t",
2551
+ "alternate_symbols": [],
2552
+ "subunit": "",
2553
+ "subunit_to_unit": 1,
2554
+ "symbol_first": false,
2555
+ "html_entity": "",
2556
+ "decimal_mark": ".",
2557
+ "thousands_separator": ",",
2558
+ "iso_numeric": "962",
2559
+ "smallest_denomination": ""
2560
+ },
2561
+ "xts": {
2562
+ "priority": 100,
2563
+ "iso_code": "xts",
2564
+ "name": "Codes specifically reserved for testing purposes",
2565
+ "symbol": "",
2566
+ "alternate_symbols": [],
2567
+ "subunit": "",
2568
+ "subunit_to_unit": 1,
2569
+ "symbol_first": false,
2570
+ "html_entity": "",
2571
+ "decimal_mark": ".",
2572
+ "thousands_separator": ",",
2573
+ "iso_numeric": "963",
2574
+ "smallest_denomination": ""
2575
+ },
2471
2576
  "yer": {
2472
2577
  "priority": 100,
2473
2578
  "iso_code": "YER",
@@ -61,5 +61,21 @@
61
61
  "thousands_separator": ",",
62
62
  "iso_numeric": "",
63
63
  "smallest_denomination": 1
64
+ },
65
+ "xfu": {
66
+ "priority": 100,
67
+ "iso_code": "XFU",
68
+ "name": "UIC Franc",
69
+ "symbol": "",
70
+ "disambiguate_symbol": "",
71
+ "alternate_symbols": [],
72
+ "subunit": "",
73
+ "subunit_to_unit": 100,
74
+ "symbol_first": true,
75
+ "html_entity": "",
76
+ "decimal_mark": ".",
77
+ "thousands_separator": ",",
78
+ "iso_numeric": "",
79
+ "smallest_denomination": ""
64
80
  }
65
81
  }
@@ -45,8 +45,9 @@ class Money
45
45
  attr_reader :mutex, :store
46
46
 
47
47
  # Available formats for importing/exporting rates.
48
- RATE_FORMATS = [:json, :ruby, :yaml]
48
+ RATE_FORMATS = [:json, :ruby, :yaml].freeze
49
49
  SERIALIZER_SEPARATOR = '_TO_'.freeze
50
+ FORMAT_SERIALIZERS = {:json => JSON, :ruby => Marshal, :yaml => YAML}.freeze
50
51
 
51
52
  # Initializes a new +Money::Bank::VariableExchange+ object.
52
53
  # It defaults to using an in-memory, thread safe store instance for
@@ -125,13 +126,13 @@ class Money
125
126
  end
126
127
 
127
128
  def exchange(fractional, rate, &block)
128
- ex = (fractional * BigDecimal.new(rate.to_s)).to_f
129
+ ex = fractional * BigDecimal.new(rate.to_s)
129
130
  if block_given?
130
131
  yield ex
131
132
  elsif @rounding_method
132
133
  @rounding_method.call(ex)
133
134
  else
134
- ex.to_s.to_d
135
+ ex
135
136
  end
136
137
  end
137
138
 
@@ -216,14 +217,7 @@ class Money
216
217
  RATE_FORMATS.include? format
217
218
 
218
219
  store.transaction do
219
- s = case format
220
- when :json
221
- JSON.dump(rates)
222
- when :ruby
223
- Marshal.dump(rates)
224
- when :yaml
225
- YAML.dump(rates)
226
- end
220
+ s = FORMAT_SERIALIZERS[format].dump(rates)
227
221
 
228
222
  unless file.nil?
229
223
  File.open(file, "w") {|f| f.write(s) }
@@ -264,14 +258,7 @@ class Money
264
258
  RATE_FORMATS.include? format
265
259
 
266
260
  store.transaction do
267
- data = case format
268
- when :json
269
- JSON.load(s)
270
- when :ruby
271
- Marshal.load(s)
272
- when :yaml
273
- YAML.load(s)
274
- end
261
+ data = FORMAT_SERIALIZERS[format].load(s)
275
262
 
276
263
  data.each do |key, rate|
277
264
  from, to = key.split(SERIALIZER_SEPARATOR)
@@ -314,10 +314,10 @@ class Money
314
314
  end
315
315
  private :compare_ids
316
316
 
317
- # Returns a Fixnum hash value based on the +id+ attribute in order to use
317
+ # Returns a Integer hash value based on the +id+ attribute in order to use
318
318
  # functions like & (intersection), group_by, etc.
319
319
  #
320
- # @return [Fixnum]
320
+ # @return [Integer]
321
321
  #
322
322
  # @example
323
323
  # Money::Currency.new(:usd).hash #=> 428936
@@ -397,7 +397,7 @@ class Money
397
397
  # Note that MGA and MRO are exceptions and are rounded to 1
398
398
  # @see https://en.wikipedia.org/wiki/ISO_4217#Active_codes
399
399
  #
400
- # @return [Fixnum]
400
+ # @return [Integer]
401
401
  def exponent
402
402
  Math.log10(@subunit_to_unit).round
403
403
  end
@@ -117,7 +117,7 @@ class Money
117
117
  # @return [Boolean] Use this to enable infinite precision cents
118
118
  #
119
119
  # @!attribute [rw] conversion_precision
120
- # @return [Fixnum] Use this to specify precision for converting Rational
120
+ # @return [Integer] Use this to specify precision for converting Rational
121
121
  # to BigDecimal
122
122
  attr_accessor :default_bank, :default_formatting_rules,
123
123
  :use_i18n, :infinite_precision, :conversion_precision
@@ -317,10 +317,10 @@ class Money
317
317
  @currency = Currency.wrap(val)
318
318
  end
319
319
 
320
- # Returns a Fixnum hash value based on the +fractional+ and +currency+ attributes
320
+ # Returns a Integer hash value based on the +fractional+ and +currency+ attributes
321
321
  # in order to use functions like & (intersection), group_by, etc.
322
322
  #
323
- # @return [Fixnum]
323
+ # @return [Integer]
324
324
  #
325
325
  # @example
326
326
  # Money.new(100).hash #=> 908351
@@ -496,7 +496,9 @@ class Money
496
496
  amounts, left_over = amounts_from_splits(allocations, splits)
497
497
 
498
498
  unless self.class.infinite_precision
499
- left_over.to_i.times { |i| amounts[i % amounts.length] += 1 }
499
+ delta = left_over > 0 ? 1 : -1
500
+ # Distribute left over pennies amongst allocations
501
+ left_over.to_i.abs.times { |i| amounts[i % amounts.length] += delta }
500
502
  end
501
503
 
502
504
  amounts.collect { |fractional| self.class.new(fractional, currency) }
@@ -549,7 +551,7 @@ class Money
549
551
  if num.respond_to?(:to_d)
550
552
  num.is_a?(Rational) ? num.to_d(self.class.conversion_precision) : num.to_d
551
553
  else
552
- BigDecimal.new(num.to_s)
554
+ BigDecimal.new(num.to_s.empty? ? 0 : num.to_s)
553
555
  end
554
556
  end
555
557
 
@@ -592,7 +594,7 @@ class Money
592
594
  if self.class.infinite_precision
593
595
  fractional * ratio
594
596
  else
595
- (fractional * ratio / allocations).floor.tap do |frac|
597
+ (fractional * ratio / allocations).truncate.tap do |frac|
596
598
  left_over -= frac
597
599
  end
598
600
  end
@@ -48,16 +48,16 @@ class Money
48
48
  #
49
49
  # @param [Money] other_money Value to compare with.
50
50
  #
51
- # @return [Fixnum]
51
+ # @return [Integer]
52
52
  #
53
53
  # @raise [TypeError] when other object is not Money
54
54
  #
55
55
  def <=>(other)
56
- if other.respond_to?(:zero?) && other.zero?
56
+ unless other.is_a?(Money)
57
+ return unless other.respond_to?(:zero?) && other.zero?
57
58
  return other.is_a?(CoercedNumeric) ? 0 <=> fractional : fractional <=> 0
58
59
  end
59
- return unless other.is_a?(Money)
60
- other = other.exchange_to(currency) if nonzero? && currency != other.currency
60
+ other = other.exchange_to(currency)
61
61
  fractional <=> other.fractional
62
62
  rescue Money::Bank::UnknownRate
63
63
  end
@@ -97,6 +97,7 @@ class Money
97
97
  fractional < 0
98
98
  end
99
99
 
100
+ # @method +(other)
100
101
  # Returns a new Money object containing the sum of the two operands' monetary
101
102
  # values. If +other_money+ has a different currency then its monetary value
102
103
  # is automatically exchanged to this object's currency using +exchange_to+.
@@ -107,13 +108,8 @@ class Money
107
108
  #
108
109
  # @example
109
110
  # Money.new(100) + Money.new(100) #=> #<Money @fractional=200>
110
- def +(other_money)
111
- return self if other_money.zero?
112
- raise TypeError unless other_money.is_a?(Money)
113
- other_money = other_money.exchange_to(currency)
114
- self.class.new(fractional + other_money.fractional, currency)
115
- end
116
-
111
+ #
112
+ # @method -(other)
117
113
  # Returns a new Money object containing the difference between the two
118
114
  # operands' monetary values. If +other_money+ has a different currency then
119
115
  # its monetary value is automatically exchanged to this object's currency
@@ -125,11 +121,15 @@ class Money
125
121
  #
126
122
  # @example
127
123
  # Money.new(100) - Money.new(99) #=> #<Money @fractional=1>
128
- def -(other_money)
129
- return self if other_money.zero?
130
- raise TypeError unless other_money.is_a?(Money)
131
- other_money = other_money.exchange_to(currency)
132
- self.class.new(fractional - other_money.fractional, currency)
124
+ [:+, :-].each do |op|
125
+ define_method(op) do |other|
126
+ unless other.is_a?(Money)
127
+ return self if other.zero?
128
+ raise TypeError
129
+ end
130
+ other = other.exchange_to(currency)
131
+ self.class.new(fractional.public_send(op, other.fractional), currency)
132
+ end
133
133
  end
134
134
 
135
135
  # Multiplies the monetary value with the given number and returns a new
@@ -195,9 +195,9 @@ class Money
195
195
  # Divide money by money or fixnum and return array containing quotient and
196
196
  # modulus.
197
197
  #
198
- # @param [Money, Fixnum] val Number to divmod by.
198
+ # @param [Money, Integer] val Number to divmod by.
199
199
  #
200
- # @return [Array<Money,Money>,Array<Fixnum,Money>]
200
+ # @return [Array<Money,Money>,Array<Integer,Money>]
201
201
  #
202
202
  # @example
203
203
  # Money.new(100).divmod(9) #=> [#<Money @fractional=11>, #<Money @fractional=1>]
@@ -225,7 +225,7 @@ class Money
225
225
 
226
226
  # Equivalent to +self.divmod(val)[1]+
227
227
  #
228
- # @param [Money, Fixnum] val Number take modulo with.
228
+ # @param [Money, Integer] val Number take modulo with.
229
229
  #
230
230
  # @return [Money]
231
231
  #
@@ -238,7 +238,7 @@ class Money
238
238
 
239
239
  # Synonym for +#modulo+.
240
240
  #
241
- # @param [Money, Fixnum] val Number take modulo with.
241
+ # @param [Money, Integer] val Number take modulo with.
242
242
  #
243
243
  # @return [Money]
244
244
  #
@@ -249,7 +249,7 @@ class Money
249
249
 
250
250
  # If different signs +self.modulo(val) - val+ otherwise +self.modulo(val)+
251
251
  #
252
- # @param [Money, Fixnum] val Number to rake remainder with.
252
+ # @param [Money, Integer] val Number to rake remainder with.
253
253
  #
254
254
  # @return [Money]
255
255
  #
@@ -10,8 +10,7 @@ class Money
10
10
  # @example
11
11
  # Money.empty #=> #<Money @fractional=0>
12
12
  def empty(currency = default_currency)
13
- @empty ||= {}
14
- @empty[currency] ||= new(0, currency).freeze
13
+ new(0, currency)
15
14
  end
16
15
  alias_method :zero, :empty
17
16
 
@@ -288,11 +288,11 @@ class Money
288
288
  end
289
289
 
290
290
  def thousands_separator
291
- i18n_format_for(:thousands_separator, :delimiter, ",")
291
+ @thousands_separator ||= i18n_format_for(:thousands_separator, :delimiter, ",")
292
292
  end
293
293
 
294
294
  def decimal_mark
295
- i18n_format_for(:decimal_mark, :separator, ".")
295
+ @decimal_mark ||= i18n_format_for(:decimal_mark, :separator, ".")
296
296
  end
297
297
 
298
298
  alias_method :delimiter, :thousands_separator
@@ -387,7 +387,11 @@ class Money
387
387
  def symbol_value_from(rules)
388
388
  if rules.has_key?(:symbol)
389
389
  if rules[:symbol] === true
390
- symbol
390
+ if rules[:disambiguate] && currency.disambiguate_symbol
391
+ currency.disambiguate_symbol
392
+ else
393
+ symbol
394
+ end
391
395
  elsif rules[:symbol]
392
396
  rules[:symbol]
393
397
  else
@@ -395,7 +399,7 @@ class Money
395
399
  end
396
400
  elsif rules[:html]
397
401
  currency.html_entity == '' ? currency.symbol : currency.html_entity
398
- elsif rules[:disambiguate] and currency.disambiguate_symbol
402
+ elsif rules[:disambiguate] && currency.disambiguate_symbol
399
403
  currency.disambiguate_symbol
400
404
  else
401
405
  symbol
@@ -1,3 +1,3 @@
1
1
  class Money
2
- VERSION = "6.7.1"
2
+ VERSION = "6.8.0"
3
3
  end
@@ -14,17 +14,6 @@ Gem::Specification.new do |s|
14
14
  s.description = "A Ruby Library for dealing with money and currency conversion."
15
15
  s.license = "MIT"
16
16
 
17
- s.post_install_message = <<MSG
18
- Please note the following API changes in Money version 6
19
-
20
- - Money#amount, Money#dollars methods now return instances of BigDecimal (rather than Float).
21
-
22
- Please read the migration notes at https://github.com/RubyMoney/money#migration-notes
23
- and choose the migration that best suits your application.
24
-
25
- Test responsibly :-)
26
- MSG
27
-
28
17
  s.add_dependency 'i18n', ['>= 0.6.4', '<= 0.7.0']
29
18
  s.add_dependency 'sixarm_ruby_unaccent', ['>= 1.1.1', '< 2']
30
19
 
@@ -75,6 +75,10 @@ class Money
75
75
  special_money_class = Class.new(Money)
76
76
  expect(bank.exchange_with(special_money_class.new(100, 'USD'), 'EUR')).to be_a special_money_class
77
77
  end
78
+
79
+ it "doesn't loose precision when handling larger amounts" do
80
+ expect(bank.exchange_with(Money.new(100_000_000_000_000_01, 'USD'), 'EUR')).to eq Money.new(133_000_000_000_000_01, 'EUR')
81
+ end
78
82
  end
79
83
  end
80
84
 
@@ -23,6 +23,7 @@ describe Money do
23
23
  end
24
24
 
25
25
  it "returns true if both amounts are zero, even if currency differs" do
26
+ allow_any_instance_of(Money).to receive(:exchange_to) { Money.usd(0) }
26
27
  expect(Money.new(0, "USD")).to eq Money.new(0, "USD")
27
28
  expect(Money.new(0, "USD")).to eq Money.new(0, "EUR")
28
29
  expect(Money.new(0, "USD")).to eq Money.new(0, "AUD")
@@ -175,7 +176,7 @@ describe Money do
175
176
  expect(Money.new(10_00, "USD") + other).to eq Money.new(19_00, "USD")
176
177
  end
177
178
 
178
- it "adds Fixnum 0 to money and returns the same ammount" do
179
+ it "adds Integer 0 to money and returns the same ammount" do
179
180
  expect(Money.new(10_00) + 0).to eq Money.new(10_00)
180
181
  end
181
182
 
@@ -196,7 +197,7 @@ describe Money do
196
197
  expect(Money.new(10_00, "USD") - other).to eq Money.new(1_00, "USD")
197
198
  end
198
199
 
199
- it "subtract Fixnum 0 to money and returns the same ammount" do
200
+ it "subtract Integer 0 to money and returns the same ammount" do
200
201
  expect(Money.new(10_00) - 0).to eq Money.new(10_00)
201
202
  end
202
203
 
@@ -207,7 +208,7 @@ describe Money do
207
208
  end
208
209
 
209
210
  describe "#*" do
210
- it "multiplies Money by Fixnum and returns Money" do
211
+ it "multiplies Money by Integer and returns Money" do
211
212
  ts = [
212
213
  {:a => Money.new( 10, :USD), :b => 4, :c => Money.new( 40, :USD)},
213
214
  {:a => Money.new( 10, :USD), :b => -4, :c => Money.new(-40, :USD)},
@@ -238,7 +239,7 @@ describe Money do
238
239
  end
239
240
 
240
241
  describe "#/" do
241
- it "divides Money by Fixnum and returns Money" do
242
+ it "divides Money by Integer and returns Money" do
242
243
  ts = [
243
244
  {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 3, :USD)},
244
245
  {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-3, :USD)},
@@ -334,7 +335,7 @@ describe Money do
334
335
  end
335
336
 
336
337
  describe "#div" do
337
- it "divides Money by Fixnum and returns Money" do
338
+ it "divides Money by Integer and returns Money" do
338
339
  ts = [
339
340
  {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 3, :USD)},
340
341
  {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-3, :USD)},
@@ -387,7 +388,7 @@ describe Money do
387
388
  end
388
389
 
389
390
  describe "#divmod" do
390
- it "calculates division and modulo with Fixnum" do
391
+ it "calculates division and modulo with Integer" do
391
392
  ts = [
392
393
  {:a => Money.new( 13, :USD), :b => 4, :c => [Money.new( 3, :USD), Money.new( 1, :USD)]},
393
394
  {:a => Money.new( 13, :USD), :b => -4, :c => [Money.new(-4, :USD), Money.new(-3, :USD)]},
@@ -450,7 +451,7 @@ describe Money do
450
451
  end
451
452
 
452
453
  describe "#modulo" do
453
- it "calculates modulo with Fixnum" do
454
+ it "calculates modulo with Integer" do
454
455
  ts = [
455
456
  {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 1, :USD)},
456
457
  {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-3, :USD)},
@@ -489,7 +490,7 @@ describe Money do
489
490
  end
490
491
 
491
492
  describe "#%" do
492
- it "calculates modulo with Fixnum" do
493
+ it "calculates modulo with Integer" do
493
494
  ts = [
494
495
  {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 1, :USD)},
495
496
  {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-3, :USD)},
@@ -528,7 +529,7 @@ describe Money do
528
529
  end
529
530
 
530
531
  describe "#remainder" do
531
- it "calculates remainder with Fixnum" do
532
+ it "calculates remainder with Integer" do
532
533
  ts = [
533
534
  {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 1, :USD)},
534
535
  {:a => Money.new( 13, :USD), :b => -4, :c => Money.new( 1, :USD)},
@@ -659,4 +660,34 @@ describe Money do
659
660
  }.to raise_exception(TypeError)
660
661
  end
661
662
  end
663
+
664
+ %w(+ - / <=> divmod remainder).each do |op|
665
+ describe "##{op}" do
666
+ subject { ->(other = self.other) { instance.send(op, other) } }
667
+ let(:instance) { Money.usd(1) }
668
+
669
+ context 'when conversions disallowed' do
670
+ around do |ex|
671
+ begin
672
+ old = Money.default_bank
673
+ Money.disallow_currency_conversion!
674
+ ex.run
675
+ ensure
676
+ Money.default_bank = old
677
+ end
678
+ end
679
+
680
+ context 'and other is money with different currency' do
681
+ let(:other) { Money.gbp(1) }
682
+ it { should raise_error Money::Bank::DifferentCurrencyError }
683
+
684
+ context 'even for zero' do
685
+ let(:instance) { Money.usd(0) }
686
+ let(:other) { Money.gbp(0) }
687
+ it { should raise_error Money::Bank::DifferentCurrencyError }
688
+ end
689
+ end
690
+ end
691
+ end
692
+ end
662
693
  end
@@ -7,18 +7,6 @@ describe Money::Constructors do
7
7
  expect(Money.empty).to eq Money.new(0)
8
8
  end
9
9
 
10
- it "memoizes the result" do
11
- expect(Money.empty.object_id).to eq Money.empty.object_id
12
- end
13
-
14
- it "memoizes a result for each currency" do
15
- expect(Money.empty(:cad).object_id).to eq Money.empty(:cad).object_id
16
- end
17
-
18
- it "doesn't allow money to be modified for a currency" do
19
- expect(Money.empty).to be_frozen
20
- end
21
-
22
10
  it "instantiates a subclass when inheritance is used" do
23
11
  special_money_class = Class.new(Money)
24
12
  expect(special_money_class.empty).to be_a special_money_class
@@ -707,6 +707,22 @@ describe Money, "formatting" do
707
707
  expect(Money.new(1999_98, "SEK").format(disambiguate: true)).to eq("1 999,98 SEK")
708
708
  end
709
709
 
710
+ it "returns disambiguate signs when disambiguate: true and symbol: true" do
711
+ expect(Money.new(1999_98, "USD").format(disambiguate: true, symbol: true)).to eq("US$1,999.98")
712
+ expect(Money.new(1999_98, "CAD").format(disambiguate: true, symbol: true)).to eq("C$1,999.98")
713
+ expect(Money.new(1999_98, "DKK").format(disambiguate: true, symbol: true)).to eq("1.999,98 DKK")
714
+ expect(Money.new(1999_98, "NOK").format(disambiguate: true, symbol: true)).to eq("1.999,98 NOK")
715
+ expect(Money.new(1999_98, "SEK").format(disambiguate: true, symbol: true)).to eq("1 999,98 SEK")
716
+ end
717
+
718
+ it "returns no signs when disambiguate: true and symbol: false" do
719
+ expect(Money.new(1999_98, "USD").format(disambiguate: true, symbol: false)).to eq("1,999.98")
720
+ expect(Money.new(1999_98, "CAD").format(disambiguate: true, symbol: false)).to eq("1,999.98")
721
+ expect(Money.new(1999_98, "DKK").format(disambiguate: true, symbol: false)).to eq("1.999,98")
722
+ expect(Money.new(1999_98, "NOK").format(disambiguate: true, symbol: false)).to eq("1.999,98")
723
+ expect(Money.new(1999_98, "SEK").format(disambiguate: true, symbol: false)).to eq("1 999,98")
724
+ end
725
+
710
726
  it "should never return an ambiguous format with disambiguate: true" do
711
727
  formatted_results = {}
712
728
 
@@ -191,7 +191,7 @@ describe Money do
191
191
  it "stores fractional as an integer regardless of what is passed into the constructor" do
192
192
  m = Money.new(100)
193
193
  expect(m.fractional).to eq 100
194
- expect(m.fractional).to be_a(Fixnum)
194
+ expect(m.fractional).to be_a(Integer)
195
195
  end
196
196
 
197
197
  context "loading a serialized Money via YAML" do
@@ -349,9 +349,9 @@ YAML
349
349
  expect {money.round_to_nearest_cash_value}.to raise_error(Money::UndefinedSmallestDenomination)
350
350
  end
351
351
 
352
- it "returns a Fixnum when infinite_precision is not set" do
352
+ it "returns a Integer when infinite_precision is not set" do
353
353
  money = Money.new(100, "USD")
354
- expect(money.round_to_nearest_cash_value).to be_a Fixnum
354
+ expect(money.round_to_nearest_cash_value).to be_a Integer
355
355
  end
356
356
 
357
357
  it "returns a BigDecimal when infinite_precision is set", :infinite_precision do
@@ -408,12 +408,16 @@ YAML
408
408
  end
409
409
 
410
410
  describe "#currency_as_string=" do
411
- it "sets the currency object using the provided string" do
411
+ it "sets the currency object using the provided string leaving cents intact" do
412
412
  money = Money.new(100_00, "USD")
413
+
413
414
  money.currency_as_string = "EUR"
414
415
  expect(money.currency).to eq Money::Currency.new("EUR")
416
+ expect(money.cents).to eq 100_00
417
+
415
418
  money.currency_as_string = "YEN"
416
419
  expect(money.currency).to eq Money::Currency.new("YEN")
420
+ expect(money.cents).to eq 100_00
417
421
  end
418
422
  end
419
423
 
@@ -584,6 +588,23 @@ YAML
584
588
  expect(moneys[2].cents).to eq 33
585
589
  end
586
590
 
591
+ context "negative amount" do
592
+ it "does not lose pennies" do
593
+ moneys = Money.us_dollar(-100).allocate([0.333, 0.333, 0.333])
594
+
595
+ expect(moneys[0].cents).to eq -34
596
+ expect(moneys[1].cents).to eq -33
597
+ expect(moneys[2].cents).to eq -33
598
+ end
599
+
600
+ it "allocates the same way as positive amounts" do
601
+ ratios = [0.6667, 0.3333]
602
+
603
+ expect(Money.us_dollar(10_00).allocate(ratios).map(&:fractional)).to eq([6_67, 3_33])
604
+ expect(Money.us_dollar(-10_00).allocate(ratios).map(&:fractional)).to eq([-6_67, -3_33])
605
+ end
606
+ end
607
+
587
608
  it "requires total to be less then 1" do
588
609
  expect { Money.us_dollar(0.05).allocate([0.5, 0.6]) }.to raise_error(ArgumentError)
589
610
  end
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.1
4
+ version: 6.8.0
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-05-08 00:00:00.000000000 Z
11
+ date: 2017-01-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -171,15 +171,7 @@ homepage: http://rubymoney.github.io/money
171
171
  licenses:
172
172
  - MIT
173
173
  metadata: {}
174
- post_install_message: |
175
- Please note the following API changes in Money version 6
176
-
177
- - Money#amount, Money#dollars methods now return instances of BigDecimal (rather than Float).
178
-
179
- Please read the migration notes at https://github.com/RubyMoney/money#migration-notes
180
- and choose the migration that best suits your application.
181
-
182
- Test responsibly :-)
174
+ post_install_message:
183
175
  rdoc_options: []
184
176
  require_paths:
185
177
  - lib