This library aids one in handling money and different currencies. Features:
-
Provides a Money class which encapsulates all information about an certain amount of money, such as its value and its currency.
-
Represents monetary values as integers, in cents. This avoids floating point rounding errors.
-
Provides APIs for exchanging money from one currency to another.
-
Has the ability to parse a money string into a Money object.
Resources:
-
Website: money.rubyforge.org
-
RDoc API: money.rubyforge.org
-
Git repository: github.com/FooBarWidget/money/tree/master
Install stable releases with the following command:
gem install money
The development version (hosted on Github) can be installed with:
gem sources -a https://gems.github.com gem install FooBarWidget-money
require 'money' # 10.00 USD money = Money.new(1000, "USD") money.cents # => 1000 money.currency # => "USD" Money.new(1000, "USD") == Money.new(1000, "USD") # => true Money.new(1000, "USD") == Money.new(100, "USD") # => false Money.new(1000, "USD") == Money.new(1000, "EUR") # => false
Exchanging money is performed through an exchange bank object. The default exchange bank object requires one to manually specify the exchange rate. Here’s an example of how it works:
Money.add_rate("USD", "CAD", 1.24515) Money.add_rate("CAD", "USD", 0.803115) Money.us_dollar(100).exchange_to("CAD") # => Money.new(124, "CAD") Money.ca_dollar(100).exchange_to("USD") # => Money.new(80, "USD")
Comparison and arithmetic operations work as expected:
Money.new(1000, "USD") <=> Money.new(900, "USD") # => 1; 9.00 USD is smaller Money.new(1000, "EUR") + Money.new(10, "EUR") == Money.new(1010, "EUR") Money.add_rate("USD", "EUR", 0.5) Money.new(1000, "EUR") + Money.new(1000, "USD") == Money.new(1500, "EUR")
There is nothing stopping you from creating bank objects which scrapes www.xe.com for the current rates or just returns rand(2)
:
Money.default_bank = ExchangeBankWhichScrapesXeDotCom.new
Use the compose_of
helper to let Active Record deal with embedding the money object in your models. The following example requires a cents
and a currency
field.
class ProductUnit < ActiveRecord::Base belongs_to :product composed_of :price, :class_name => "Money", :mapping => [%w(cents cents), %w(currency currency)] private validate :cents_not_zero def cents_not_zero errors.add("cents", "cannot be zero or less") unless cents > 0 end validates_presence_of :sku, :currency validates_uniqueness_of :sku end
By default Money defaults to USD as its currency. This can be overwritten using
Money.default_currency = "CAD"
If you use Rails, then environment.rb is a very good place to put this.