Revision: 30494
Initial Code
Initial URL
Initial Description
Initial Title
Initial Tags
Initial Language
at August 15, 2010 14:21 by viatropos
Initial Code
require 'rubygems'
require 'active_model'
# use this if you want to create before and after filters around a commonly used
# method, but still want to define the method in subclasses.
module SubclassableCallbacks
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
attr_accessor :subclassable_callbacks
def subclassable_callbacks(*methods)
@subclassable_callbacks ||= []
unless methods.empty?
@subclassable_callbacks = @subclassable_callbacks.concat(methods).flatten.compact.map(&:to_sym).uniq
define_model_callbacks *methods
class_eval do
methods.each do |variable|
define_method "implementation_#{variable.to_s}" do; end
define_method variable do
send("_run_#{variable.to_s}_callbacks") do
send("implementation_#{variable.to_s}")
end
end
alias_method "superclass_#{variable.to_s}", variable
end
end
end
@subclassable_callbacks
end
end
def self.override
ObjectSpace.each_object(Class) do |object|
if object.ancestors.include?(SubclassableCallbacks)
object.class_eval do
methods = object.subclassable_callbacks
last_index = object.superclass.ancestors.index(SubclassableCallbacks)
if last_index && last_index > 0
superclass_methods = object.superclass.ancestors[0..last_index - 1].map(&:subclassable_callbacks)
methods = methods.concat(superclass_methods).flatten.uniq
end
methods.each do |name|
alias_method "subclass_#{name}", "#{name}"
alias_method "implementation_#{name}", "subclass_#{name}"
alias_method "#{name}", "superclass_#{name}"
end
end
end
end
end
end
class BaseModel
extend ActiveModel::Callbacks
include SubclassableCallbacks
subclassable_callbacks :save
before_save { puts "[save:before]"}
after_save { puts "[save:after]"}
end
class SomeModel < BaseModel
def save
puts "[saving some_model...]"
true
end
end
class AnotherModel < BaseModel
def save
puts "[saving another_model...]"
true
end
end
SubclassableCallbacks.override
SomeModel.new.save
#=> [save:before]
#=> [saving some_model...]
#=> [save:after]
AnotherModel.new.save
#=> [save:before]
#=> [saving another_model...]
#=> [save:after]
Initial URL
ruby-metaprogramming-subclassable-callback-module
Initial Description
Initial Title
Ruby Metaprogramming - Subclassable Callback Module
Initial Tags
object, ruby
Initial Language
Ruby