minting 1.6.3 → 1.7.2
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 +4 -4
- data/README.md +71 -113
- data/Rakefile +25 -3
- data/bin/bench_check +46 -0
- data/doc/Mint/Currency.html +1139 -0
- data/doc/Mint/CurrencyRegistry.html +511 -0
- data/doc/Mint/Money.html +3859 -0
- data/doc/Mint/RangeStepPatch.html +277 -0
- data/doc/Mint/UnknownCurrency.html +136 -0
- data/doc/Mint.html +911 -0
- data/doc/Minting.html +142 -0
- data/doc/_index.html +173 -0
- data/doc/class_list.html +54 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +206 -0
- data/doc/css/style.css +1089 -0
- data/doc/file.README.html +275 -0
- data/doc/file_list.html +59 -0
- data/doc/frames.html +22 -0
- data/doc/index.html +275 -0
- data/doc/js/app.js +801 -0
- data/doc/js/full_list.js +334 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +518 -0
- data/doc/top-level-namespace.html +151 -0
- data/lib/minting/{mint/currency → currency}/currency.rb +8 -0
- data/lib/minting/{mint/currency → currency}/currency_registry.rb +1 -1
- data/lib/minting/{mint/currency → currency}/world_currencies.rb +1 -1
- data/lib/minting/mint/aliases.rb +3 -0
- data/lib/minting/mint/dsl/numeric.rb +23 -0
- data/lib/minting/mint/dsl/range.rb +67 -0
- data/lib/minting/mint/dsl/string.rb +12 -0
- data/lib/minting/mint/{dsl.rb → dsl/top_level.rb} +3 -18
- data/lib/minting/mint/mint.rb +17 -3
- data/lib/minting/mint/{parser.rb → parser/parser.rb} +17 -29
- data/lib/minting/mint/parser/separators.rb +39 -0
- data/lib/minting/mint.rb +19 -8
- data/lib/minting/money/allocation/allocation.rb +25 -0
- data/lib/minting/money/allocation/split.rb +41 -0
- data/lib/minting/money/arithmetics/methods.rb +27 -0
- data/lib/minting/money/{arithmetics.rb → arithmetics/operators.rb} +5 -26
- data/lib/minting/money/clamp.rb +66 -0
- data/lib/minting/money/coercion.rb +18 -11
- data/lib/minting/money/comparable.rb +6 -0
- data/lib/minting/money/constructors.rb +13 -3
- data/lib/minting/money/format/formatting.rb +44 -0
- data/lib/minting/money/{formatting.rb → format/to_s.rb} +5 -42
- data/lib/minting/money/money.rb +0 -58
- data/lib/minting/version.rb +1 -1
- data/minting.gemspec +5 -2
- metadata +42 -11
- data/lib/minting/money/allocation.rb +0 -59
|
@@ -13,7 +13,9 @@ module Mint
|
|
|
13
13
|
checked_currency = Mint.currency(currency)
|
|
14
14
|
raise ArgumentError, "Currency not found (#{currency})" unless checked_currency
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
amount = checked_currency.normalize_amount(amount)
|
|
17
|
+
|
|
18
|
+
amount.zero? ? Mint.zero(checked_currency) : new(amount, checked_currency)
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
# Builds a Money from a fractional (smallest-unit) Integer amount.
|
|
@@ -41,7 +43,8 @@ module Mint
|
|
|
41
43
|
raise ArgumentError, "Currency not found (#{currency})" unless checked_currency
|
|
42
44
|
|
|
43
45
|
amount = Rational(fractional, checked_currency.fractional_multiplier)
|
|
44
|
-
|
|
46
|
+
|
|
47
|
+
amount.zero? ? Mint.zero(checked_currency) : new(amount, checked_currency)
|
|
45
48
|
end
|
|
46
49
|
|
|
47
50
|
# Returns a new Money object with the specified amount, or self if unchanged.
|
|
@@ -56,7 +59,14 @@ module Mint
|
|
|
56
59
|
# price.mint(10.00) #=> [USD 10.00] (returns self)
|
|
57
60
|
def mint(new_amount)
|
|
58
61
|
new_amount = currency.normalize_amount(new_amount)
|
|
59
|
-
|
|
62
|
+
|
|
63
|
+
if new_amount == amount
|
|
64
|
+
self
|
|
65
|
+
elsif new_amount.zero?
|
|
66
|
+
Mint.zero(currency)
|
|
67
|
+
else
|
|
68
|
+
Money.new(new_amount, currency)
|
|
69
|
+
end
|
|
60
70
|
end
|
|
61
71
|
|
|
62
72
|
private
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mint
|
|
4
|
+
# Formatting functionality for Money objects
|
|
5
|
+
class Money
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
# Selects the appropriate format template and value based on the amount's sign.
|
|
9
|
+
# @private
|
|
10
|
+
def select_format(format)
|
|
11
|
+
negative_format = format[:negative]
|
|
12
|
+
zero_format = format[:zero]
|
|
13
|
+
|
|
14
|
+
if amount.negative? && negative_format
|
|
15
|
+
[negative_format, -amount]
|
|
16
|
+
elsif amount.zero? && zero_format
|
|
17
|
+
[zero_format, amount]
|
|
18
|
+
else
|
|
19
|
+
[format[:positive], amount]
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Validates that format hash contains only known keys.
|
|
24
|
+
# @private
|
|
25
|
+
def validate_format_hash(format)
|
|
26
|
+
unknown = format.keys - %i[positive negative zero]
|
|
27
|
+
|
|
28
|
+
raise ArgumentError, "Unknown format parameter(s): #{unknown.inspect}. " unless unknown.empty?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Applies a format template to produce a formatted string representation.
|
|
32
|
+
# @private
|
|
33
|
+
def format_amount(format)
|
|
34
|
+
format, value = select_format(format)
|
|
35
|
+
format ||= '%<symbol>s%<amount>f'
|
|
36
|
+
# Automatically adjust decimal places based on currency subunit if missing
|
|
37
|
+
format = format.gsub(/%<amount>(\s*\+?\d*)f/, "%<amount>\\1.#{currency.subunit}f")
|
|
38
|
+
|
|
39
|
+
refs = format.scan(/%<(\w+)>/).flatten.map(&:to_sym)
|
|
40
|
+
all_args = { amount: value, currency: currency_code, symbol: currency.symbol }
|
|
41
|
+
Kernel.format(format, **all_args.slice(*refs))
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -45,10 +45,10 @@ module Mint
|
|
|
45
45
|
#
|
|
46
46
|
def to_s(format: '%<symbol>s%<amount>f', decimal: '.', thousand: ',', width: nil)
|
|
47
47
|
case format
|
|
48
|
-
when {}, ''
|
|
49
|
-
when Hash
|
|
50
|
-
when String
|
|
51
|
-
else
|
|
48
|
+
when {}, '' then raise ArgumentError, 'format must not be empty'
|
|
49
|
+
when Hash then validate_format_hash(format)
|
|
50
|
+
when String then format = { positive: format }
|
|
51
|
+
else raise ArgumentError, 'Invalid format. Only String or Hash are accepted'
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
formatted = format_amount(format)
|
|
@@ -61,44 +61,7 @@ module Mint
|
|
|
61
61
|
formatted.gsub!(/(\d)(?=(?:\d{3})+(?:[^\d]{1}|$))/, "\\1#{thousand}")
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
formatted
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
private
|
|
69
|
-
|
|
70
|
-
def validate_format_hash!(format)
|
|
71
|
-
unknown = format.keys - %i[positive negative zero]
|
|
72
|
-
|
|
73
|
-
raise ArgumentError, "Unknown format parameter(s): #{unknown.inspect}. " unless unknown.empty?
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def format_amount(format)
|
|
77
|
-
format = { positive: format } if format.is_a?(String)
|
|
78
|
-
positive_format = format[:positive]
|
|
79
|
-
negative_format = format[:negative]
|
|
80
|
-
zero_format = format[:zero]
|
|
81
|
-
|
|
82
|
-
if amount.negative? && negative_format
|
|
83
|
-
format = negative_format
|
|
84
|
-
value = -amount
|
|
85
|
-
elsif amount.zero? && zero_format
|
|
86
|
-
format = zero_format
|
|
87
|
-
value = amount
|
|
88
|
-
else
|
|
89
|
-
format = positive_format
|
|
90
|
-
value = amount
|
|
91
|
-
end
|
|
92
|
-
format ||= '%<symbol>s%<amount>f'
|
|
93
|
-
|
|
94
|
-
# Automatically adjust decimal places based on currency subunit if missing
|
|
95
|
-
adjusted_format = format
|
|
96
|
-
.gsub(/%<amount>(\s*\+?\d*)f/, "%<amount>\\1.#{currency.subunit}f")
|
|
97
|
-
|
|
98
|
-
Kernel.format(adjusted_format,
|
|
99
|
-
amount: value,
|
|
100
|
-
currency: currency_code,
|
|
101
|
-
symbol: currency.symbol)
|
|
64
|
+
width ? formatted.rjust(width) : formatted
|
|
102
65
|
end
|
|
103
66
|
end
|
|
104
67
|
end
|
data/lib/minting/money/money.rb
CHANGED
|
@@ -43,63 +43,5 @@ module Mint
|
|
|
43
43
|
# @param other [Currency] the target currency to compare
|
|
44
44
|
# @return [Boolean] true if currencies match, false otherwise
|
|
45
45
|
def same_currency?(other) = other.currency == currency
|
|
46
|
-
|
|
47
|
-
# Constrains +self+ to the inclusive range [+min+, +max+].
|
|
48
|
-
#
|
|
49
|
-
# Bounds may be:
|
|
50
|
-
# - nil meaning no boundary
|
|
51
|
-
# - same-currency {Money} or Range
|
|
52
|
-
# - Numeric amount, or Range
|
|
53
|
-
#
|
|
54
|
-
# Numeric is interpreted as an amount in +self+'s currency, so the common
|
|
55
|
-
# pricing idiom +price.clamp(0, 100)+ reads as "0 to 100 in the same
|
|
56
|
-
# currency as +price+".
|
|
57
|
-
#
|
|
58
|
-
# When +self+ is already in range the receiver is returned (no new object
|
|
59
|
-
# allocated). When out of range, the nearest bound is returned as a new
|
|
60
|
-
# frozen {Money} in +self+'s currency.
|
|
61
|
-
#
|
|
62
|
-
# @param min_or_range [Money, Numeric, Range, nil] lower bound (inclusive), or range
|
|
63
|
-
# @param max [Money, Numeric, nil] upper bound (inclusive)
|
|
64
|
-
# @return [Money] +self+ if in range, otherwise the nearer bound
|
|
65
|
-
# @raise [ArgumentError] if +min+ or +max+ is not a Money, Numeric or nil; if
|
|
66
|
-
# a Money operand has a different currency; if +min+ > +max+;
|
|
67
|
-
# if min is a Range, and max is not nil
|
|
68
|
-
#
|
|
69
|
-
# @example In range
|
|
70
|
-
# Mint.money(5, 'USD').clamp(0, 10) #=> [USD 5.00] (returns self)
|
|
71
|
-
#
|
|
72
|
-
# @example Out of range, with Numeric bounds
|
|
73
|
-
# Mint.money(50, 'USD').clamp(0, 10) #=> [USD 10.00]
|
|
74
|
-
#
|
|
75
|
-
# @example Out of range, with Money bounds
|
|
76
|
-
# loss = Mint.money(-5, 'USD')
|
|
77
|
-
# floor = Mint.money(0, 'USD')
|
|
78
|
-
# ceil = Mint.money(10, 'USD')
|
|
79
|
-
# loss.clamp(floor, ceil) #=> [USD 0.00]
|
|
80
|
-
#
|
|
81
|
-
# @example Subunit-0 currency (JPY)
|
|
82
|
-
# Mint.money(500, 'JPY').clamp(0, 100) #=> [JPY 100]
|
|
83
|
-
def clamp(min_or_range, max = nil)
|
|
84
|
-
if min_or_range.is_a?(Range)
|
|
85
|
-
raise(ArgumentError, "Either amount range alone or two amounts accepted: #{max}") if max
|
|
86
|
-
|
|
87
|
-
min, max = min_or_range.minmax
|
|
88
|
-
else
|
|
89
|
-
min = min_or_range
|
|
90
|
-
end
|
|
91
|
-
mint(amount.clamp(normalize_boundary(min), normalize_boundary(max)))
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
private
|
|
95
|
-
|
|
96
|
-
def normalize_boundary(boundary)
|
|
97
|
-
case boundary
|
|
98
|
-
in NilClass | Numeric then boundary
|
|
99
|
-
in Money if same_currency?(boundary) then boundary.amount
|
|
100
|
-
in Money then raise ArgumentError, "oundary currency must be: #{currency_code}"
|
|
101
|
-
else raise ArgumentError, "Boundary must be Numeric or Money #{boundary}"
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
46
|
end
|
|
105
47
|
end
|
data/lib/minting/version.rb
CHANGED
data/minting.gemspec
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
lib = File.expand_path('lib', __dir__)
|
|
2
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
5
|
require 'minting/version'
|
|
@@ -15,18 +17,19 @@ Gem::Specification.new do |s|
|
|
|
15
17
|
# Prevent pushing this gem to RubyGems.org.
|
|
16
18
|
# To allow pushes either set the 'allowed_push_host' to allow pushing to
|
|
17
19
|
# a single host or delete this section to allow pushing to any host.
|
|
18
|
-
raise 'RubyGems 3.
|
|
20
|
+
raise 'RubyGems 3.3 or newer is required' unless s.respond_to?(:metadata)
|
|
19
21
|
|
|
20
22
|
s.metadata = {
|
|
21
23
|
'bug_tracker_uri' => "#{s.homepage}/issues",
|
|
22
24
|
'changelog_uri' => "#{s.homepage}/blob/master/CHANGELOG.md",
|
|
25
|
+
'documentation_uri' => 'https://www.rubydoc.info/gems/minting',
|
|
23
26
|
'homepage_uri' => s.homepage,
|
|
24
27
|
'source_code_uri' => s.homepage,
|
|
25
28
|
'allowed_push_host' => 'https://rubygems.org',
|
|
26
29
|
'rubygems_mfa_required' => 'true'
|
|
27
30
|
}
|
|
28
31
|
|
|
29
|
-
s.required_ruby_version = '>= 3.
|
|
32
|
+
s.required_ruby_version = '>= 3.3.0'
|
|
30
33
|
s.add_dependency 'bigdecimal', '>= 4.0'
|
|
31
34
|
|
|
32
35
|
s.files = Dir.glob('{bin,doc,lib}/**/*')
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: minting
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.7.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gilson Ferraz
|
|
@@ -32,31 +32,61 @@ files:
|
|
|
32
32
|
- LICENSE
|
|
33
33
|
- README.md
|
|
34
34
|
- Rakefile
|
|
35
|
+
- bin/bench_check
|
|
35
36
|
- bin/check-currencies
|
|
36
37
|
- bin/console
|
|
37
38
|
- bin/setup
|
|
39
|
+
- doc/Mint.html
|
|
40
|
+
- doc/Mint/Currency.html
|
|
41
|
+
- doc/Mint/CurrencyRegistry.html
|
|
42
|
+
- doc/Mint/Money.html
|
|
43
|
+
- doc/Mint/RangeStepPatch.html
|
|
44
|
+
- doc/Mint/UnknownCurrency.html
|
|
45
|
+
- doc/Minting.html
|
|
46
|
+
- doc/_index.html
|
|
38
47
|
- doc/agents/AGENTS.md
|
|
39
48
|
- doc/agents/copilot-instructions.md
|
|
40
49
|
- doc/agents/gemini_gem_evaluation.md
|
|
41
50
|
- doc/agents/recommendations.md
|
|
42
51
|
- doc/agents/rubocop-issues.md
|
|
52
|
+
- doc/class_list.html
|
|
53
|
+
- doc/css/common.css
|
|
54
|
+
- doc/css/full_list.css
|
|
55
|
+
- doc/css/style.css
|
|
56
|
+
- doc/file.README.html
|
|
57
|
+
- doc/file_list.html
|
|
58
|
+
- doc/frames.html
|
|
59
|
+
- doc/index.html
|
|
60
|
+
- doc/js/app.js
|
|
61
|
+
- doc/js/full_list.js
|
|
62
|
+
- doc/js/jquery.js
|
|
63
|
+
- doc/method_list.html
|
|
64
|
+
- doc/top-level-namespace.html
|
|
43
65
|
- lib/minting.rb
|
|
66
|
+
- lib/minting/currency/currency.rb
|
|
67
|
+
- lib/minting/currency/currency_registry.rb
|
|
68
|
+
- lib/minting/currency/world_currencies.rb
|
|
44
69
|
- lib/minting/data/world-currencies.yaml
|
|
45
70
|
- lib/minting/mint.rb
|
|
46
71
|
- lib/minting/mint/aliases.rb
|
|
47
|
-
- lib/minting/mint/
|
|
48
|
-
- lib/minting/mint/
|
|
49
|
-
- lib/minting/mint/
|
|
50
|
-
- lib/minting/mint/dsl.rb
|
|
72
|
+
- lib/minting/mint/dsl/numeric.rb
|
|
73
|
+
- lib/minting/mint/dsl/range.rb
|
|
74
|
+
- lib/minting/mint/dsl/string.rb
|
|
75
|
+
- lib/minting/mint/dsl/top_level.rb
|
|
51
76
|
- lib/minting/mint/mint.rb
|
|
52
|
-
- lib/minting/mint/parser.rb
|
|
53
|
-
- lib/minting/
|
|
54
|
-
- lib/minting/money/
|
|
77
|
+
- lib/minting/mint/parser/parser.rb
|
|
78
|
+
- lib/minting/mint/parser/separators.rb
|
|
79
|
+
- lib/minting/money/allocation/allocation.rb
|
|
80
|
+
- lib/minting/money/allocation/split.rb
|
|
81
|
+
- lib/minting/money/arithmetics/methods.rb
|
|
82
|
+
- lib/minting/money/arithmetics/operators.rb
|
|
83
|
+
- lib/minting/money/clamp.rb
|
|
55
84
|
- lib/minting/money/coercion.rb
|
|
56
85
|
- lib/minting/money/comparable.rb
|
|
57
86
|
- lib/minting/money/constructors.rb
|
|
58
87
|
- lib/minting/money/conversion.rb
|
|
59
|
-
- lib/minting/money/formatting.rb
|
|
88
|
+
- lib/minting/money/format/formatting.rb
|
|
89
|
+
- lib/minting/money/format/to_s.rb
|
|
60
90
|
- lib/minting/money/money.rb
|
|
61
91
|
- lib/minting/version.rb
|
|
62
92
|
- minting.gemspec
|
|
@@ -66,6 +96,7 @@ licenses:
|
|
|
66
96
|
metadata:
|
|
67
97
|
bug_tracker_uri: https://github.com/gferraz/minting/issues
|
|
68
98
|
changelog_uri: https://github.com/gferraz/minting/blob/master/CHANGELOG.md
|
|
99
|
+
documentation_uri: https://www.rubydoc.info/gems/minting
|
|
69
100
|
homepage_uri: https://github.com/gferraz/minting
|
|
70
101
|
source_code_uri: https://github.com/gferraz/minting
|
|
71
102
|
allowed_push_host: https://rubygems.org
|
|
@@ -77,14 +108,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
77
108
|
requirements:
|
|
78
109
|
- - ">="
|
|
79
110
|
- !ruby/object:Gem::Version
|
|
80
|
-
version: 3.
|
|
111
|
+
version: 3.3.0
|
|
81
112
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
82
113
|
requirements:
|
|
83
114
|
- - ">="
|
|
84
115
|
- !ruby/object:Gem::Version
|
|
85
116
|
version: '0'
|
|
86
117
|
requirements: []
|
|
87
|
-
rubygems_version: 4.0.
|
|
118
|
+
rubygems_version: 4.0.10
|
|
88
119
|
specification_version: 4
|
|
89
120
|
summary: Library to manipulate currency values
|
|
90
121
|
test_files: []
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Mint
|
|
4
|
-
# Allocation and splitting
|
|
5
|
-
class Money
|
|
6
|
-
# Proportionally allocates the monetary amount among a list of ratios.
|
|
7
|
-
# Disperses any subunit rounding amounts across the initial slots
|
|
8
|
-
# @param proportions [Array<Numeric>] a list of numeric proportions/ratios to allocate by
|
|
9
|
-
# @return [Array<Money>] the list of newly allocated Money objects
|
|
10
|
-
# @raise [ArgumentError] if the proportions list is empty or sums to zero
|
|
11
|
-
#
|
|
12
|
-
# @example Proportional allocation
|
|
13
|
-
# money = Mint.money(10.00, 'USD')
|
|
14
|
-
# money.allocate([1, 2, 3]) #=> [[USD 1.67], [USD 3.33], [USD 5.00]]
|
|
15
|
-
def allocate(proportions)
|
|
16
|
-
whole = proportions.sum.to_r
|
|
17
|
-
raise ArgumentError, 'Need at least 1 proportion element' if proportions.empty?
|
|
18
|
-
raise ArgumentError, 'Proportions total must not be zero' if whole.zero?
|
|
19
|
-
|
|
20
|
-
subunit = currency.subunit
|
|
21
|
-
amounts = proportions.map { |rate| Rational(amount * rate, whole).round(subunit) }
|
|
22
|
-
allocate_left_over!(amounts: amounts, left_over: amount - amounts.sum)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
# Splits the monetary amount into a given quantity of equal parts.
|
|
26
|
-
# Disperses any fractional subunit rounding differences across the initial slots
|
|
27
|
-
# so that the sum is preserved.
|
|
28
|
-
#
|
|
29
|
-
# @param quantity [Integer] the number of equal parts to divide the money into (must be > 0)
|
|
30
|
-
# @return [Array<Money>] the list of newly split Money objects
|
|
31
|
-
# @raise [ArgumentError] if quantity is not a positive integer
|
|
32
|
-
#
|
|
33
|
-
# @example Even split
|
|
34
|
-
# money = Mint.money(10.00, 'USD')
|
|
35
|
-
# money.split(3) #=> [[USD 3.34], [USD 3.33], [USD 3.33]]
|
|
36
|
-
def split(quantity)
|
|
37
|
-
unless quantity.positive? && quantity.integer?
|
|
38
|
-
raise ArgumentError,
|
|
39
|
-
'quantity must be an integer > 0'
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
fraction = (amount / quantity).round(currency.subunit)
|
|
43
|
-
allocate_left_over!(amounts: Array.new(quantity, fraction),
|
|
44
|
-
left_over: amount - (fraction * quantity))
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
private
|
|
48
|
-
|
|
49
|
-
def allocate_left_over!(amounts:, left_over:)
|
|
50
|
-
if left_over.nonzero?
|
|
51
|
-
minimum = currency.minimum_amount
|
|
52
|
-
minimum = -minimum if left_over.negative?
|
|
53
|
-
last_slot = (left_over / minimum).to_i - 1
|
|
54
|
-
(0..last_slot).each { |slot| amounts[slot] += minimum }
|
|
55
|
-
end
|
|
56
|
-
amounts.map { |amount| Money.new(amount, currency) }
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|