Easy Money!

A Ruby mixin library to add simple money display and editing using data stored as an integer in cents or other precision or currency. Easy Money is a simpler alternative to the “money” gem, and easier to use, hence the name.

Float types are not good for storing and computing financial data because of rounding and conversion between floats and decimal precision and slower performance compared to integer arithmetic. Integers are preferred in this case, with a dollar amount ($1.00) stored as cents (100) internally.

Easy Money will also handle any float data stored as integer in the database for this reason, such as FM Radio Frequencies (88.1 FM) or an NTRP Tennis Rating (4.5).

Quick Start

Easy Money works in any Ruby class, it does not require Active Record or other ORM. Its default setting allow it to work on US Dollar amounts stored in cents, but is easily configured.

First, install this from gemcutter

gem install easy_money

Next, you need to configure your app to use it, by either:

require 'rubygems'                 # Rails application, no framework
require 'easy_money'               # 

config.gem 'easy_money'            # Rails 2.x, in your ./config/environment.rb

gem 'easy_money'                   # Rails 3.x, in your ./Gemfile

Mixin the EasyMoney module into the (model) class you need, and declare the attributes (columns) you wish you have the easy_money helpers

class Ledger
  include EasyMoney
  attr_accessor :amount, :euro     # Integer value of cents
  easy_money :amount               # Creates amount_money() and amount_money=() methods
  easy_money :amount, :units=>"dollars", :unit=>'$', :negative=>'%.2f CR'
                                   # Creates amount_dollars() and amount_dollars=() methods
end

ledger = Ledger.new
ledger.amount = 100                # 100 cents = $1.00
ledger.amount_money                #=> "1.00"
ledger.amount_money = "-123.45"
ledger.amount                      #=> -12345 (cents)
ledger.amount_money(:negative=>'%.2f CR', :zero=>'Free') # Uses these formats 
ledger.amount_dollars              #=> "$123.45 CR"

# Track the bets of the Gamesters of Triskelion on their drill thrall competitions.
class ProviderWagers < ActiveRecord::Base
  include EasyMoney
  easy_money :quatloos, :units=>'quatloos', :precision=>3, 
    :zero=>'even', :nil=>'no bet', :negative=>'%.3f Loss', :unit=>'Q',
    :negative_regex=>/^(-?)(.+\d)\s*Loss/i
                                   # creates amount_quatloos(), amount_quatloos=()
end

# in your views
<%= f.text_field :amount_quatloos %>  # -12000 => "Q12.000 Loss"

Options for Easy Money calls:

  • :money_method - Use this as the alternative name to the money-access methods

  • :units - Use this as an alternative suffix name to the money methods (‘dollars’ gives ‘xx_dollars’)

  • :precision - The number of digits implied after the decimal, default is 2

  • :separator - The character to use after the integer part, default is ‘.’

  • :delimiter - The character to use between every 3 digits of the integer part, default none

  • :positive - The sprintf format to use for positive numbers, default is based on precision

  • :negative - The sprintf format to use for negative numbers, default is same as :positive

  • :zero - The sprintf format to use for zero, default is same as :positive

  • :nil - The sprintf format to use for nil values, default none

  • :unit - Prepend this to the front of the money value, say ‘$’, default none

  • :blank - Return this value when the money string is empty or has no digits on assignment

  • :negative_regex - A Regular Expression used to determine if a number is negative (and without a - sign), defaults to having a “CR” after the number

Easy Money Formatters

You can also call or build your own custom conversions. Ensure that you can convert between the integer and money forms if you need to.

The “money” type is a string, sutitable for human editing, and will convert back into integer type. If you override the formatting options, test that your money result string will convert properly back to the original integer value.

include EasyMoney
...
puts EasyMoney.money_to_integer( money_string, :option=>value, ... )
puts EasyMoney.integer_to_money( cents_integer, :option=>value, ... )
puts EasyMoney.integer_to_float( cents_integer, :option=>value, ... )
puts EasyMoney.float_to_integer( money_float, :option=>value, ... )

EasyMoney.integer_to_float( nil, blank:0.0 ) #=> 0.0  [Ruby 1.9.1 Syntax]
EasyMoney.integer_to_float( 12345, :precision=>3 ) #=> 12.345
EasyMoney.float_to_integer(12.345111, :precision=>3 ) #=> 12345

The options to these methods are the same as the #easy_money declarations

To Do

  • Validate Money string format

  • Global configuration for currency settings

  • Explore rounding vs. truncation issues

  • Use a Locale and I18n on money formatting, without introducing dependencies (perhaps by injection)?

  • Explore inegration of Rails’ NumberHelper methods, but not require ActionView

  • Custom converters (useful for say, converting bytes to Gigabytes)?

Copyright © 2010 Allen Fair. See LICENSE for details.