aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support/callbacks.rb
diff options
context:
space:
mode:
authorPratik Naik <pratiknaik@gmail.com>2010-01-04 03:24:39 +0530
committerPratik Naik <pratiknaik@gmail.com>2010-01-04 03:24:39 +0530
commitcda36a0731f14b33a920bf7e32255661e06f890a (patch)
tree79ccba37953f9fe3055503be42b1610faa6d64ad /activesupport/lib/active_support/callbacks.rb
parentbd4a3cce4ecd8e648179a91e26506e3622ac2162 (diff)
parenta115b5d79a850bb56cd3c9db9a05d6da35e3d7be (diff)
downloadrails-cda36a0731f14b33a920bf7e32255661e06f890a.tar.gz
rails-cda36a0731f14b33a920bf7e32255661e06f890a.tar.bz2
rails-cda36a0731f14b33a920bf7e32255661e06f890a.zip
Merge remote branch 'mainstream/master'
Diffstat (limited to 'activesupport/lib/active_support/callbacks.rb')
-rw-r--r--activesupport/lib/active_support/callbacks.rb87
1 files changed, 63 insertions, 24 deletions
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index 274df12e5d..6727eda811 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -1,6 +1,7 @@
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/class/inheritable_attributes'
require 'active_support/core_ext/kernel/reporting'
+require 'active_support/core_ext/object/metaclass'
module ActiveSupport
# Callbacks are hooks into the lifecycle of an object that allow you to trigger logic
@@ -90,7 +91,7 @@ module ActiveSupport
class Callback
@@_callback_sequence = 0
- attr_accessor :chain, :filter, :kind, :options, :per_key, :klass
+ attr_accessor :chain, :filter, :kind, :options, :per_key, :klass, :raw_filter
def initialize(chain, filter, kind, options, klass)
@chain, @kind, @klass = chain, kind, klass
@@ -367,12 +368,6 @@ module ActiveSupport
method << "halted ? false : (block_given? ? value : true)"
method.compact.join("\n")
end
-
- def clone(klass)
- chain = CallbackChain.new(@name, @config.dup)
- callbacks = map { |c| c.clone(chain, klass) }
- chain.push(*callbacks)
- end
end
module ClassMethods
@@ -389,10 +384,16 @@ module ActiveSupport
# key. See #define_callbacks for more information.
#
def __define_runner(symbol) #:nodoc:
+ send("_update_#{symbol}_superclass_callbacks")
body = send("_#{symbol}_callbacks").compile(nil)
body, line = <<-RUBY_EVAL, __LINE__
def _run_#{symbol}_callbacks(key = nil, &blk)
+ if self.class.send("_update_#{symbol}_superclass_callbacks")
+ self.class.__define_runner(#{symbol.inspect})
+ return _run_#{symbol}_callbacks(key, &blk)
+ end
+
if key
name = "_run__\#{self.class.name.hash.abs}__#{symbol}__\#{key.hash.abs}__callbacks"
@@ -431,6 +432,8 @@ module ActiveSupport
# CallbackChain.
#
def __update_callbacks(name, filters = [], block = nil) #:nodoc:
+ send("_update_#{name}_superclass_callbacks")
+
type = [:before, :after, :around].include?(filters.first) ? filters.shift : :before
options = filters.last.is_a?(Hash) ? filters.pop : {}
filters.unshift(block) if block
@@ -467,10 +470,11 @@ module ActiveSupport
# method that took into consideration the per_key conditions. This
# is a speed improvement for ActionPack.
#
- def set_callback(name, *filters, &block)
- __update_callbacks(name, filters, block) do |chain, type, filters, options|
+ def set_callback(name, *filter_list, &block)
+ __update_callbacks(name, filter_list, block) do |chain, type, filters, options|
filters.map! do |filter|
- chain.delete_if {|c| c.matches?(type, filter) }
+ removed = chain.delete_if {|c| c.matches?(type, filter) }
+ send("_removed_#{name}_callbacks").push(*removed)
Callback.new(chain, filter, type, options.dup, self)
end
@@ -480,18 +484,19 @@ module ActiveSupport
# Skip a previously defined callback for a given type.
#
- def skip_callback(name, *filters, &block)
- __update_callbacks(name, filters, block) do |chain, type, filters, options|
- chain = send("_#{name}_callbacks=", chain.clone(self))
-
+ def skip_callback(name, *filter_list, &block)
+ __update_callbacks(name, filter_list, block) do |chain, type, filters, options|
filters.each do |filter|
filter = chain.find {|c| c.matches?(type, filter) }
if filter && options.any?
- filter.recompile!(options, options[:per_key] || {})
- else
- chain.delete(filter)
+ new_filter = filter.clone(chain, self)
+ chain.insert(chain.index(filter), new_filter)
+ new_filter.recompile!(options, options[:per_key] || {})
end
+
+ chain.delete(filter)
+ send("_removed_#{name}_callbacks") << filter
end
end
end
@@ -499,7 +504,9 @@ module ActiveSupport
# Reset callbacks for a given type.
#
def reset_callbacks(symbol)
- send("_#{symbol}_callbacks").clear
+ callbacks = send("_#{symbol}_callbacks")
+ callbacks.clear
+ send("_removed_#{symbol}_callbacks").concat(callbacks)
__define_runner(symbol)
end
@@ -546,14 +553,46 @@ module ActiveSupport
#
# Defaults to :kind.
#
- def define_callbacks(*symbols)
- config = symbols.last.is_a?(Hash) ? symbols.pop : {}
- symbols.each do |symbol|
- extlib_inheritable_accessor("_#{symbol}_callbacks") do
- CallbackChain.new(symbol, config)
+ def define_callbacks(*callbacks)
+ config = callbacks.last.is_a?(Hash) ? callbacks.pop : {}
+ callbacks.each do |callback|
+ extlib_inheritable_reader("_#{callback}_callbacks") do
+ CallbackChain.new(callback, config)
+ end
+
+ extlib_inheritable_reader("_removed_#{callback}_callbacks") do
+ []
end
- __define_runner(symbol)
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
+ def self._#{callback}_superclass_callbacks
+ if superclass.respond_to?(:_#{callback}_callbacks)
+ superclass._#{callback}_callbacks + superclass._#{callback}_superclass_callbacks
+ else
+ []
+ end
+ end
+
+ def self._update_#{callback}_superclass_callbacks
+ changed, index = false, 0
+
+ callbacks = (_#{callback}_superclass_callbacks -
+ _#{callback}_callbacks) - _removed_#{callback}_callbacks
+
+ callbacks.each do |callback|
+ if new_index = _#{callback}_callbacks.index(callback)
+ index = new_index + 1
+ else
+ changed = true
+ _#{callback}_callbacks.insert(index, callback)
+ index = index + 1
+ end
+ end
+ changed
+ end
+ METHOD
+
+ __define_runner(callback)
end
end
end