money 6.16.0 → 6.19.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -0
- data/LICENSE +1 -1
- data/README.md +58 -1
- data/config/currency_backwards_compatible.json +16 -0
- data/config/currency_iso.json +41 -23
- data/config/currency_non_iso.json +16 -0
- data/lib/money/money/allocation.rb +29 -7
- data/lib/money/money/formatter.rb +13 -2
- data/lib/money/money/formatting_rules.rb +1 -1
- data/lib/money/money.rb +1 -0
- data/lib/money/version.rb +1 -1
- data/money.gemspec +0 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 331d852b12ab9a5e62108f3610d1ec5eed8f4fa9bb683be1aab2703cd2df26cd
|
4
|
+
data.tar.gz: 56e2bcad250542c80b800db800c2216dd2b3b10f1df5d8a77819d13153a77844
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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)
|
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
|
-
[![
|
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",
|
data/config/currency_iso.json
CHANGED
@@ -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": "
|
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": "R",
|
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
|
6
|
-
#
|
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
|
12
|
-
#
|
13
|
-
#
|
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
|
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
|
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
|
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
data/lib/money/version.rb
CHANGED
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.
|
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:
|
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.
|
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.
|