module ActiveSupport::Callbacks::ClassMethods

def __callback_runner_name(kind)

def __callback_runner_name(kind)
  __callback_runner_name_cache[kind]
end

def __callback_runner_name_cache

def __callback_runner_name_cache
  @__callback_runner_name_cache ||= ThreadSafe::Cache.new {|cache, kind| cache[kind] = __generate_callback_runner_name(kind) }
end

def __define_callbacks(kind, object) #:nodoc:

:nodoc:
This generated method plays caching role.
if it was not yet defined.
This method defines callback chain method for the given kind
def __define_callbacks(kind, object) #:nodoc:
  name = __callback_runner_name(kind)
  unless object.respond_to?(name, true)
    str = object.send("_#{kind}_callbacks").compile
    class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
      def #{name}() #{str} end
      protected :#{name}
    RUBY_EVAL
  end
  name
end

def __generate_callback_runner_name(kind)

def __generate_callback_runner_name(kind)
  "_run__#{self.name.hash.abs}__#{kind}__callbacks"
end

def __reset_runner(symbol)

def __reset_runner(symbol)
  name = __callback_runner_name(symbol)
  undef_method(name) if method_defined?(name)
end

def __update_callbacks(name, filters = [], block = nil) #:nodoc:

:nodoc:
CallbackChain.
This is used internally to append, prepend and skip callbacks to the
def __update_callbacks(name, filters = [], block = nil) #:nodoc:
  type = CALLBACK_FILTER_TYPES.include?(filters.first) ? filters.shift : :before
  options = filters.last.is_a?(Hash) ? filters.pop : {}
  filters.unshift(block) if block
  ([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse.each do |target|
    chain = target.send("_#{name}_callbacks")
    yield target, chain.dup, type, filters, options
    target.__reset_runner(name)
  end
end

def define_callbacks(*callbacks)

would call Audit#save.

define_callbacks :save, scope: [:name]

A declaration like

which callbacks are being defined.
callback (before/after/around) and +:name+ refers to the method on
and +:name+ have special meanings: +:kind+ refers to the kind of
case "kind" is "before" and "name" is "save". In this context +:kind+
by calling #{kind}_#{name} on the given instance. In this
would trigger Audit#before_save instead. That's constructed

define_callbacks :save, scope: [:kind, :name]

Audit#before will be called. On the other hand
In the above case whenever you save an account the method

end
end
end
puts 'save in main'
run_callbacks :save do
def save

set_callback :save, :before, Audit.new
define_callbacks :save

include ActiveSupport::Callbacks
class Account

end
end
puts 'Audit: before_save is called'
def before_save(caller)

end
puts 'Audit: before is called'
def before(caller)
class Audit

object is used as a callback.
* :scope - Indicates which methods should be executed when an

option is specified.
terminated or not. Option makes sense only when :terminator
default after callbacks executed no matter if callback chain was
callbacks should be terminated by the :terminator option. By
* :skip_after_callbacks_if_terminated - Determines if after

halts the chain.
other callbacks are not executed. Defaults to +false+, meaning no value
In this example, if any before validate callbacks returns +false+,

define_callbacks :validate, terminator: 'result == false'

result of the callback is available in the +result+ variable.
the event from being triggered. This is a string to be eval'ed. The
callback chain, preventing following callbacks from being called and
* :terminator - Determines when a before filter will halt the

===== Options

define_callbacks :initialize, :save, :destroy
define_callbacks :validate

Define sets of events in the object life cycle that support callbacks.
def define_callbacks(*callbacks)
  config = callbacks.last.is_a?(Hash) ? callbacks.pop : {}
  callbacks.each do |callback|
    class_attribute "_#{callback}_callbacks"
    send("_#{callback}_callbacks=", CallbackChain.new(callback, config))
  end
end

def reset_callbacks(symbol)

Remove all set callbacks for the given event.
def reset_callbacks(symbol)
  callbacks = send("_#{symbol}_callbacks")
  ActiveSupport::DescendantsTracker.descendants(self).each do |target|
    chain = target.send("_#{symbol}_callbacks").dup
    callbacks.each { |c| chain.delete(c) }
    target.send("_#{symbol}_callbacks=", chain)
    target.__reset_runner(symbol)
  end
  self.send("_#{symbol}_callbacks=", callbacks.dup.clear)
  __reset_runner(symbol)
end

def set_callback(name, *filter_list, &block)

existing chain rather than appended.
* :prepend - If +true+, the callback will be prepended to the
callback will be called only when it returns a +false+ value.
* :unless - A symbol naming an instance method or a proc; the
callback will be called only when it returns a +true+ value.
* :if - A symbol naming an instance method or a proc; the

===== Options

wasn't halted, from the +yield+ call.
Around callbacks can access the return value from the event, if it

after callbacks are called in the reverse order.
Before and around callbacks are called in the order that they are set;

an argument.
of the current object. It can also optionally accept the current object as
If a proc, lambda, or block is given, its body is evaluated in the context

argument to +define_callback+.
object that responds to a certain method determined by the :scope
proc, lambda, or block; as a string to be instance evaluated; or as an
The callback can be specified as a symbol naming an instance method; as a

set_callback :save, :before_meth

means the first example above can also be written as:
+:after+, or +:around+ the event. If omitted, +:before+ is assumed. This
The second arguments indicates whether the callback is to be run +:before+,

set_callback :save, :around, ->(r, &block) { stuff; result = block.call; stuff }
set_callback :save, :after, :after_meth, if: :condition
set_callback :save, :before, :before_meth

Install a callback for the given event.
def set_callback(name, *filter_list, &block)
  mapped = nil
  __update_callbacks(name, filter_list, block) do |target, chain, type, filters, options|
    mapped ||= filters.map do |filter|
      Callback.new(chain, filter, type, options.dup, self)
    end
    options[:prepend] ? chain.prepend(*mapped) : chain.append(*mapped)
    target.send("_#{name}_callbacks=", chain)
  end
end

def skip_callback(name, *filter_list, &block)

end
skip_callback :validate, :before, :check_membership, if: -> { self.age > 18 }
class Writer < Person

callback is skipped.
:unless options may be passed in order to control when the
Skip a previously set callback. Like +set_callback+, :if or
def skip_callback(name, *filter_list, &block)
  __update_callbacks(name, filter_list, block) do |target, chain, type, filters, options|
    filters.each do |filter|
      filter = chain.find {|c| c.matches?(type, filter) }
      if filter && options.any?
        new_filter = filter.clone(chain, self)
        chain.insert(chain.index(filter), new_filter)
        new_filter.recompile!(options)
      end
      chain.delete(filter)
    end
    target.send("_#{name}_callbacks=", chain)
  end
end