minting 1.0.1 → 1.1.1

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.
@@ -0,0 +1,82 @@
1
+ module Mint
2
+ # nodoc
3
+ class Money
4
+ # Parses a human-readable money string into a {Money} object.
5
+ #
6
+ # @param input [String] Amount input, optionally including a currency symbol or code
7
+ # @param currency [String, Symbol, Currency, nil] ISO code when not present in +input+
8
+ # @return [Money]
9
+ # @raise [ArgumentError] when +input+ is invalid or currency cannot be determined
10
+ #
11
+ # @example With explicit currency
12
+ # Money.parse('19.99', 'USD') #=> [USD 19.99]
13
+ # Money.parse('1.234,56', 'EUR') #=> [EUR 1234.56]
14
+ #
15
+ # @example With symbol or code in the string
16
+ # Money.parse('$19.99') #=> [USD 19.99]
17
+ # Money.parse('19,99 €') #=> [EUR 19.99]
18
+ # Money.parse('USD 1,234.56') #=> [USD 1234.56]
19
+ def self.parse(input, currency = nil)
20
+ raise ArgumentError, 'input must be a String' unless input.is_a?(String)
21
+
22
+ input = input.strip
23
+ raise ArgumentError, 'input cannot be empty' if input.empty?
24
+
25
+ currency = currency ? Mint.currency(currency) : parse_currency(input)
26
+ raise ArgumentError, "Currency [#{currency}] not registered" unless currency
27
+
28
+ amount = parse_amount(input)
29
+ new(amount, currency)
30
+ end
31
+
32
+ # Extracts a numeric value from input that should only contain an amount.
33
+ def self.parse_amount(input)
34
+ # Remove any charater that is not a digit, comma or period
35
+ numeric = input.scan(/[\d.\-,]/).join
36
+ numeric = normalize_separators(numeric)
37
+ Rational(numeric)
38
+ end
39
+
40
+ # Converts locale-specific decimal/thousand separators into a plain decimal string.
41
+ def self.normalize_separators(numeric)
42
+ case [numeric.count(','), numeric.count('.')]
43
+ in [0, 0] | [0, 1] # Nothing to normalize (e.g. "1500" or "34.21").
44
+ numeric
45
+ in [1, 0] # Only one comma: decimal (e.g. 19,99 or 1,234).
46
+ numeric.tr(',', '.')
47
+ in [c, p] if c > 1 && p > 1 # Both separators appear multiple times
48
+ raise ArgumentError, "could not distinguish decimal and thousand separators in '#{numeric}'"
49
+ in [c, p] if c > 0 && p > 0 # Commas and dots: the rightmost one is the decimal separator.
50
+ if numeric.rindex(',') > numeric.rindex('.')
51
+ numeric.delete('.').tr(',', '.')
52
+ else
53
+ numeric.delete(',')
54
+ end
55
+ else # Multiple of the same separator only (e.g. 1,234,567) — all are thousands.
56
+ numeric.delete(',.')
57
+ end
58
+ end
59
+
60
+ def self.parse_currency(input)
61
+ # Prefer an explicit ISO 4217 code (e.g. "USD 1,234.56") over symbol matching.
62
+ code = input[/\b([A-Z]{3})\b/, 1]
63
+ if code
64
+ currency = Mint.currency(code)
65
+ return currency if currency
66
+ end
67
+
68
+ # Fall back to registered symbols, longest first (HK$ before $).
69
+ Mint.currency_symbols.each do |symbol, currency|
70
+ next if symbol.empty?
71
+
72
+ return currency if input.include?(symbol)
73
+ end
74
+
75
+ raise ArgumentError,
76
+ 'currency could not be detected; pass a currency code as the second argument'
77
+ end
78
+
79
+ private_class_method :parse_amount, :normalize_separators,
80
+ :parse_currency
81
+ end
82
+ end
data/lib/minting/money.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'minting/money/parse'
1
2
  require 'minting/money/allocation'
2
3
  require 'minting/money/arithmetics'
3
4
  require 'minting/money/coercion'
@@ -1,3 +1,5 @@
1
+ # Root namespace for the Minting library.
1
2
  module Minting
2
- VERSION = '1.0.1'.freeze
3
+ # Current version of the Minting gem.
4
+ VERSION = '1.1.1'.freeze
3
5
  end
data/minting.gemspec CHANGED
@@ -29,7 +29,7 @@ Gem::Specification.new do |s|
29
29
  s.required_ruby_version = '>= 3.2.0'
30
30
 
31
31
  s.files = Dir.glob('{bin,doc,lib}/**/*')
32
- s.files += %w[minting.gemspec Rakefile README.md]
32
+ s.files += %w[minting.gemspec Rakefile README.md LICENSE]
33
33
 
34
34
  s.bindir = 'bin'
35
35
  s.require_paths = ['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.0.1
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gilson Ferraz
@@ -15,11 +15,13 @@ executables: []
15
15
  extensions: []
16
16
  extra_rdoc_files: []
17
17
  files:
18
+ - LICENSE
18
19
  - README.md
19
20
  - Rakefile
20
21
  - bin/console
21
22
  - bin/setup
22
23
  - lib/minting.rb
24
+ - lib/minting/data/currencies.yaml
23
25
  - lib/minting/mint.rb
24
26
  - lib/minting/mint/currency.rb
25
27
  - lib/minting/mint/refinements.rb
@@ -32,6 +34,7 @@ files:
32
34
  - lib/minting/money/conversion.rb
33
35
  - lib/minting/money/formatting.rb
34
36
  - lib/minting/money/money.rb
37
+ - lib/minting/money/parse.rb
35
38
  - lib/minting/version.rb
36
39
  - minting.gemspec
37
40
  homepage: https://github.com/gferraz/minting
@@ -58,7 +61,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
58
61
  - !ruby/object:Gem::Version
59
62
  version: '0'
60
63
  requirements: []
61
- rubygems_version: 3.7.1
64
+ rubygems_version: 4.0.9
62
65
  specification_version: 4
63
66
  summary: Library to manipulate currency values
64
67
  test_files: []