Skip to content

Instantly share code, notes, and snippets.

@txus
Created February 27, 2011 15:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save txus/846276 to your computer and use it in GitHub Desktop.
Save txus/846276 to your computer and use it in GitHub Desktop.
Draft implementation of ActiveModel::Transformations
class Address
include ActiveModel::Transformations
attr_accessor :street, :phone
transform :street do |name|
name.split(' ').map(&:capitalize).join(' ')
end
transform :phone do |number|
number.gsub('-','')
end
def initialize(attributes = {})
attributes.each do |key, value|
send "#{key}=", value
end
end
def save
run_callbacks :save
end
end
# See Mike Perham's proposal on ticket: https://rails.lighthouseapp.com/projects/8994/tickets/6477-activemodel-transformations
module ActiveModel
# == Active Model Transformations
#
# Provides a set of callbacks to perform transformations on your model
# attributes before being assigned.
#
# A minimal implementation could be:
#
# class Person
# include ActiveModel::Transformations
#
# attr_accessor :first_name, :phone_number
#
# transform :first_name do |name|
# name.capitalize
# end
#
# transform :phone_number do |number|
# num.gsub(/\D/, '')
# end
#
# end
#
# Which pre-processes attributes on assignment like this:
#
# person = Person.new(:first_name => 'john', :phone_number => '93-788-43-42')
# person.save!
# person.first_name # => 'John'
# person.phone_number # => '937884342'
#
module Transformations
extend ActiveSupport::Concern
include ActiveSupport::Callbacks
included do
define_callbacks :save
define_callbacks :transform
set_callback(:save, :before, :run_transformations!)
end
module ClassMethods
def transform(*args, &block)
args.each do |arg|
set_callback(:transform, arg) do |object|
object.send(:"#{arg}=", block.call(object.send(arg)))
end
end
end
# TODO: Copy transformations on inheritance.
def inherited(base)
# . . .
super
end
end
protected
def run_transformations!
run_callbacks :transform
end
end
end
# encoding: utf-8
require 'cases/helper'
require 'models/address'
class TransformationsTest < ActiveModel::TestCase
def teardown
Address.reset_callbacks(:transform)
Address.reset_callbacks(:save)
end
def test_single_field_transformation
a = Address.new(:street => "c sant joan", :phone => '93-788-42-42')
a.save
assert_equal 'C Sant Joan', a.street
assert_equal '937884242', a.phone
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment