minting 1.7.3 → 1.8.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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +31 -24
  3. data/Rakefile +15 -4
  4. data/doc/Mint/Currency.html +535 -18
  5. data/doc/Mint/Money.html +659 -185
  6. data/doc/Mint/RangeStepPatch.html +1 -1
  7. data/doc/Mint/Registry.html +19 -2
  8. data/doc/Mint/Rounding.html +495 -0
  9. data/doc/Mint/UnknownCurrency.html +1 -1
  10. data/doc/Mint.html +187 -399
  11. data/doc/Minting.html +2 -2
  12. data/doc/_index.html +8 -1
  13. data/doc/agents/api_review-2026-06-15.md +0 -13
  14. data/doc/agents/copilot-instructions.md +70 -0
  15. data/doc/class_list.html +1 -1
  16. data/doc/file.README.html +19 -9
  17. data/doc/index.html +19 -9
  18. data/doc/method_list.html +130 -42
  19. data/doc/top-level-namespace.html +1 -1
  20. data/lib/minting/currency/currency.rb +41 -2
  21. data/lib/minting/mint/dsl/numeric.rb +4 -4
  22. data/lib/minting/mint/dsl/range.rb +1 -0
  23. data/lib/minting/mint/dsl/string.rb +1 -1
  24. data/lib/minting/mint/mint.rb +10 -37
  25. data/lib/minting/mint/parser/parser.rb +50 -15
  26. data/lib/minting/mint/parser/separators.rb +10 -8
  27. data/lib/minting/mint/registry/zeros.rb +3 -1
  28. data/lib/minting/mint/rounding.rb +51 -0
  29. data/lib/minting/mint.rb +1 -0
  30. data/lib/minting/money/allocation/allocation.rb +1 -2
  31. data/lib/minting/money/allocation/split.rb +1 -1
  32. data/lib/minting/money/arithmetics/methods.rb +2 -2
  33. data/lib/minting/money/arithmetics/operators.rb +6 -6
  34. data/lib/minting/money/clamp.rb +1 -1
  35. data/lib/minting/money/coercion.rb +1 -1
  36. data/lib/minting/money/comparable.rb +6 -0
  37. data/lib/minting/money/constructors.rb +60 -12
  38. data/lib/minting/money/money.rb +0 -6
  39. data/lib/minting/version.rb +1 -1
  40. metadata +4 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ebe31c2ae1b9febafa3a6a4ccea1392cb089242746a933d530121b08f55cd4e
4
- data.tar.gz: 80f1eb17f62b7a7924df8b2fedb79d864bcadd5ea5e8432e5149b14fb0d9af0c
3
+ metadata.gz: baca6fa666461ab6bc9f1e0ebed40d7ae0ac56af88993b5d243d25f1ad9bbad3
4
+ data.tar.gz: e54ad7a337df49a298e0e6236ec98d46a902ddd18b62538d395992609eca533b
5
5
  SHA512:
6
- metadata.gz: 44147d3523485fc36491bb62f24df5f4040fe3ddda673201d5b6fc9a5e005bda94cd3300b4e84682f4378cb9eedb851ad16c247a2dfeb9de264fd24a6b1714ca
7
- data.tar.gz: 5f41672831c8c722e47de8b8e94549bb633c48b677fc8e63eca9f10233062f32a0acd276b31271a4f0ac4417779b03db7f034a9b9afcfbd39c0cbadb16886dbf
6
+ metadata.gz: eff34626e551613b9dc312caf42698951869333aaf62440551e44eb681a8b2407e0a36ed24b02ba6f6ef03afc68dd1c7b6ac86aa85d3fafb45155f3637b70a04
7
+ data.tar.gz: b1d2f0f9228ef185ce8b86d4474a1d53151960d7796619ba53ff19fe0db53a9ad990e3f77f924b59c90cd984d144fb62f2fba56059f9e40dfeb5893f790e84cd
data/README.md CHANGED
@@ -21,29 +21,19 @@ total.to_s #=> "$21.59"
21
21
  total.currency_code #=> "USD"
22
22
  ```
23
23
 
24
- ## Why Minting?
25
-
26
- | | Minting |
27
- |--------------------|-------------------------------------------|
28
- | **Precision** | Rational-based, zero floating-point error |
29
- | **Performance** | **2× faster** (10×+ formatting) |
30
- | **Ruby support** | 3.3+ (including Ruby 4.0) |
31
- | **Rails** | Dedicated companion gem |
32
- | **Code quality** | 100% coverage, 93/100 RubyCritic |
33
-
34
- ### 🎯 Exact precision
24
+ ### Exact precision
35
25
  Amounts are stored as `Rational` and rounded to the currency subunit. No floating-point surprises, ever.
36
26
 
37
- ### Blazing performance
38
- Minting is **2× faster** than the Money gem for everyday operations and **over 10× faster for formatting**. See full benchmarks in the [Performance Guide](test/performance/README.md).
27
+ ### Blazing performance
28
+ Minting is faster than the Money gem for everyday operations and **over 10× faster for formatting**. See full benchmarks in the [Performance Guide](test/performance/README.md).
39
29
 
40
- ### 🧼 Clean, modern API
30
+ ### Clean, modern API
41
31
  Intuitive interface, descriptive error messages, and sensible defaults. Works the way you expect.
42
32
 
43
- ### 🚆 Rails-ready
33
+ ### Rails-ready
44
34
  Use with the [minting-rails](https://github.com/gferraz/minting-rails) companion gem for drop-in ActiveRecord type casting, validators, and form helpers.
45
35
 
46
- ### 🏆 Quality you can trust
36
+ ### Quality code
47
37
  - **100% test coverage** — every line exercised
48
38
  - **93/100 RubyCritic score** — clean, maintainable code
49
39
  - **CI-tested on Ruby 3.3 and 4.0**
@@ -176,12 +166,12 @@ Notes:
176
166
 
177
167
  ```ruby
178
168
  # By ISO code (direct hash lookup, string only)
179
- Mint.currency_for_code('USD') #=> #<Currency code="USD" ...>
169
+ Mint::Currency.for_code('USD') #=> #<Currency code="USD" ...>
180
170
 
181
171
  # By display symbol (highest-priority currency for ambiguous symbols)
182
- Mint.currency_for_symbol('$') #=> #<Currency code="USD" ...>
183
- Mint.currency_for_symbol('R$') #=> #<Currency code="BRL" ...>
184
- Mint.currency_for_symbol('€') #=> #<Currency code="EUR" ...>
172
+ Mint::Currency.for_symbol('$') #=> #<Currency code="USD" ...>
173
+ Mint::Currency.for_symbol('R$') #=> #<Currency code="BRL" ...>
174
+ Mint::Currency.for_symbol('€') #=> #<Currency code="EUR" ...>
185
175
 
186
176
  ```
187
177
 
@@ -189,15 +179,25 @@ Mint.currency_for_symbol('€') #=> #<Currency code="EUR" ...>
189
179
 
190
180
  **Exact amounts** — Amounts are stored as `Rational` and rounded to the currency subunit.
191
181
 
182
+ **Rounding modes** — Wrap operations in `Mint.with_rounding(mode)` to change how amounts are rounded to the subunit:
183
+
184
+ ```ruby
185
+ Mint.with_rounding(:half_down) { Mint.money(1.005, 'USD') } #=> [USD 1.00]
186
+ Mint.with_rounding(:ceil) { Mint.money(1.001, 'USD') } #=> [USD 1.01]
187
+ Mint.with_rounding(:floor) { Mint.parse('1.009', 'USD') } #=> [USD 1.00]
188
+ ```
189
+
190
+ Modes: `:half_up` (default), `:half_down`, `:floor`, `:ceil`, `:truncate`, `:down`. Applies to construction, parsing, `change`, `split`, and `allocate`. Restores the previous mode when the block exits, even on exception.
191
+
192
192
  **Refinements** — `10.dollars` and similar helpers require `using Mint` in the current scope (see Usage above).
193
193
 
194
194
  **Division** — `money / 5` returns new `Money`; `money / other_money` returns a numeric ratio, not money.
195
195
 
196
196
  **Zero equality** — Any zero amount is considered equal across currencies and to numeric zero (`Mint.money(0, 'USD') == Mint.money(0, 'EUR')` is intentionally `true`). Non-zero amounts must match currency and value.
197
197
 
198
- **Zero helper** — `Mint.zero('USD')` returns a frozen zero-Money, useful as a default value for discounts, totals, or counters.
198
+ **Zero helper** — `Currency.zero('USD')` returns a frozen zero-Money, useful as a default value for discounts, totals, or counters.
199
199
 
200
- **Registered currencies** — `Mint.register_currency(code:, subunit:, symbol:, priority:)` adds custom currencies. Only registered codes and symbols are recognized by the parser.
200
+ **Registered currencies** — `Currency.register(code:, subunit:, symbol:, priority:)` adds custom currencies. Only registered codes and symbols are recognized by the parser.
201
201
 
202
202
  **Built-in currencies** — 150+ ISO-4217 world currencies ship in `lib/minting/data/currencies.yaml` and load when the registry is first accessed.
203
203
 
@@ -216,11 +216,18 @@ Or at runtime:
216
216
  Minting.use_top_level_constants!
217
217
  ```
218
218
 
219
+ For Rails applications, you can enable the top-level constants in an initializer:
220
+
221
+ ```ruby
222
+ # config/initializers/minting.rb
223
+ require "minting/dsl"
224
+ ```
225
+
219
226
  After opting in:
220
227
 
221
228
  ```ruby
222
- price = Money.create(10, "USD") # equivalent to Mint::Money.create
223
- tax = Money.money(2.50, "USD")
229
+ price = Money.from(10, "USD") # equivalent to Mint::Money.from
230
+ tax = Money.from(2.50, "USD")
224
231
  cur = Currency.new(code: "EUR", symbol: "€", subunit: 2, priority: 0)
225
232
  ```
226
233
 
data/Rakefile CHANGED
@@ -16,7 +16,7 @@ end
16
16
 
17
17
  Rake::TestTask.new('bench:all') do |t|
18
18
  t.libs = %w[lib test]
19
- t.pattern = 'test/performance/**/*_benchmark.rb'
19
+ t.pattern = 'test/performance/{core,memory,regression,competitive/money}/*_benchmark.rb'
20
20
  end
21
21
 
22
22
  Rake::TestTask.new('bench:core') do |t|
@@ -34,9 +34,20 @@ Rake::TestTask.new('bench:regression') do |t|
34
34
  t.pattern = 'test/performance/regression/*_benchmark.rb'
35
35
  end
36
36
 
37
- Rake::TestTask.new('bench:competitive') do |t|
38
- t.libs = %w[lib test]
39
- t.pattern = 'test/performance/competitive/**/*_benchmark.rb'
37
+ desc 'Run competitive benchmarks (Money gem)'
38
+ task 'bench:competitive' do
39
+ sh 'bundle exec ruby -Ilib -Itest -e "Dir[File.join(__dir__, \"test/performance/competitive/money/**/*_benchmark.rb\")].each { |f| require f }"'
40
+ end
41
+
42
+ desc 'Run competitive benchmarks (Shopify Money)'
43
+ task 'bench:competitive:shopify' do
44
+ sh 'BUNDLE_WITHOUT=money_bench bundle exec ruby -Ilib -Itest -e "Dir[File.join(__dir__, \"test/performance/competitive/shopify/**/*_benchmark.rb\")].each { |f| require f }"'
45
+ end
46
+
47
+ desc 'Run all competitive benchmarks (both Money and Shopify)'
48
+ task 'bench:competitive:all' do
49
+ sh 'bundle exec ruby -Ilib -Itest -e "Dir[File.join(__dir__, \"test/performance/competitive/money/**/*_benchmark.rb\")].each { |f| require f }"'
50
+ sh 'BUNDLE_WITHOUT=money_bench bundle exec ruby -Ilib -Itest -e "Dir[File.join(__dir__, \"test/performance/competitive/shopify/**/*_benchmark.rb\")].each { |f| require f }"'
40
51
  end
41
52
 
42
53
  desc 'Run core benchmarks and update the baseline'