Minting
Fast, precise, and developer-friendly money handling for Ruby.
Why Minting?
Tired of floating-point errors in financial calculations? Minting uses Rational numbers for perfect precision.
Need performance? Minting is 2x faster than alternatives.
Want a clean API? Minting provides an intuitive interface with helpful error messages.
Looking for a proven alternative? Check out the established Money gem with thousands of stars on GitHub.
Rails? Use the minting-rails companion gem
Quick start
require 'minting'
price = Mint.money(19.99, 'USD') #=> [USD 19.99]
tax = price * 0.08 #=> [USD 1.60]
total = price + tax #=> [USD 21.59]
total.to_s #=> "$21.59"
total.currency_code #=> "USD"
Features
- Arithmetic:
+ - * /, unary minus,abs - Comparisons:
==,<=>,zero?,nonzero?,positive?,negative? - Formatting:
to_swith custom formats, thousand delimiters and decimal separators - Serialization:
to_json,to_i,to_f,to_r,to_d - Allocation utilities:
split(quantity),allocate([ratios]) - Numeric Refinements for ergonomics:
10.dollars,3.euros,4.to_money('USD') - Currency registry with 117+ currencies and custom registration
Usage
require 'minting'
# Create money
ten = Mint.money(10, 'USD') #=> [USD 10.00]
# Create money using Numeric refinements
using Mint
1.dollar == Mint.money(1, 'USD') #=> true
ten = 10.dollars #=> [USD 10.00]
4.to_money('USD') #=> [USD 4.00]
# Comparisons
ten == 10.dollars #=> true
ten == Mint.money(10, 'EUR') #=> false
ten > Mint.money(9.99, 'USD') #=> true
# Zero equality semantics
# Any zero amount is treated as equal, regardless of currency
Mint.money(0, 'USD') == Mint.money(0, 'EUR') #=> true
Mint.money(0, 'USD') == 0 #=> true
Mint.money(0, 'USD') == 0.0 #=> true
Mint.money(0, 'USD') == 0r #=> true
# Non-zero numerics are not equal to Money objects
Mint.money(10, 'USD') == 10 #=> false
# Format (uses Kernel.format internally)
price = Mint.money(9.99, 'USD')
price.to_s #=> "$9.99",
price.to_s(format: '%<amount>d') #=> "9",
price.to_s(format: '%<symbol>s%<amount>f') #=> "$9.99",
price.to_s(format: '%<symbol>s%<amount>+f') #=> "$+9.99",
(-price).to_s(format: '%<amount>f') #=> "-9.99",
# Format with padding
price_in_euros = Mint.money(12.34, 'EUR')
price.to_s(format: '--%<amount>7d') #=> "-- 9"
price.to_s(format: ' %<amount>10f %<currency>s') #=> " 9.99 USD"
(-price).to_s(format: ' %<amount>10f') #=> " -9.99"
price_in_euros.to_s(format: '%<symbol>2s%<amount>+10f') #=> " € +12.34"
# Json serialization
price.to_json # => "{ "currency": "USD", "amount": "9.99" }"
# Proportional allocation and split
ten.split(3) #=> [[USD 3.34], [USD 3.33], [USD 3.33]]
ten.allocate([1, 2, 3]) #=> [[USD 1.67], [USD 3.33], [USD 5.00]]
# Ranges and enumeration are supported
1.dollar..10.dollars #=> [USD 1.00]..[USD 10.00]
(1.dollar..3.dollars).step(1.dollar).to_a #=> [[USD 1.00], [USD 2.00], [USD 3.00]]
API notes
Module names — Require the minting gem; the public API lives under Mint (the gem module is Minting::VERSION).
Exact amounts — Amounts are stored as Rational and rounded to the currency subunit. Prefer rationals or decimal strings for exact literals (Mint.money(1999/100r, 'USD'), '19.99'.to_r) instead of binary floats when precision matters.
Refinements — 10.dollars and similar helpers require using Mint in the current scope (see Usage above).
Division — money / 5 returns new Money; money / other_money returns a numeric ratio, not money.
Zero equality — Mint.money(0, 'USD') == Mint.money(0, 'EUR') is intentionally true. Non-zero amounts must match currency and value.
Custom currencies — Mint.register_currency returns the existing entry if the code is already registered; use register_currency! to detect duplicates.
Built-in currencies — ISO-style codes ship in lib/minting/data/currencies.yaml and load when the registry is first accessed.
Installation
Option 1: Via bundler command
bundle add minting
bundle install
Option 2: add the line below to your application's Gemfile:
gem 'minting'
or, if you want latest development version from Github
gem 'minting', git: 'https://github.com/gferraz/minting.git'
and execute:
bundle install
Option 3: Install it yourself with:
gem install minting
Parsing strings
Mint::Money.parse('$19.99') #=> [USD 19.99]
Mint::Money.parse('19,99 €') #=> [EUR 19.99]
Mint::Money.parse('1.234,56', 'EUR') #=> [EUR 1234.56]
Mint::Money.parse('USD 1,234.56') #=> [USD 1234.56]
- Pass a currency code when the string has no symbol or code.
- 1,234 means 1.234, not 1234, because one comma is treated as decimal.
- 1,234.00 is unambiguous thousands-plus-decimal.
- accounting negatives like ($1.23) are unsupported.
- ambiguous symbols like $ resolve by priority, currently USD.
Roadmap
- Improve formatting features
- Localization (I18n-aware formatting)
- Basic exchange-rate conversions
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/gferraz/minting.
- Fork and create a feature branch
- Run the test suite:
rake - Run performance suites as needed:
BENCH=true rake bench:performance - Open a PR with a clear description and benchmarks if relevant
Performance
This gem includes a performance suite under test/performance:
- Core operations (creation, arithmetic, comparisons)
- Algorithm benchmarks (split, allocate)
- Memory and GC pressure tests
- Competitive benchmarks vs
moneygem
On a typical machine, reference numbers are:
- Money creation: ~1.6M ops/sec
- Addition: ~1.7M ops/sec
Run locally:
# All performance suites
BENCH=true rake bench:performance
# Competitive vs money gem
BENCH=true rake bench:competitive
# Regression checks
rake bench:regression
License
MIT