diff options
Diffstat (limited to 'activesupport/lib/active_support/callbacks.rb')
-rw-r--r-- | activesupport/lib/active_support/callbacks.rb | 45 |
1 files changed, 39 insertions, 6 deletions
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 3a8353857e..e3e1845868 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -1,3 +1,4 @@ +require 'thread_safe' require 'active_support/concern' require 'active_support/descendants_tracker' require 'active_support/core_ext/class/attribute' @@ -133,6 +134,10 @@ module ActiveSupport @kind == _kind && @filter == _filter end + def duplicates?(other) + matches?(other.kind, other.filter) + end + def _update_filter(filter_options, new_options) filter_options[:if].concat(Array(new_options[:unless])) if new_options.key?(:unless) filter_options[:unless].concat(Array(new_options[:if])) if new_options.key?(:if) @@ -327,6 +332,30 @@ module ActiveSupport method.join("\n") end + def append(*callbacks) + callbacks.each { |c| append_one(c) } + end + + def prepend(*callbacks) + callbacks.each { |c| prepend_one(c) } + end + + private + + def append_one(callback) + remove_duplicates(callback) + push(callback) + end + + def prepend_one(callback) + remove_duplicates(callback) + unshift(callback) + end + + def remove_duplicates(callback) + delete_if { |c| callback.duplicates?(c) } + end + end module ClassMethods @@ -351,10 +380,18 @@ module ActiveSupport undef_method(name) if method_defined?(name) end - def __callback_runner_name(kind) + def __callback_runner_name_cache + @__callback_runner_name_cache ||= ThreadSafe::Cache.new {|cache, kind| cache[kind] = __generate_callback_runner_name(kind) } + end + + def __generate_callback_runner_name(kind) "_run__#{self.name.hash.abs}__#{kind}__callbacks" end + def __callback_runner_name(kind) + __callback_runner_name_cache[kind] + end + # This is used internally to append, prepend and skip callbacks to the # CallbackChain. def __update_callbacks(name, filters = [], block = nil) #:nodoc: @@ -412,11 +449,7 @@ module ActiveSupport Callback.new(chain, filter, type, options.dup, self) end - filters.each do |filter| - chain.delete_if {|c| c.matches?(type, filter) } - end - - options[:prepend] ? chain.unshift(*(mapped.reverse)) : chain.push(*mapped) + options[:prepend] ? chain.prepend(*mapped) : chain.append(*mapped) target.send("_#{name}_callbacks=", chain) end |