Library / SDK
RubyMoney/money avatar
RubyMoney/money

RubyMoney/money: integer cents, ISO 4217 currencies and exchange in Ruby

A Ruby Library for dealing with money and currency conversion.

2,882 stars645 forksRubyMIT

At a glance

What is it?
A Ruby gem that models monetary amounts as integer subunits and currencies as Money::Currency objects, with an exchange API you configure yourself. The README documents arithmetic, formatting and registration; it does not document how exchange rates are fetched.
Who is it for?
Adopt RubyMoney/money if you need arithmetic on monetary amounts in Ruby and want integer subunits rather than floats, and if you are willing to supply exchange rates yourself rather than have the gem fetch them. Do not adopt it as a rate feed or as a replacement for your accounting ledger; the README shows exchange_to relying on a setup step you write.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 8 days ago.
What is it written in?
Mainly Ruby, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What RubyMoney/money does that a float does not

The README states the library represents monetary values as integers, in cents, and that this avoids floating point rounding errors. That is the whole reason the gem exists. A Ruby Float cannot represent 10.00 exactly, so summing prices in floats drifts. RubyMoney/money stores 10.00 USD as 1000 cents and exposes it through a Money object that also carries the currency. The README shows Money.from_cents(1000, "USD") returning .cents as 1000 and .currency as Currency.new("USD").

The audience is Ruby and Rails developers who handle prices, invoices, subscriptions or payouts and need equality and arithmetic to behave. The README's comparison examples are explicit that a Money in USD never equals a Money in EUR even when the cents match, so a currency mix-up surfaces as false rather than as a silently wrong number. That is a design decision worth having: cross-currency equality is a bug, not a conversion.

The library also carries currency metadata. Money::Currency holds the ISO 4217 code, the numeric code, the name, the symbol, the subunit name, the ratio between unit and subunit, the decimal mark and the thousands separator. Formatting and parsing read from that table, which is why Money.from_cents(100, "GBP").format returns "£1.00" without any format string from you.

Subunits, from_amount and the currencies that break the pattern

Most currencies have 100 subunits, but the README's own examples show that assumption failing. Money.from_amount(5, "USD") equals 500 cents. Money.from_amount(5, "JPY") equals 5 cents, because the yen has no fractional unit in this model. Money.from_amount(5, "TND") equals 5000 cents, because the Tunisian dinar is divided into 1000 millimes. If you hardcode a multiply-by-100 anywhere in your code, you will be wrong for at least two of those three.

The mechanism is the subunit_to_unit attribute on Money::Currency. from_amount divides or multiplies according to that per-currency value, and the currency table supplies it. This is the part of the gem that repays reading before you write your own helpers. The README lists subunit_to_unit among the pre-defined attributes and shows it as 100 in the registration example.

Currencies are objects, not strings, but the API accepts either. The README shows Money.from_cents(1000, "USD") == Money.from_cents(1000, Money::Currency.new("USD")) evaluating to true, and Money.from_cents(1000, "EUR").currency == Money::Currency.new("EUR") also true. That flexibility means you can pass a symbol, a string or a Currency instance and get the same object semantics, which keeps call sites readable.

Installing the gem and doing a first conversion

The README gives one command for a stable release. Run it and the money gem is available to require.

bash
gem install money

The README also documents a development install from the Git repository, which clones the source, changes into the directory and runs bin/rake install:

bash
git clone git://github.com/RubyMoney/money.git
cd money
bin/rake install

For a first real use, the README's usage block starts by requiring the library and choosing a locale backend. Note that the README warns your app must use UTF-8, because several currency attributes are non-ASCII.

ruby
require 'money'

I18n.config.available_locales = :en
Money.locale_backend = :i18n

money = Money.from_cents(1000, "USD")
money.cents     #=> 1000
money.currency  #=> Currency.new("USD")

Arithmetic and formatting follow from that object. The README's examples take a Money in USD and a divisor, and format a small amount in three currencies:

ruby
a = Money.from_cents(1000, "USD")
b = Money.from_cents(500, "USD")
(a + b).cents                 #=> 1500
(a / 5).cents                 #=> 200
Money.from_cents(100, "USD").format  #=> "$1.00"
Money.from_cents(100, "GBP").format  #=> "£1.00"
Money.from_cents(100, "EUR").format  #=> "€1.00"

Currency conversion is the step where the README stops short. The example calls some_code_to_setup_exchange_rates and then Money.from_cents(1000, "USD").exchange_to("EUR"). There is no rate provider in the snippet. You supply the rates.

exchange_to has no rate source, and that is the main limitation

The README's conversion example is a placeholder: some_code_to_setup_exchange_rates. Nothing in the documented material fetches a rate from an API, reads a file or ships a rate table. The gem gives you the exchange_to call and the arithmetic; the data is your problem. Anyone expecting a working converter after gem install money will be disappointed, and the README does not pretend otherwise.

There is a second boundary. Money.from_cents(1000, "USD").with_currency("EUR") is documented as producing 1000 EUR. That is a relabeling, not a conversion, and the README places it under the comment "Swap currency". If a caller reaches for with_currency when they meant exchange_to, the amount is unchanged and no error is raised. Nothing in the documented API prevents that mistake; only code review does.

A third constraint is the default currency. The README states that no default currency is set, and that without one the library raises an error when you initialize a Money without an explicit currency or parse a string with no currency in it. Applications that rely on an implicit locale currency must set Money.default_currency themselves, as the README shows with Money::Currency.new("CAD").

Finally, the README opens with a warning to read the upgrade guides before moving to a new major version, and the repository root contains UPGRADING-6.0.md and UPGRADING-7.0.md. Major upgrades are a documented event, not a silent one.

Registering a currency and using priority for selectors

For currencies outside the built-in table, or for overriding attributes, the README documents Money::Currency.register with a hash. Only iso_code is required; the rest are optional. The example registers USD with priority 1, iso_numeric "840", symbol "$", subunit "Cent", subunit_to_unit 100, decimal_mark "." and thousands_separator ",".

ruby
curr = {
  priority:            1,
  iso_code:            "USD",
  iso_numeric:         "840",
  name:                "United States Dollar",
  symbol:              "$",
  subunit:             "Cent",
  subunit_to_unit:     100,
  decimal_mark:        ".",
  thousands_separator: ","
}

Money::Currency.register(curr)

The priority attribute is described as an arbitrary number you can use for sorting and grouping. The README's own example builds a currency selector by filtering Money::Currency.table down to entries with priority below 10, which the example returns as [:usd, :eur, :gbp, :aud, :cad, :jpy], and lists every currency id with hash.keys. That is a small amount of code for a common UI problem, and it is the clearest illustration in the README of why currency objects beat currency strings.

Where this gem sits against other Ruby money libraries

The direct comparison is the monetize gem, which the README points to at the top for anyone who misses String parsing. The split is deliberate: RubyMoney/money handles amounts, currencies and arithmetic, and monetize handles turning strings such as "$10.00" into Money objects. If your input is user-typed price text, you likely want both, and the README says as much rather than pretending the core gem covers parsing.

Compared with storing amounts as decimals in the database and doing arithmetic in BigDecimal, this gem's approach is to keep the integer in cents and attach currency semantics at the object level. The difference shows up in equality and formatting: BigDecimal has no notion of currency, so a USD value and an EUR value with the same magnitude compare equal unless you track the currency separately. RubyMoney/money makes that comparison false by construction, as the README's equality examples show.

Compared with calling a currency conversion API directly, the gem gives you the arithmetic and the currency model but not the rates. If all you need is a one-off conversion, an HTTP call plus a multiply is less machinery. The gem earns its place when converted and unconverted amounts both flow through the same application code and need consistent formatting and safe arithmetic.

Maintenance, licence and what an upgrade costs

The repository is not archived and the last push was on 2026-09-23, days before this writing, so the codebase is receiving commits. The README carries no release notes and no version history beyond the pointers to UPGRADING-6.0.md and UPGRADING-7.0.md, so the practical maintenance question is not whether the project moves but what a major bump costs you.

The README's warning is explicit: read the upgrade guides before upgrading to a new major version. Two such guides sit in the repository root, which tells you that at least two major transitions required migration work. Pin the gem version in your Gemfile and read the relevant guide before bumping the major. That is a concrete cost, and it is the main ongoing maintenance item the documented material supports.

The licence is MIT, per the repository's LICENSE file and the badge in the README. In practical terms an MIT licence permits commercial use and modification with the licence text retained; this is a description of the licence, not legal advice, and your own counsel should review anything that matters to you. The README does not discuss any commercial offering, support contract or dual licensing, so there is nothing else to weigh on that axis.

Editorial conclusion

Adopt RubyMoney/money if you need arithmetic on monetary amounts in Ruby and want integer subunits rather than floats, and if you are willing to supply exchange rates yourself rather than have the gem fetch them. Do not adopt it as a rate feed or as a replacement for your accounting ledger; the README shows exchange_to relying on a setup step you write. Before adding it to a Gemfile, read UPGRADING-6.0.md and UPGRADING-7.0.md, because the README warns that upgrade guides must be read before a new major version, and confirm your application runs with UTF-8 since the README states non-ASCII currency attributes are present.

Frequently asked questions

How do I install RubyMoney/money?

The README gives gem install money for a stable release, or a development install by cloning the Git repository, changing into the directory and running bin/rake install.

Does RubyMoney/money fetch exchange rates for me?

No. The README's conversion example calls some_code_to_setup_exchange_rates before exchange_to, and no rate provider appears anywhere in the documented material, so you supply the rates.

What is the difference between exchange_to and with_currency in RubyMoney/money?

The README documents exchange_to as a currency conversion and with_currency as a currency swap. Money.from_cents(1000, "USD").with_currency("EUR") produces 1000 EUR, so the number is unchanged.

Why does RubyMoney/money store amounts in cents instead of floats?

The README states that monetary values are represented as integers, in cents, and that this avoids floating point rounding errors. Money.from_cents(1000, "USD") reports .cents as 1000.

Does RubyMoney/money work without a default currency set?

The README states that no default currency is set by default, and that without one the library raises an error when you initialize a Money without an explicit currency or parse a string containing no currency. You set one with Money.default_currency.

Official sources

  1. Issues
  2. License: MIT
  3. Project website
  4. README
  5. RubyMoney/money on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/rubymoney-money.svg)](https://hysenlabs.com/projects/rubymoney-money)