Ruby gem for representing monetary values.
Pure Ruby—compatible with MRI/CRuby, JRuby, TruffleRuby, and Natalie.
Using Bundler:
$ bundle add monies
Using RubyGems:
$ gem install monies
Getting started:
require 'monies'
a = Monies(11, 'USD')
b = Monies('22.22', 'USD') * 2
c = Monies.parse('$33.44')
puts Monies.format(a + b + c, symbol: true)
Currencies are represented as strings. Using ISO 4217 currency codes is recommended for maximum interoperability, however there are no restrictions on what strings you can use. For example:
Monies(10, 'USD')
Monies(10, 'BTC')
Monies(10, 'GBX')
Monies(10, 'X')
Monies(10, 'LOL')
Monies(10, 'Cubit')
Monies(10, 'Latinum')
Monies(10, 'sats')
If your application primarily uses a single currency you can set a default currency:
Monies.currency = 'USD'
Monies(10)
Arithmetic is currency checked to prevent errors:
Monies(1, 'USD') + Monies(1, 'RUB') # raises Monies::CurrencyError
If you need to sum amounts in different currencies you should first convert them all to the same currency.
Division is limited to 16 decimal places by default, which ought to be enough for everyone. If you need more accuracy you can use the #div method to specify the maximum number of decimal places you want:
Monies(1, 'USD').div(9, 100)
Use the #allocate method to split an amount into a number of smaller amounts:
installments = Monies(1, 'USD').allocate(3, 2)
Use the #convert method to convert instances to another currency:
value = Monies('1.23', 'BTC')
price = Monies(100_000, 'USD')
puts value.convert(price).round(2)
Fetching price data, caching that data, and rounding the result are all responsibilities of the caller.
Use the Monies
method to convert strings that are expected to be valid and
don't contain special formatting, such as those in source code and databases:
Monies('12345.6')
Use the Monies.parse
method to parse strings that could be invalid or could
contain special formatting like thousand separators, currency codes, or symbols:
Monies.parse('£1,999.99')
Monies.parse('1.999,00 EUR')
An ArgumentError
exception is raised for invalid input:
Monies.parse('notmoney') # raises ArgumentError
Currency symbols and currency codes are defined in Monies.symbols
which can
be updated to support additional currencies using #[]= or #update. For example:
Monies.symbols["\u20BF"] = 'BTC'
Monies.symbols.update({"\u20BF" => 'BTC'})
Monies.parse('1,000 BTC')
Use the Monies.format
method to produce formatted strings:
Monies.format(Monies('1234.56', 'USD')) # "1,234.56"
Specify the code
or symbol
options to include the currency code or symbol:
Monies.format(Monies('1234.56', 'USD'), code: true) # "1,234.56 USD"
Monies.format(Monies('1234.56', 'USD'), symbol: true) # "$1,234.56"
Specify the name of the format to use different formatting rules:
Monies.format(Monies('1234.56', 'USD'), :eu) # "1.234,56"
The default format is :en
and can be changed by updating Monies.formats
,
for example to change the default format to the built-in :eu
format:
Monies.formats[:default] = Monies.formats[:eu]
To create a custom format first create a Monies::Format
subclass,
and then add the format to Monies.formats
. For example:
class CustomFormat < Monies::Format::EN
# ...
end
Monies.formats[:custom] = CustomFormat.new
Monies integrates with the bigdecimal gem for multiplication and currency conversion. For example:
require 'bigdecimal/util'
Monies('1.23', 'USD') * BigDecimal('0.1')
Use the Monies
method to convert from a BigDecimal
value:
Monies(BigDecimal(10), 'USD')
Use the #to_d method to convert to a BigDecimal
value:
monies.to_d
Specify a currency argument to use BigDecimal
values for currency conversion:
monies = Monies('1.11', 'BTC')
monies.convert(BigDecimal(100_000), 'USD').round(2)
Monies integrates with the percentage gem for percentage calculations. For example:
require 'percentage'
capital_gains = Monies(10_000, 'GBP')
tax_rate = Percentage.new(20)
tax_liability = capital_gains * tax_rate
puts tax_liability
Monies integrates with the sequel gem to support database serialization. For example:
class Product < Sequel::Model
plugin Monies::Serialization::Sequel
serialize_monies :price
end
This will serialize the value and the currency as a single string.
You can also specify the currency at the model/application level using the currency keyword argument:
serialize_monies :price, currency: Monies.currency
This will serialize just the value as a single string.
You can also use two columns, one for the value and an additional string column to store the currency:
serialize_monies :price, currency: :currency
Monies integrates with the activerecord gem to support database serialization. For example:
class Product < ApplicationRecord
include Monies::Serialization::ActiveRecord
serialize_monies :price
end
Usage of serialize_monies
is identical to the sequel integration.
Monies is released under the LGPL-3.0 license.