money 6.7.1 → 6.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 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