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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +71 -118
  3. data/Rakefile +13 -1
  4. data/bin/bench_check +46 -0
  5. data/doc/Mint/Currency.html +178 -32
  6. data/doc/Mint/CurrencyRegistry.html +7 -7
  7. data/doc/Mint/Money.html +128 -125
  8. data/doc/Mint/RangeStepPatch.html +277 -0
  9. data/doc/Mint/UnknownCurrency.html +2 -2
  10. data/doc/Mint.html +47 -22
  11. data/doc/Minting.html +3 -3
  12. data/doc/_index.html +17 -2
  13. data/doc/class_list.html +1 -1
  14. data/doc/file.README.html +86 -89
  15. data/doc/index.html +86 -89
  16. data/doc/method_list.html +29 -21
  17. data/doc/top-level-namespace.html +13 -5
  18. data/lib/minting/{mint/currency → currency}/currency.rb +8 -0
  19. data/lib/minting/{mint/currency → currency}/world_currencies.rb +1 -1
  20. data/lib/minting/mint/aliases.rb +3 -0
  21. data/lib/minting/mint/dsl/{refinements.rb → numeric.rb} +6 -5
  22. data/lib/minting/mint/dsl/range.rb +31 -18
  23. data/lib/minting/mint/dsl/string.rb +12 -0
  24. data/lib/minting/mint/dsl/top_level.rb +3 -0
  25. data/lib/minting/mint/mint.rb +16 -2
  26. data/lib/minting/mint/parser/parser.rb +66 -0
  27. data/lib/minting/mint/parser/separators.rb +39 -0
  28. data/lib/minting/mint.rb +17 -8
  29. data/lib/minting/money/allocation/allocation.rb +25 -0
  30. data/lib/minting/money/{allocation.rb → allocation/split.rb} +1 -19
  31. data/lib/minting/money/arithmetics/methods.rb +27 -0
  32. data/lib/minting/money/{arithmetics.rb → arithmetics/operators.rb} +0 -21
  33. data/lib/minting/money/clamp.rb +66 -0
  34. data/lib/minting/money/coercion.rb +10 -0
  35. data/lib/minting/money/comparable.rb +6 -0
  36. data/lib/minting/money/constructors.rb +13 -3
  37. data/lib/minting/money/format/formatting.rb +44 -0
  38. data/lib/minting/money/{formatting.rb → format/to_s.rb} +0 -32
  39. data/lib/minting/money/money.rb +0 -58
  40. data/lib/minting/version.rb +1 -1
  41. metadata +19 -14
  42. data/lib/minting/mint/parser.rb +0 -85
  43. /data/lib/minting/{mint/currency → currency}/currency_registry.rb +0 -0
@@ -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
@@ -3,5 +3,5 @@
3
3
  # Root namespace for the Minting library.
4
4
  module Minting
5
5
  # Current version of the Minting gem.
6
- VERSION = '1.7.0'
6
+ VERSION = '1.7.2'
7
7
  end
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.0
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: 2026-06-12 00:00:00.000000000 Z
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/currency/currency.rb
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/refinements.rb
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/money/allocation.rb
77
- - lib/minting/money/arithmetics.rb
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: 3.5.22
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: []
@@ -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