module ActiveSupport::Callbacks
def run_callbacks(kind, type = nil)
smoothly through and into the supplied block, we want as little evidence
callback can be as noisy as it likes -- but when control has passed
the visible call stack. An exception from inside a :before or :after
user code, it has an additional design goal of minimizing its impact on
As this method is used in many places, and often wraps large portions of
--
end
save
run_callbacks :save do
if callbacks have been set but no block is given.
result of the block, +nil+ if no callbacks have been set, or +true+
If the callback chain was halted, returns +false+. Otherwise returns the
order.
the block (if given one), and then runs the after callbacks in reverse
Calls the before and around callbacks in the order they were set, yields
Runs the callbacks for the given event.
def run_callbacks(kind, type = nil) callbacks = __callbacks[kind.to_sym] if callbacks.empty? yield if block_given? else env = Filters::Environment.new(self, false, nil) next_sequence = callbacks.compile(type) # Common case: no 'around' callbacks defined if next_sequence.final? next_sequence.invoke_before(env) env.value = !env.halted && (!block_given? || yield) next_sequence.invoke_after(env) env.value else invoke_sequence = Proc.new do skipped = nil while true current = next_sequence current.invoke_before(env) if current.final? env.value = !env.halted && (!block_given? || yield) elsif current.skip?(env) (skipped ||= []) << current next_sequence = next_sequence.nested next else next_sequence = next_sequence.nested begin target, block, method, *arguments = current.expand_call_template(env, invoke_sequence) target.send(method, *arguments, &block) ensure next_sequence = current end end current.invoke_after(env) skipped.pop.invoke_after(env) while skipped&.first break env.value end end invoke_sequence.call end end end