Vacuum Cleaner
A Ruby (and Rails) attribute normalization gem.
Note: Starting with Version 2.0.0 it is no longer compatible with Rails 2.x, please use 1.x.
Installation
Add this line to your application's Gemfile:
gem 'mote_sms'
And then execute:
$ bundle
Or install it yourself as:
$ gem install mote_sms
Usage
It creates a new setter method for an attribute and thus allows the normalizers defined to reprocess the input value.
class Doctor
include VacuumCleaner::Normalizations # enables #normalizes, NOTE: not required for ActiveRecord models
attr_accessor :name # create some reader/writter
normalizes :name # enables strip/clean-up magic on attribute :name
end
Using normalizes
just adds a default normalization implemenation, which removes leading/trailing
whitespace and converts spaces only to nil
. Everything happens upon "set".
@doc = Doctor.new
@doc.name = " Elliot Reid\n\t"
@doc.name # => "Elliot Reid" => trailing space was stripped
@doc.name = "\t\n"
@doc.name # => nil => converted to nil
Okay, this is how it basically works, the normalizes
call just generates a new setter method,
which normalizes
the input value and then calls the original setter method.
What else can be done then?
# can be used with multiple attributes (if they all share the same normalizer)
normalizes :name, :company
# provides a fancy :downcase and :upcase normalizer (guess what they do)
normalizes :email, :downcase => true
# "JD@EXAMPLE.COM \n" => "jd@example.com"
# provides a :method normalizer which takes a string/symbol as argument which is
# then called upon the resulting value (if it respond_to)
normalizes :name, :method => :titleize
# "carla ESPINOSA" => "Carla Espinosa" PS: only works if ActiveSupport is available :)
# or a simple URL normalizer, which prefixes http:// if not starting with
# http or https
normalizes :homepage, :url => true
# "google.com" => "http://google.com"
# "http://example.com" => "http://example.com" PS: left as is
Take a look at VacuumCleaner::Normalizer
, about how the process works and how custom
reusable normalizers can be written. For the-quick-fix-that-shouldnt-have-been-used-but-was
case or if there's no reuse, normalizes
takes a block as argument which is called
after any other normalizer in the chain. Note that normalizers are not halted, nor stopped
if they return nil
or false
or something similar, so ensure that case is handled properly.
# strips all whitespace within a string
normalizes(:phone) { |value| value.to_s.gsub(/\s+/, '') unless value.nil? }
# "\t+45 123 123 " => "+45123123" PS: yes, the standard strip etc. magic is still run
# no need for the default normalizer and feeling really custom?
normalizes(:phone, :default => false, :upcase => true) { |value| value.to_s.strip.gsub(/\s+/, '') }
# "\t0800 sacred heart" => "0800SACREDHEART"
# "\t\n" => ""
# nil => ""
Need access to the full object within the block? As easy as:
# naming J.D. after some girly girl?
normalizes(:first_name) do |obj, attribute, value|
obj.name == "Dorian" ? %w{Agnes Shirley Denise}[rand(3)] : value
end
Background
As mentoined earlier normalizes
creates a new setter method, so let's shortly take a look
at how.
normalizes(:name)
# 1. creates a :normalize_name method, which contains the normalization chain, block etc.
# 2. if :name= exists, it's aliased to :name_without_normalization=
# 3. creates a new :name= method, which calls :normalize_name, then tries to
# set the normalized value by one of:
# a) calling :name_without_normalization=, if defined
# b) self[:name] = v, if it responds to :[]= (for ActiveRecord support)
# c) or, as a fallback, sets @name to the result of :normalize_name
Lessons learned: when the need arises to set the value without any normalization and there's
a setter just use @object.name_without_normalization = "har har har\n\t"
. Feel free to
completly override normalize_<attribute>
, but a much smarter way to add very custom normalizers
is by a) providing a block to normalizes
or b) create a custom VacuumCleaner::Normalizer
implementation.
Some info about the different files, might be a good place to look at when trying to figure
out how to write custom VacuumCleaner::Normalizer
implemenations, or for a look at how
it works.
lib/vacuum_cleaner/normalizer.rb # Base Normalizer implementation
lib/vacuum_cleaner/normalizations/*.rb # Some default Normalizer implementations, like url, downcase etc.
lib/vacuum_cleaner/normalizations.rb # Provides the `normalizes` method and all the logic etc.