require 'active_support/callbacks'
module ActiveModel
module Callbacks
def self.extended(base)
base.class_eval do
include ActiveSupport::Callbacks
end
end
# Define callbacks similar to ActiveRecord ones. It means:
#
# * The callback chain is aborted whenever the block given to
# _run_callbacks returns false.
#
# * If a class is given to the fallback, it will search for
# before_create, around_create and after_create methods.
#
# == Usage
#
# First you need to define which callbacks your model will have:
#
# class MyModel
# define_model_callbacks :create
# end
#
# This will define three class methods: before_create, around_create,
# and after_create. They accept a symbol, a string, an object or a block.
#
# After you create a callback, you need to tell when they are executed.
# For example, you could do:
#
# def create
# _run_create_callbacks do
# super
# end
# end
#
# == Options
#
# define_model_callbacks accepts all options define_callbacks does, in
# case you want to overwrite a default. Besides that, it also accepts
# an :only option, where you can choose if you want all types (before,
# around or after) or just some:
#
# define_model_callbacks :initializer, :only => :after
#
def define_model_callbacks(*callbacks)
options = callbacks.extract_options!
options = { :terminator => "result == false", :scope => [:kind, :name] }.merge(options)
types = Array(options.delete(:only))
types = [:before, :around, :after] if types.empty?
callbacks.each do |callback|
define_callbacks(callback, options)
types.each do |type|
send(:"_define_#{type}_model_callback", self, callback)
end
end
end
def _define_before_model_callback(klass, callback) #:nodoc:
klass.class_eval <<-CALLBACK, __FILE__, __LINE__
def self.before_#{callback}(*args, &block)
set_callback(:#{callback}, :before, *args, &block)
end
CALLBACK
end
def _define_around_model_callback(klass, callback) #:nodoc:
klass.class_eval <<-CALLBACK, __FILE__, __LINE__
def self.around_#{callback}(*args, &block)
set_callback(:#{callback}, :around, *args, &block)
end
CALLBACK
end
def _define_after_model_callback(klass, callback) #:nodoc:
klass.class_eval <<-CALLBACK, __FILE__, __LINE__
def self.after_#{callback}(*args, &block)
options = args.extract_options!
options[:prepend] = true
options[:if] = Array(options[:if]) << "!halted && value != false"
set_callback(:#{callback}, :after, *(args << options), &block)
end
CALLBACK
end
end
end