easy_attributes

Easy Attributes is a Ruby DSL to give more control to attributes. Tested with ruby 1.87 & 1.9.2

Usage

Easy Attributes works in any Ruby class, it does not require Active Record or other ORM.

First, install this from rubygems.org

gem install easy_attributes

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

require 'rubygems'                 # Ruby application, no framework
require 'easy_attributes'          #

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

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

Configuration:

EasyAttributes::Config.orm = :active_model   # will generate some validations, etc.
EasyAttributes::Config.load(filename)        # Loads a file of column/value/names/descriptions
EasyAttributes::define(attribute_name, {:name=>value, ...})

Declaration:

class Record < ObjectRelationalMapperOfChoice
  include EasyAttributes

  attr_values :field, :name=>'value', :name=>'value', ... :validate=>:active_record, :required=>true, :like=>'other' ...
  attr_sequence  :field, :name, :name, ... ,:start=>1, :step=>1
  attr_money  :amount, :units=>"dollars", :unit=>'$', :negative=>'%.2f CR'
  attr_bytes  :bandwidth
end

attr_values

will define:

field()              # => value  ### if orm == :attr, attr_accessor will be installed for the attribute
field=(value)        # => value  ### for active_model classes
field_sym()          # => :name
field_sym=(symbol)   # => value
field_values()       # => {:name=>value, ...}
field_is?(:name)     # true if :name matches current value
field_is?(:name, :name, ...)  # true if value matches a given symbol
field_is?(:greater_than, :name) # true if the value is greater than the value of :name
  The first argument can be one of: 
  :greater_than, :gt, :greater_than_or_equal, :ge, :less_than, :lt, :less_than_or_equal, :le
field_is?(:between, :name1, :name2) # true if the value is between the corresponding values

attr_sequence

sets up a attr_values with the sequential numbering, by default starting at 1 incrementing by 1

attr_bytes

Creates helper fields to display and accept byte quantities as KB, MB, GB, TB, etc. Since a kilobyte (KB) is now defined as 1000 bytes, and a kibibyte (KiB) is the 1024 quantity, you wan to configure which you want to use

EasyAttributes::Config.kb_size = 1000   # Uses KB units as 1KB = 1000 bytes
EasyAttributes::Config.kb_size = 1024   # Uses KB units as 1KB = 1024 bytes
EasyAttributes::Config.kb_size = :new   # Uses KiB units as 1KiB = 1024 bytes (DEFAULT)
EasyAttributes::Config.kb_size = :both  # Combines usage of KB (1000) and KiB (1024) units (Watch out!)

attr_bytes creates the following methods for a :bandwidth attribute

bandwidth_bytes = "1 KB"                # => 1024
bandwidth_bytes                         # => "1 KB" using whatever unit is best
bandwidth_bytes(:MiB)                   # => "12345.67 MB" using the specified unit
bandwidth_bytes(:MiB, :precision=>0)    # => "123 MB"

attr_money

is the inclusion of my easy_money gem

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

class Ledger
  include EasyAttributes
  attr_accessor :amount, :euro     # Integer value of cents
  attr_money :amount               # Creates amount_money() and amount_money=() methods
  attr_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 EasyAttributes
  attr_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 attr_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

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, suitable 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 EasyAttributes
...
puts EasyAttributes.money_to_integer( money_string, :option=>value, ... )
puts EasyAttributes.integer_to_money( cents_integer, :option=>value, ... )
puts EasyAttributes.integer_to_float( cents_integer, :option=>value, ... )
puts EasyAttributes.float_to_integer( money_float, :option=>value, ... )

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

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

Note on Patches/Pull Requests

  • Fork the project.

  • Make your feature addition or bug fix.

  • Add tests for it. This is important so I don't break it in a future version unintentionally.

  • Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but

    bump version in a commit by itself I can ignore when I pull)
    
  • Send me a pull request. Bonus points for topic branches.

Copyright

Copyright © 2010 Allen Fair. See LICENSE for details.