Minting

Fast, precise, and developer-friendly money handling for Ruby.

Gem Version

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_s with 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.

Refinements10.dollars and similar helpers require using Mint in the current scope (see Usage above).

Divisionmoney / 5 returns new Money; money / other_money returns a numeric ratio, not money.

Zero equalityMint.money(0, 'USD') == Mint.money(0, 'EUR') is intentionally true. Non-zero amounts must match currency and value.

Custom currenciesMint.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.

  1. Fork and create a feature branch
  2. Run the test suite: rake
  3. Run performance suites as needed: BENCH=true rake bench:performance
  4. 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 money gem

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