money 6.16.0 → 6.19.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
  SHA256:
3
- metadata.gz: 3de47437ec002ed24a400508cac96b2ff6812f484c666fe3db3a82e921a805c0
4
- data.tar.gz: f96755602e56ea81d734b7505e7cfc88caaa948d7a8d285eeb470801028c15b9
3
+ metadata.gz: 331d852b12ab9a5e62108f3610d1ec5eed8f4fa9bb683be1aab2703cd2df26cd
4
+ data.tar.gz: 56e2bcad250542c80b800db800c2216dd2b3b10f1df5d8a77819d13153a77844
5
5
  SHA512:
6
- metadata.gz: 2f8cd71611e96a80cb733651675cb6fac59d358cb7c9576c8c264abbfec6eb1da11b8cbe2af12cdfb070e5dd01cd74f6fdc70772da16aa4c2abc5248b13fca3c
7
- data.tar.gz: '092ba5a188eb29d462431e94420e1c6d7a7f9a4a59c0895f66a4a1cf92cfaa37cbc1bc344a241f5f8cc9fc4e998189164bc2d0ab11480a589fe7bb0e341754ba'
6
+ metadata.gz: ae6d529a7382aaab721a4ae933658828f975eaa4c9a0ad9444b74b28d8ff1141d59f3e264d08b650367e327987266be03dcd480e0a850fe224feb6cdca4163d1
7
+ data.tar.gz: bbb76570efd7bf4be700cc3f46d01e26945e9790f5f9f3fee666d4ac3164d1422f5ca1614622a429c430804a9047bcc8f5178886905e5ad814ce21ab4117f94a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## Upcoming
4
+
5
+ -
6
+
7
+ ## 6.19.0
8
+
9
+ - Change Peruvian Sol (PEN) decimal mark and thousands separator.
10
+ - Improves Precision and Simplifies Allocation Logic
11
+ - explicit declaration of i18n locales
12
+ - Add space to CHF format
13
+ - Update deprecation message to suggest correct formatting.
14
+
15
+ ## 6.18.0
16
+
17
+ - Add second dobra (STN) from São Tomé and Príncipe
18
+ - Correct South African Rand (ZAR) to use comma decimal mark, and space thousands separator
19
+ - Use euro symbol as html_entity for euro currency
20
+ - Update Georgian Lari symbol
21
+ - Add Ruby 3.1 and 3.2 to the CI matrix
22
+ - Add `Money.from_dollars` alias as a more explicit initializer, it's the same as `Money.from_amount`
23
+ - Mark Croatian Kuna (HRK) as obsolete by moving its definition to the backwards compatibility data source
24
+
25
+ ## 6.17.0
26
+
27
+ - Allow true for `thousands_separator`
28
+
3
29
  ## 6.16.0
4
30
 
5
31
  - Add `Money.from_cents` alias as a more explicit initializer, it's the same as `Money.new`
data/LICENSE CHANGED
@@ -2,7 +2,7 @@ MIT License
2
2
 
3
3
  Copyright (c) 2005 Tobias Lutke
4
4
  Copyright (c) 2008 Phusion
5
- Copyright (c) 2021 Shane Emmons
5
+ Copyright (c) 2024 Shane Emmons
6
6
 
7
7
  Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # RubyMoney - Money
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/money.svg)](https://rubygems.org/gems/money)
4
- [![Build Status](https://travis-ci.org/RubyMoney/money.svg?branch=master)](https://travis-ci.org/RubyMoney/money)
4
+ [![Ruby](https://github.com/RubyMoney/money/actions/workflows/ruby.yml/badge.svg)](https://github.com/RubyMoney/money/actions/workflows/ruby.yml)
5
5
  [![Code Climate](https://codeclimate.com/github/RubyMoney/money.svg)](https://codeclimate.com/github/RubyMoney/money)
6
6
  [![Inline docs](https://inch-ci.org/github/RubyMoney/money.svg)](https://inch-ci.org/github/RubyMoney/money)
7
7
  [![License](https://img.shields.io/github/license/RubyMoney/money.svg)](https://opensource.org/licenses/MIT)
@@ -60,6 +60,10 @@ The development version (hosted on Github) can be installed with:
60
60
  ``` ruby
61
61
  require 'money'
62
62
 
63
+ # explicitly define locales
64
+ I18n.config.available_locales = :en
65
+ Money.locale_backend = :i18n
66
+
63
67
  # 10.00 USD
64
68
  money = Money.from_cents(1000, "USD")
65
69
  money.cents #=> 1000
@@ -334,6 +338,59 @@ class ExchangeRate < ApplicationRecord
334
338
  yield rate.from, rate.to, rate.rate
335
339
  end
336
340
  end
341
+
342
+ def self.marshal_dump
343
+ [self]
344
+ end
345
+ end
346
+ ```
347
+
348
+ The following example implements a `Redis` store to save exchange rates to a redis database.
349
+
350
+ ```ruby
351
+
352
+ class RedisRateStore
353
+ INDEX_KEY_SEPARATOR = '_TO_'.freeze
354
+
355
+ # Using second db of the redis instance
356
+ # because sidekiq uses the first db
357
+ REDIS_DATABASE = 1
358
+
359
+ # Using Hash to store rates data
360
+ REDIS_STORE_KEY = 'rates'
361
+
362
+ def initialize
363
+ conn_url = "#{Rails.application.credentials.redis_server}/#{REDIS_DATABASE}"
364
+ @connection = Redis.new(url: conn_url)
365
+ end
366
+
367
+ def add_rate(iso_from, iso_to, rate)
368
+ @connection.hset(REDIS_STORE_KEY, rate_key_for(iso_from, iso_to), rate)
369
+ end
370
+
371
+ def get_rate(iso_from, iso_to)
372
+ @connection.hget(REDIS_STORE_KEY, rate_key_for(iso_from, iso_to))
373
+ end
374
+
375
+ def each_rate
376
+ rates = @connection.hgetall(REDIS_STORE_KEY)
377
+ return to_enum(:each_rate) unless block_given?
378
+
379
+ rates.each do |key, rate|
380
+ iso_from, iso_to = key.split(INDEX_KEY_SEPARATOR)
381
+ yield iso_from, iso_to, rate
382
+ end
383
+ end
384
+
385
+ def transaction
386
+ yield
387
+ end
388
+
389
+ private
390
+
391
+ def rate_key_for(iso_from, iso_to)
392
+ [iso_from, iso_to].join(INDEX_KEY_SEPARATOR).upcase
393
+ end
337
394
  end
338
395
  ```
339
396
 
@@ -31,6 +31,22 @@
31
31
  "iso_numeric": "288",
32
32
  "smallest_denomination": 1
33
33
  },
34
+ "hrk": {
35
+ "priority": 100,
36
+ "iso_code": "HRK",
37
+ "name": "Croatian Kuna",
38
+ "symbol": "kn",
39
+ "alternate_symbols": [],
40
+ "subunit": "Lipa",
41
+ "subunit_to_unit": 100,
42
+ "symbol_first": false,
43
+ "format": "%n %u",
44
+ "html_entity": "",
45
+ "decimal_mark": ",",
46
+ "thousands_separator": ".",
47
+ "iso_numeric": "191",
48
+ "smallest_denomination": 1
49
+ },
34
50
  "ltl": {
35
51
  "priority": 100,
36
52
  "iso_code": "LTL",
@@ -452,7 +452,7 @@
452
452
  "subunit": "Rappen",
453
453
  "subunit_to_unit": 100,
454
454
  "symbol_first": true,
455
- "format": "%u%n",
455
+ "format": "%u %n",
456
456
  "html_entity": "",
457
457
  "decimal_mark": ".",
458
458
  "thousands_separator": ",",
@@ -723,7 +723,7 @@
723
723
  "subunit": "Cent",
724
724
  "subunit_to_unit": 100,
725
725
  "symbol_first": true,
726
- "html_entity": "&#x20AC;",
726
+ "html_entity": "",
727
727
  "decimal_mark": ",",
728
728
  "thousands_separator": ".",
729
729
  "iso_numeric": "978",
@@ -782,7 +782,7 @@
782
782
  "priority": 100,
783
783
  "iso_code": "GEL",
784
784
  "name": "Georgian Lari",
785
- "symbol": "",
785
+ "symbol": "",
786
786
  "alternate_symbols": ["lari"],
787
787
  "subunit": "Tetri",
788
788
  "subunit_to_unit": 100,
@@ -922,22 +922,6 @@
922
922
  "iso_numeric": "340",
923
923
  "smallest_denomination": 5
924
924
  },
925
- "hrk": {
926
- "priority": 100,
927
- "iso_code": "HRK",
928
- "name": "Croatian Kuna",
929
- "symbol": "kn",
930
- "alternate_symbols": [],
931
- "subunit": "Lipa",
932
- "subunit_to_unit": 100,
933
- "symbol_first": false,
934
- "format": "%n %u",
935
- "html_entity": "",
936
- "decimal_mark": ",",
937
- "thousands_separator": ".",
938
- "iso_numeric": "191",
939
- "smallest_denomination": 1
940
- },
941
925
  "htg": {
942
926
  "priority": 100,
943
927
  "iso_code": "HTG",
@@ -1706,8 +1690,8 @@
1706
1690
  "subunit_to_unit": 100,
1707
1691
  "symbol_first": true,
1708
1692
  "html_entity": "S/",
1709
- "decimal_mark": ".",
1710
- "thousands_separator": ",",
1693
+ "decimal_mark": ",",
1694
+ "thousands_separator": ".",
1711
1695
  "iso_numeric": "604",
1712
1696
  "smallest_denomination": 1
1713
1697
  },
@@ -1999,11 +1983,28 @@
1999
1983
  "iso_numeric": "703",
2000
1984
  "smallest_denomination": 50
2001
1985
  },
1986
+ "sle": {
1987
+ "priority": 100,
1988
+ "iso_code": "SLE",
1989
+ "name": "New Leone",
1990
+ "symbol": "Le",
1991
+ "alternate_symbols": [],
1992
+ "subunit": "Cent",
1993
+ "subunit_to_unit": 100,
1994
+ "symbol_first": false,
1995
+ "format": "%n %u",
1996
+ "html_entity": "",
1997
+ "decimal_mark": ".",
1998
+ "thousands_separator": ",",
1999
+ "iso_numeric": "925",
2000
+ "smallest_denomination": 1000
2001
+ },
2002
2002
  "sll": {
2003
2003
  "priority": 100,
2004
2004
  "iso_code": "SLL",
2005
2005
  "name": "Sierra Leonean Leone",
2006
2006
  "symbol": "Le",
2007
+ "disambiguate_symbol": "SLL",
2007
2008
  "alternate_symbols": [],
2008
2009
  "subunit": "Cent",
2009
2010
  "subunit_to_unit": 100,
@@ -2081,6 +2082,23 @@
2081
2082
  "iso_numeric": "678",
2082
2083
  "smallest_denomination": 10000
2083
2084
  },
2085
+ "stn": {
2086
+ "priority": 100,
2087
+ "iso_code": "STN",
2088
+ "name": "São Tomé and Príncipe Second Dobra",
2089
+ "symbol": "Db",
2090
+ "disambiguate_symbol": "STN",
2091
+ "alternate_symbols": [],
2092
+ "subunit": "Cêntimo",
2093
+ "subunit_to_unit": 100,
2094
+ "symbol_first": false,
2095
+ "format": "%n %u",
2096
+ "html_entity": "",
2097
+ "decimal_mark": ".",
2098
+ "thousands_separator": ",",
2099
+ "iso_numeric": "930",
2100
+ "smallest_denomination": 10
2101
+ },
2084
2102
  "svc": {
2085
2103
  "priority": 100,
2086
2104
  "iso_code": "SVC",
@@ -2661,8 +2679,8 @@
2661
2679
  "subunit_to_unit": 100,
2662
2680
  "symbol_first": true,
2663
2681
  "html_entity": "&#x0052;",
2664
- "decimal_mark": ".",
2665
- "thousands_separator": ",",
2682
+ "decimal_mark": ",",
2683
+ "thousands_separator": " ",
2666
2684
  "iso_numeric": "710",
2667
2685
  "smallest_denomination": 10
2668
2686
  },
@@ -126,5 +126,21 @@
126
126
  "thousands_separator": ",",
127
127
  "iso_numeric": "",
128
128
  "smallest_denomination": 1
129
+ },
130
+ "usdc": {
131
+ "priority": 100,
132
+ "iso_code": "USDC",
133
+ "name": "USD Coin",
134
+ "symbol": "USDC",
135
+ "disambiguate_symbol": "USDC",
136
+ "alternate_symbols": [],
137
+ "subunit": "Cent",
138
+ "subunit_to_unit": 100,
139
+ "symbol_first": false,
140
+ "html_entity": "$",
141
+ "decimal_mark": ".",
142
+ "thousands_separator": ",",
143
+ "iso_numeric": "",
144
+ "smallest_denomination": 1
129
145
  }
130
146
  }
@@ -2,16 +2,17 @@
2
2
 
3
3
  class Money
4
4
  class Allocation
5
- # Splits a given amount in parts without losing pennies.
6
- # The left-over pennies will be distributed round-robin amongst the parts. This means that
7
- # parts listed first will likely receive more pennies than the ones listed later.
5
+ # Splits a given amount in parts. The allocation is based on the parts' proportions
6
+ # or evenly if parts are numerically specified.
8
7
  #
9
8
  # The results should always add up to the original amount.
10
9
  #
11
- # The parts can be specified as:
12
- # Numeric performs the split between a given number of parties evenely
13
- # Array<Numeric> allocates the amounts proportionally to the given array
10
+ # @param amount [Numeric] The total amount to be allocated.
11
+ # @param parts [Numeric, Array<Numeric>] Number of parts to split into or an array (proportions for allocation)
12
+ # @param whole_amounts [Boolean] Specifies whether to allocate whole amounts only. Defaults to true.
14
13
  #
14
+ # @return [Array<Numeric>] An array containing the allocated amounts.
15
+ # @raise [ArgumentError] If parts is empty or not provided.
15
16
  def self.generate(amount, parts, whole_amounts = true)
16
17
  parts = if parts.is_a?(Numeric)
17
18
  Array.new(parts, 1)
@@ -21,7 +22,12 @@ class Money
21
22
  parts.dup
22
23
  end
23
24
 
24
- raise ArgumentError, 'need at least one party' if parts.empty?
25
+ raise ArgumentError, 'need at least one part' if parts.empty?
26
+
27
+ if [amount, *parts].any? { |i| i.is_a?(BigDecimal) || i.is_a?(Float) || i.is_a?(Rational) }
28
+ amount = convert_to_big_decimal(amount)
29
+ parts.map! { |p| convert_to_big_decimal(p) }
30
+ end
25
31
 
26
32
  result = []
27
33
  remaining_amount = amount
@@ -42,5 +48,21 @@ class Money
42
48
 
43
49
  result
44
50
  end
51
+
52
+ # Converts a given number to BigDecimal.
53
+ # This method supports inputs of BigDecimal, Rational, and other numeric types by ensuring they are all returned
54
+ # as BigDecimal instances for consistent handling.
55
+ #
56
+ # @param number [Numeric, BigDecimal, Rational] The number to convert.
57
+ # @return [BigDecimal] The converted number as a BigDecimal.
58
+ def self.convert_to_big_decimal(number)
59
+ if number.is_a? BigDecimal
60
+ number
61
+ elsif number.is_a? Rational
62
+ BigDecimal(number.to_f.to_s)
63
+ else
64
+ BigDecimal(number.to_s)
65
+ end
66
+ end
45
67
  end
46
68
  end
@@ -124,11 +124,14 @@ class Money
124
124
  # the currency should be delimited by the specified character or ','
125
125
  #
126
126
  # @example
127
- # # If false is specified, no thousands_separator is used.
127
+ # # If a falsey value is specified, no thousands_separator is used.
128
128
  # Money.new(100000, "USD").format(thousands_separator: false) #=> "1000.00"
129
129
  # Money.new(100000, "USD").format(thousands_separator: nil) #=> "1000.00"
130
130
  # Money.new(100000, "USD").format(thousands_separator: "") #=> "1000.00"
131
131
  #
132
+ # # If true is specified, the locale or default thousands_separator is used.
133
+ # Money.new(100000, "USD").format(thousands_separator: true) #=> "1,000.00"
134
+ #
132
135
  # # If a string is specified, it's value is used.
133
136
  # Money.new(100000, "USD").format(thousands_separator: ".") #=> "$1.000.00"
134
137
  #
@@ -241,7 +244,11 @@ class Money
241
244
  end
242
245
 
243
246
  def thousands_separator
244
- lookup :thousands_separator
247
+ val = lookup :thousands_separator
248
+
249
+ return val unless val == true
250
+
251
+ lookup_default :thousands_separator
245
252
  end
246
253
 
247
254
  def decimal_mark
@@ -371,6 +378,10 @@ class Money
371
378
  def lookup(key)
372
379
  return rules[key] || DEFAULTS[key] if rules.has_key?(key)
373
380
 
381
+ lookup_default key
382
+ end
383
+
384
+ def lookup_default(key)
374
385
  (Money.locale_backend && Money.locale_backend.lookup(key, currency)) || DEFAULTS[key]
375
386
  end
376
387
 
@@ -117,7 +117,7 @@ class Money
117
117
  def warn_about_deprecated_rules(rules)
118
118
  if rules.has_key?(:symbol_position)
119
119
  position = rules[:symbol_position]
120
- template = position == :before ? '%u %n' : '%n %u'
120
+ template = position == :before ? '%u%n' : '%n%u'
121
121
 
122
122
  warn "[DEPRECATION] `symbol_position: :#{position}` is deprecated - you can replace it with `format: #{template}`"
123
123
  end
data/lib/money/money.rb CHANGED
@@ -314,6 +314,7 @@ class Money
314
314
 
315
315
  class << self
316
316
  alias_method :from_cents, :new
317
+ alias_method :from_dollars, :from_amount
317
318
  end
318
319
 
319
320
  # Creates a new Money object of value given in the
data/lib/money/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Money
2
- VERSION = '6.16.0'
2
+ VERSION = '6.19.0'
3
3
  end
data/money.gemspec CHANGED
@@ -23,8 +23,6 @@ Gem::Specification.new do |s|
23
23
  s.add_development_dependency "kramdown", "~> 2.3"
24
24
 
25
25
  s.files = `git ls-files -z -- config/* lib/* CHANGELOG.md LICENSE money.gemspec README.md`.split("\x0")
26
- s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
27
- s.test_files = s.files.grep(%r{^(test|spec|features)/})
28
26
  s.require_paths = ["lib"]
29
27
 
30
28
  if s.respond_to?(:metadata)
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.16.0
4
+ version: 6.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shane Emmons
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-05-09 00:00:00.000000000 Z
12
+ date: 2024-03-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: i18n
@@ -159,7 +159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
159
159
  - !ruby/object:Gem::Version
160
160
  version: '0'
161
161
  requirements: []
162
- rubygems_version: 3.2.3
162
+ rubygems_version: 3.5.3
163
163
  signing_key:
164
164
  specification_version: 4
165
165
  summary: A Ruby Library for dealing with money and currency conversion.