mirror of https://github.com/rails/rails
Add ability to run only before/around/after callbacks in run_callbacks
This commit is contained in:
parent
f9030fe0c6
commit
b985dc2b1f
|
@ -68,7 +68,7 @@ module ActiveSupport
|
|||
class_attribute :__callbacks, instance_writer: false, default: {}
|
||||
end
|
||||
|
||||
CALLBACK_FILTER_TYPES = [:before, :after, :around]
|
||||
CALLBACK_FILTER_TYPES = [:before, :after, :around].freeze
|
||||
|
||||
# Runs the callbacks for the given event.
|
||||
#
|
||||
|
@ -92,14 +92,15 @@ module ActiveSupport
|
|||
# callback can be as noisy as it likes -- but when control has passed
|
||||
# smoothly through and into the supplied block, we want as little evidence
|
||||
# as possible that we were here.
|
||||
def run_callbacks(kind)
|
||||
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
|
||||
|
||||
next_sequence = callbacks.compile(type)
|
||||
|
||||
# Common case: no 'around' callbacks defined
|
||||
if next_sequence.final?
|
||||
|
@ -612,7 +613,8 @@ module ActiveSupport
|
|||
terminator: default_terminator
|
||||
}.merge!(config)
|
||||
@chain = []
|
||||
@callbacks = nil
|
||||
@all_callbacks = nil
|
||||
@single_callbacks = {}
|
||||
@mutex = Mutex.new
|
||||
end
|
||||
|
||||
|
@ -621,32 +623,45 @@ module ActiveSupport
|
|||
def empty?; @chain.empty?; end
|
||||
|
||||
def insert(index, o)
|
||||
@callbacks = nil
|
||||
@all_callbacks = nil
|
||||
@single_callbacks.clear
|
||||
@chain.insert(index, o)
|
||||
end
|
||||
|
||||
def delete(o)
|
||||
@callbacks = nil
|
||||
@all_callbacks = nil
|
||||
@single_callbacks.clear
|
||||
@chain.delete(o)
|
||||
end
|
||||
|
||||
def clear
|
||||
@callbacks = nil
|
||||
@all_callbacks = nil
|
||||
@single_callbacks.clear
|
||||
@chain.clear
|
||||
self
|
||||
end
|
||||
|
||||
def initialize_copy(other)
|
||||
@callbacks = nil
|
||||
@all_callbacks = nil
|
||||
@single_callbacks = {}
|
||||
@chain = other.chain.dup
|
||||
@mutex = Mutex.new
|
||||
end
|
||||
|
||||
def compile
|
||||
@callbacks || @mutex.synchronize do
|
||||
final_sequence = CallbackSequence.new
|
||||
@callbacks ||= @chain.reverse.inject(final_sequence) do |callback_sequence, callback|
|
||||
callback.apply callback_sequence
|
||||
def compile(type)
|
||||
if type.nil?
|
||||
@all_callbacks || @mutex.synchronize do
|
||||
final_sequence = CallbackSequence.new
|
||||
@all_callbacks ||= @chain.reverse.inject(final_sequence) do |callback_sequence, callback|
|
||||
callback.apply(callback_sequence)
|
||||
end
|
||||
end
|
||||
else
|
||||
@single_callbacks[type] || @mutex.synchronize do
|
||||
final_sequence = CallbackSequence.new
|
||||
@single_callbacks[type] ||= @chain.reverse.inject(final_sequence) do |callback_sequence, callback|
|
||||
type == callback.kind ? callback.apply(callback_sequence) : callback_sequence
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -664,19 +679,22 @@ module ActiveSupport
|
|||
|
||||
private
|
||||
def append_one(callback)
|
||||
@callbacks = nil
|
||||
@all_callbacks = nil
|
||||
@single_callbacks.clear
|
||||
remove_duplicates(callback)
|
||||
@chain.push(callback)
|
||||
end
|
||||
|
||||
def prepend_one(callback)
|
||||
@callbacks = nil
|
||||
@all_callbacks = nil
|
||||
@single_callbacks.clear
|
||||
remove_duplicates(callback)
|
||||
@chain.unshift(callback)
|
||||
end
|
||||
|
||||
def remove_duplicates(callback)
|
||||
@callbacks = nil
|
||||
@all_callbacks = nil
|
||||
@single_callbacks.clear
|
||||
@chain.delete_if { |c| callback.duplicates?(c) }
|
||||
end
|
||||
|
||||
|
|
|
@ -1187,4 +1187,76 @@ module CallbacksTest
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
class AllSaveCallbacks
|
||||
include ActiveSupport::Callbacks
|
||||
|
||||
attr_reader :history
|
||||
define_callbacks :save
|
||||
|
||||
def initialize
|
||||
@history = []
|
||||
end
|
||||
|
||||
set_callback :save, :before, :before_save_1
|
||||
set_callback :save, :before, :before_save_2
|
||||
set_callback :save, :around, :around_save_1
|
||||
set_callback :save, :around, :around_save_2
|
||||
set_callback :save, :after, :after_save_1
|
||||
set_callback :save, :after, :after_save_2
|
||||
|
||||
def before_save_1
|
||||
@history << __method__.to_s
|
||||
end
|
||||
|
||||
def before_save_2
|
||||
@history << __method__.to_s
|
||||
end
|
||||
|
||||
def around_save_1
|
||||
@history << __method__.to_s + "_before"
|
||||
yield
|
||||
@history << __method__.to_s + "_after"
|
||||
end
|
||||
|
||||
def around_save_2
|
||||
@history << __method__.to_s + "_before"
|
||||
yield
|
||||
@history << __method__.to_s + "_after"
|
||||
end
|
||||
|
||||
def after_save_1
|
||||
@history << __method__.to_s
|
||||
end
|
||||
|
||||
def after_save_2
|
||||
@history << __method__.to_s
|
||||
end
|
||||
end
|
||||
|
||||
class RunSpecificCallbackTest < ActiveSupport::TestCase
|
||||
def test_run_callbacks_only_before
|
||||
klass = AllSaveCallbacks.new
|
||||
klass.run_callbacks :save, :before
|
||||
assert_equal ["before_save_1", "before_save_2"], klass.history
|
||||
end
|
||||
|
||||
def test_run_callbacks_only_around
|
||||
klass = AllSaveCallbacks.new
|
||||
klass.run_callbacks :save, :around
|
||||
assert_equal [
|
||||
"around_save_1_before",
|
||||
"around_save_2_before",
|
||||
"around_save_2_after",
|
||||
"around_save_1_after"
|
||||
],
|
||||
klass.history
|
||||
end
|
||||
|
||||
def test_run_callbacks_only_after
|
||||
klass = AllSaveCallbacks.new
|
||||
klass.run_callbacks :save, :after
|
||||
assert_equal ["after_save_2", "after_save_1"], klass.history
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue