minting 1.7.0 → 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 -118
- data/Rakefile +13 -1
- data/bin/bench_check +46 -0
- data/doc/Mint/Currency.html +178 -32
- data/doc/Mint/CurrencyRegistry.html +7 -7
- data/doc/Mint/Money.html +128 -125
- data/doc/Mint/RangeStepPatch.html +277 -0
- data/doc/Mint/UnknownCurrency.html +2 -2
- data/doc/Mint.html +47 -22
- data/doc/Minting.html +3 -3
- data/doc/_index.html +17 -2
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +86 -89
- data/doc/index.html +86 -89
- data/doc/method_list.html +29 -21
- data/doc/top-level-namespace.html +13 -5
- data/lib/minting/{mint/currency → currency}/currency.rb +8 -0
- data/lib/minting/{mint/currency → currency}/world_currencies.rb +1 -1
- data/lib/minting/mint/aliases.rb +3 -0
- data/lib/minting/mint/dsl/{refinements.rb → numeric.rb} +6 -5
- data/lib/minting/mint/dsl/range.rb +31 -18
- data/lib/minting/mint/dsl/string.rb +12 -0
- data/lib/minting/mint/dsl/top_level.rb +3 -0
- data/lib/minting/mint/mint.rb +16 -2
- data/lib/minting/mint/parser/parser.rb +66 -0
- data/lib/minting/mint/parser/separators.rb +39 -0
- data/lib/minting/mint.rb +17 -8
- data/lib/minting/money/allocation/allocation.rb +25 -0
- data/lib/minting/money/{allocation.rb → allocation/split.rb} +1 -19
- data/lib/minting/money/arithmetics/methods.rb +27 -0
- data/lib/minting/money/{arithmetics.rb → arithmetics/operators.rb} +0 -21
- data/lib/minting/money/clamp.rb +66 -0
- data/lib/minting/money/coercion.rb +10 -0
- 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} +0 -32
- data/lib/minting/money/money.rb +0 -58
- data/lib/minting/version.rb +1 -1
- metadata +19 -14
- data/lib/minting/mint/parser.rb +0 -85
- /data/lib/minting/{mint/currency → currency}/currency_registry.rb +0 -0
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
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: minting
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.7.
|
|
4
|
+
version: 1.7.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gilson Ferraz
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: bigdecimal
|
|
@@ -33,6 +32,7 @@ files:
|
|
|
33
32
|
- LICENSE
|
|
34
33
|
- README.md
|
|
35
34
|
- Rakefile
|
|
35
|
+
- bin/bench_check
|
|
36
36
|
- bin/check-currencies
|
|
37
37
|
- bin/console
|
|
38
38
|
- bin/setup
|
|
@@ -40,6 +40,7 @@ files:
|
|
|
40
40
|
- doc/Mint/Currency.html
|
|
41
41
|
- doc/Mint/CurrencyRegistry.html
|
|
42
42
|
- doc/Mint/Money.html
|
|
43
|
+
- doc/Mint/RangeStepPatch.html
|
|
43
44
|
- doc/Mint/UnknownCurrency.html
|
|
44
45
|
- doc/Minting.html
|
|
45
46
|
- doc/_index.html
|
|
@@ -62,24 +63,30 @@ files:
|
|
|
62
63
|
- doc/method_list.html
|
|
63
64
|
- doc/top-level-namespace.html
|
|
64
65
|
- lib/minting.rb
|
|
66
|
+
- lib/minting/currency/currency.rb
|
|
67
|
+
- lib/minting/currency/currency_registry.rb
|
|
68
|
+
- lib/minting/currency/world_currencies.rb
|
|
65
69
|
- lib/minting/data/world-currencies.yaml
|
|
66
70
|
- lib/minting/mint.rb
|
|
67
71
|
- lib/minting/mint/aliases.rb
|
|
68
|
-
- lib/minting/mint/
|
|
69
|
-
- lib/minting/mint/currency/currency_registry.rb
|
|
70
|
-
- lib/minting/mint/currency/world_currencies.rb
|
|
72
|
+
- lib/minting/mint/dsl/numeric.rb
|
|
71
73
|
- lib/minting/mint/dsl/range.rb
|
|
72
|
-
- lib/minting/mint/dsl/
|
|
74
|
+
- lib/minting/mint/dsl/string.rb
|
|
73
75
|
- lib/minting/mint/dsl/top_level.rb
|
|
74
76
|
- lib/minting/mint/mint.rb
|
|
75
|
-
- lib/minting/mint/parser.rb
|
|
76
|
-
- lib/minting/
|
|
77
|
-
- 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
|
|
78
84
|
- lib/minting/money/coercion.rb
|
|
79
85
|
- lib/minting/money/comparable.rb
|
|
80
86
|
- lib/minting/money/constructors.rb
|
|
81
87
|
- lib/minting/money/conversion.rb
|
|
82
|
-
- lib/minting/money/formatting.rb
|
|
88
|
+
- lib/minting/money/format/formatting.rb
|
|
89
|
+
- lib/minting/money/format/to_s.rb
|
|
83
90
|
- lib/minting/money/money.rb
|
|
84
91
|
- lib/minting/version.rb
|
|
85
92
|
- minting.gemspec
|
|
@@ -94,7 +101,6 @@ metadata:
|
|
|
94
101
|
source_code_uri: https://github.com/gferraz/minting
|
|
95
102
|
allowed_push_host: https://rubygems.org
|
|
96
103
|
rubygems_mfa_required: 'true'
|
|
97
|
-
post_install_message:
|
|
98
104
|
rdoc_options: []
|
|
99
105
|
require_paths:
|
|
100
106
|
- lib
|
|
@@ -109,8 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
109
115
|
- !ruby/object:Gem::Version
|
|
110
116
|
version: '0'
|
|
111
117
|
requirements: []
|
|
112
|
-
rubygems_version:
|
|
113
|
-
signing_key:
|
|
118
|
+
rubygems_version: 4.0.10
|
|
114
119
|
specification_version: 4
|
|
115
120
|
summary: Library to manipulate currency values
|
|
116
121
|
test_files: []
|
data/lib/minting/mint/parser.rb
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Mint Money parsing
|
|
4
|
-
module Mint
|
|
5
|
-
extend self
|
|
6
|
-
|
|
7
|
-
# Parses a human-readable money string into a {Money} object.
|
|
8
|
-
#
|
|
9
|
-
# @param input [String] Amount input, optionally including a currency symbol or code
|
|
10
|
-
# @param currency [String, Symbol, Currency, nil] ISO code when not present in +input+
|
|
11
|
-
# @return [Money]
|
|
12
|
-
# @raise [ArgumentError] when +input+ is invalid or currency cannot be determined
|
|
13
|
-
#
|
|
14
|
-
# @example With explicit currency
|
|
15
|
-
# Money.parse('19.99', 'USD') #=> [USD 19.99]
|
|
16
|
-
# Money.parse('1.234,56', 'EUR') #=> [EUR 1234.56]
|
|
17
|
-
#
|
|
18
|
-
# @example With symbol or code in the string
|
|
19
|
-
# Money.parse('$19.99') #=> [USD 19.99]
|
|
20
|
-
# Money.parse('19,99 €') #=> [EUR 19.99]
|
|
21
|
-
# Money.parse('USD 1,234.56') #=> [USD 1234.56]
|
|
22
|
-
def parse(input, currency = nil)
|
|
23
|
-
raise ArgumentError, 'input must be a String' unless input.is_a?(String)
|
|
24
|
-
|
|
25
|
-
input = input.strip
|
|
26
|
-
raise ArgumentError, 'input cannot be empty' if input.empty?
|
|
27
|
-
|
|
28
|
-
currency = Mint.currency(currency) || parse_currency(input)
|
|
29
|
-
raise ArgumentError, "Currency [#{currency}] not registered" unless currency
|
|
30
|
-
|
|
31
|
-
amount = currency.normalize_amount(parse_amount(input))
|
|
32
|
-
Mint::Money.new(amount, currency)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
private
|
|
36
|
-
|
|
37
|
-
# Extracts a numeric value from input that should only contain an amount.
|
|
38
|
-
def parse_amount(input)
|
|
39
|
-
# Remove any charater that is not a digit, comma or period
|
|
40
|
-
numeric = input.scan(/[\d.,-]/).join
|
|
41
|
-
numeric = normalize_separators(numeric)
|
|
42
|
-
Rational(numeric)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def classify_separators(numeric)
|
|
46
|
-
case [numeric.count(','), numeric.count('.')]
|
|
47
|
-
in [0, 0] | [0, 1] then :decimal_period # e.g. "1500" or "34.21".
|
|
48
|
-
in [1, 0] then :decimal_comma # Only one comma: decimal (e.g. 19,99 or 1,234).
|
|
49
|
-
in [c, p] if c > 1 && p > 1 then :ambiguous # Both separators appear multiple times
|
|
50
|
-
in [c, p] if c > 0 && p > 0 then :mixed # Commas and dots: the rightmost one is the decimal separator.
|
|
51
|
-
else :thousands_only # Multiple of the same separator only (e.g. 1,234,567)
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Converts locale-specific decimal/thousand separators into a plain decimal string.
|
|
56
|
-
def normalize_separators(numeric)
|
|
57
|
-
case classify_separators(numeric)
|
|
58
|
-
when :decimal_period then numeric # Nothing to normalize (e.g. "1500" or "34.21").
|
|
59
|
-
when :decimal_comma then numeric.tr(',', '.') # Only one comma: decimal (e.g. 19,99 or 1,234).
|
|
60
|
-
when :thousands_only then numeric.delete(',.')
|
|
61
|
-
when :ambiguous then raise ArgumentError, "could not distinguish decimal and thousand separators in '#{numeric}'"
|
|
62
|
-
when :mixed # Commas and dots: the rightmost one is the decimal separator.
|
|
63
|
-
if numeric.rindex(',') > numeric.rindex('.')
|
|
64
|
-
numeric.delete('.').tr(',', '.')
|
|
65
|
-
else
|
|
66
|
-
numeric.delete(',')
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def parse_currency(input)
|
|
72
|
-
case input
|
|
73
|
-
when String
|
|
74
|
-
# Prefer an explicit ISO 4217 code (e.g. "USD 1,234.56") over symbol matching.
|
|
75
|
-
currency = Mint.currency(input[/\b([A-Z_]+)\b/, 1])
|
|
76
|
-
return currency if currency
|
|
77
|
-
|
|
78
|
-
# Fall back to registered symbols, longest first (HK$ before $).
|
|
79
|
-
CurrencyRegistry.currency_symbols.each do |symbol, currency|
|
|
80
|
-
return currency if input.include?(symbol)
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
raise ArgumentError, 'Currency could not be detected'
|
|
84
|
-
end
|
|
85
|
-
end
|
|
File without changes
|