提交 1126a85a 编写于 作者: Y Yehuda Katz

Further cleaning up new callbacks

上级 971e2438
......@@ -45,19 +45,19 @@ def _insert_callbacks(names, block)
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
def #{filter}_filter(*names, &blk)
_insert_callbacks(names, blk) do |name, options|
_set_callback(:process_action, :#{filter}, name, options)
set_callback(:process_action, :#{filter}, name, options)
end
end
def prepend_#{filter}_filter(*names, &blk)
_insert_callbacks(names, blk) do |name, options|
_set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true))
set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true))
end
end
def skip_#{filter}_filter(*names, &blk)
_insert_callbacks(names, blk) do |name, options|
_skip_callback(:process_action, :#{filter}, name, options)
skip_callback(:process_action, :#{filter}, name, options)
end
end
......
......@@ -8,7 +8,7 @@ class ControllerWithCallbacks < AbstractController::Base
end
class Callback1 < ControllerWithCallbacks
_set_callback :process_action, :before, :first
set_callback :process_action, :before, :first
def first
@text = "Hello world"
......
......@@ -91,9 +91,8 @@ class Callback
@@_callback_sequence = 0
attr_accessor :filter, :kind, :name, :options, :per_key, :klass
def initialize(filter, kind, options, klass, name)
def initialize(filter, kind, options, klass)
@kind, @klass = kind, klass
@name = name
normalize_options!(options)
......@@ -131,9 +130,8 @@ def next_id
@@_callback_sequence += 1
end
def matches?(_kind, _name, _filter)
def matches?(_kind, _filter)
@kind == _kind &&
@name == _name &&
@filter == _filter
end
......@@ -310,40 +308,35 @@ def #{method_name}
RUBY_EVAL
method_name
else
kind, name = @kind, @name
kind = @kind
@klass.send(:define_method, "#{method_name}_object") { filter }
if kind == :around
@klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
def #{method_name}(&blk)
if :#{kind} == :around && #{method_name}_object.respond_to?(:filter)
#{method_name}_object.send("filter", self, &blk)
# TODO: Deprecate this
elsif #{method_name}_object.respond_to?(:before) && #{method_name}_object.respond_to?(:after)
should_continue = #{method_name}_object.before(self)
yield if should_continue
#{method_name}_object.after(self)
else
#{method_name}_object.send("#{kind}_#{name}", self, &blk)
end
end
RUBY_EVAL
else
@klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
def #{method_name}(&blk)
if #{method_name}_object.respond_to?(:#{kind})
#{method_name}_object.#{kind}(self, &blk)
elsif #{method_name}_object.respond_to?(:filter)
#{method_name}_object.send("filter", self, &blk)
else
#{method_name}_object.send("#{kind}_#{name}", self, &blk)
end
end
RUBY_EVAL
end
_normalize_legacy_filter(kind, filter)
@klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
def #{method_name}(&blk)
#{method_name}_object.send(:#{kind}, self, &blk)
end
RUBY_EVAL
method_name
end
end
def _normalize_legacy_filter(kind, filter)
if !filter.respond_to?(kind) && filter.respond_to?(:filter)
filter.metaclass.class_eval(
"def #{kind}(context, &block) filter(context, &block) end",
__FILE__, __LINE__ - 1)
elsif filter.respond_to?(:before) && filter.respond_to?(:after) && kind == :around
def filter.around(context)
should_continue = before(context)
yield if should_continue
after(context)
end
end
end
end
# An Array with a compile method
......@@ -385,22 +378,19 @@ module ClassMethods
# The _run_save_callbacks method can optionally take a key, which
# will be used to compile an optimized callback method for each
# key. See #define_callbacks for more information.
def _define_runner(symbol, callbacks, options)
def _define_runner(symbol, callbacks)
body = callbacks.compile(nil, :terminator => send("_#{symbol}_terminator"))
body = <<-RUBY_EVAL
def _run_#{symbol}_callbacks(key = nil)
body, line = <<-RUBY_EVAL, __LINE__
def _run_#{symbol}_callbacks(key = nil, &blk)
if key
key = key.hash.to_s.gsub(/-/, '_')
name = "_run__\#{self.class.name.split("::").last}__#{symbol}__\#{key}__callbacks"
name = "_run__\#{self.class.name.hash.abs}__#{symbol}__\#{key.hash.abs}__callbacks"
if respond_to?(name)
send(name) { yield if block_given? }
else
self.class._create_and_run_keyed_callback(
self.class.name.split("::").last,
:#{symbol}, key, self) { yield if block_given? }
unless respond_to?(name)
self.class._create_keyed_callback(name, :#{symbol}, self, &blk)
end
send(name, &blk)
else
#{body}
end
......@@ -408,30 +398,22 @@ def _run_#{symbol}_callbacks(key = nil)
RUBY_EVAL
undef_method "_run_#{symbol}_callbacks" if method_defined?("_run_#{symbol}_callbacks")
class_eval body, __FILE__, __LINE__
before_name, around_name, after_name =
options.values_at(:before, :after, :around)
class_eval body, __FILE__, line
end
# This is called the first time a callback is called with a particular
# key. It creates a new callback method for the key, calculating
# which callbacks can be omitted because of per_key conditions.
def _create_and_run_keyed_callback(klass, kind, key, obj, &blk)
def _create_keyed_callback(name, kind, obj, &blk)
@_keyed_callbacks ||= {}
@_keyed_callbacks[[kind, key]] ||= begin
str = self.send("_#{kind}_callbacks").compile(key, :object => obj, :terminator => self.send("_#{kind}_terminator"))
@_keyed_callbacks[name] ||= begin
str = send("_#{kind}_callbacks").
compile(name, :object => obj, :terminator => send("_#{kind}_terminator"))
self.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
def _run__#{klass.split("::").last}__#{kind}__#{key}__callbacks
#{str}
end
RUBY_EVAL
class_eval "def #{name}() #{str} end", __FILE__, __LINE__
true
end
obj.send("_run__#{klass.split("::").last}__#{kind}__#{key}__callbacks", &blk)
end
# Define callbacks.
......@@ -473,32 +455,30 @@ def _update_callbacks(name, filters = CallbackChain.new(name), block = nil)
callbacks = send("_#{name}_callbacks")
yield callbacks, type, filters, options if block_given?
_define_runner(name, callbacks, options)
_define_runner(name, callbacks)
end
def _set_callback(name, *filters, &block)
def set_callback(name, *filters, &block)
_update_callbacks(name, filters, block) do |callbacks, type, filters, options|
filters.map! do |filter|
# overrides parent class
callbacks.delete_if do |c|
c.matches?(type, name, filter)
end
Callback.new(filter, type, options.dup, self, name)
callbacks.delete_if {|c| c.matches?(type, filter) }
Callback.new(filter, type, options.dup, self)
end
options[:prepend] ? callbacks.unshift(*filters) : callbacks.push(*filters)
end
end
def _skip_callback(name, *filters, &block)
def skip_callback(name, *filters, &block)
_update_callbacks(name, filters, block) do |callbacks, type, filters, options|
filters.each do |filter|
callbacks = send("_#{name}_callbacks=", callbacks.clone(self))
filter = callbacks.find {|c| c.matches?(type, name, filter) }
per_key = options[:per_key] || {}
filter = callbacks.find {|c| c.matches?(type, filter) }
if filter && options.any?
filter.recompile!(options, per_key)
filter.recompile!(options, options[:per_key] || {})
else
callbacks.delete(filter)
end
......@@ -520,7 +500,7 @@ def self.reset_#{symbol}_callbacks
_update_callbacks(:#{symbol})
end
self._set_callback(:#{symbol}, :before)
self.set_callback(:#{symbol}, :before)
RUBY_EVAL
end
end
......
......@@ -11,8 +11,8 @@ def initialize(action_name)
end
define_callbacks :dispatch
_set_callback :dispatch, :before, :before1, :before2, :per_key => {:if => proc {|c| c.action_name == "index" || c.action_name == "update" }}
_set_callback :dispatch, :after, :after1, :after2, :per_key => {:if => proc {|c| c.action_name == "update" || c.action_name == "delete" }}
set_callback :dispatch, :before, :before1, :before2, :per_key => {:if => proc {|c| c.action_name == "index" || c.action_name == "update" }}
set_callback :dispatch, :after, :after1, :after2, :per_key => {:if => proc {|c| c.action_name == "update" || c.action_name == "delete" }}
def before1
@log << "before1"
......@@ -39,12 +39,12 @@ def dispatch
end
class Parent < GrandParent
_skip_callback :dispatch, :before, :before2, :per_key => {:unless => proc {|c| c.action_name == "update" }}
_skip_callback :dispatch, :after, :after2, :per_key => {:unless => proc {|c| c.action_name == "delete" }}
skip_callback :dispatch, :before, :before2, :per_key => {:unless => proc {|c| c.action_name == "update" }}
skip_callback :dispatch, :after, :after2, :per_key => {:unless => proc {|c| c.action_name == "delete" }}
end
class Child < GrandParent
_skip_callback :dispatch, :before, :before2, :per_key => {:unless => proc {|c| c.action_name == "update" }}, :if => :state_open?
skip_callback :dispatch, :before, :before2, :per_key => {:unless => proc {|c| c.action_name == "update" }}, :if => :state_open?
def state_open?
@state == :open
......
......@@ -10,11 +10,11 @@ class Record
define_callbacks :save
def self.before_save(*filters, &blk)
_set_callback(:save, :before, *filters, &blk)
set_callback(:save, :before, *filters, &blk)
end
def self.after_save(*filters, &blk)
_set_callback(:save, :after, *filters, &blk)
set_callback(:save, :after, *filters, &blk)
end
class << self
......@@ -37,7 +37,7 @@ def callback_proc(callback_method)
def callback_object(callback_method)
klass = Class.new
klass.send(:define_method, callback_method) do |model|
model.history << [callback_method, :object]
model.history << [:"#{callback_method}_save", :object]
end
klass.new
end
......@@ -54,7 +54,7 @@ class Person < Record
send(callback_method, callback_symbol(callback_method_sym))
send(callback_method, callback_string(callback_method_sym))
send(callback_method, callback_proc(callback_method_sym))
send(callback_method, callback_object(callback_method_sym))
send(callback_method, callback_object(callback_method_sym.to_s.gsub(/_save/, '')))
send(callback_method) { |model| model.history << [callback_method_sym, :block] }
end
......@@ -64,10 +64,10 @@ def save
end
class PersonSkipper < Person
_skip_callback :save, :before, :before_save_method, :if => :yes
_skip_callback :save, :after, :before_save_method, :unless => :yes
_skip_callback :save, :after, :before_save_method, :if => :no
_skip_callback :save, :before, :before_save_method, :unless => :no
skip_callback :save, :before, :before_save_method, :if => :yes
skip_callback :save, :after, :before_save_method, :unless => :yes
skip_callback :save, :after, :before_save_method, :if => :no
skip_callback :save, :before, :before_save_method, :unless => :no
def yes; true; end
def no; false; end
end
......@@ -77,8 +77,8 @@ class ParentController
define_callbacks :dispatch
_set_callback :dispatch, :before, :log, :per_key => {:unless => proc {|c| c.action_name == :index || c.action_name == :show }}
_set_callback :dispatch, :after, :log2
set_callback :dispatch, :before, :log, :per_key => {:unless => proc {|c| c.action_name == :index || c.action_name == :show }}
set_callback :dispatch, :after, :log2
attr_reader :action_name, :logger
def initialize(action_name)
......@@ -102,8 +102,8 @@ def dispatch
end
class Child < ParentController
_skip_callback :dispatch, :before, :log, :per_key => {:if => proc {|c| c.action_name == :update} }
_skip_callback :dispatch, :after, :log2
skip_callback :dispatch, :before, :log, :per_key => {:if => proc {|c| c.action_name == :update} }
skip_callback :dispatch, :after, :log2
end
class OneTimeCompile < Record
......@@ -188,19 +188,19 @@ class MySuper
class AroundPerson < MySuper
attr_reader :history
_set_callback :save, :before, :nope, :if => :no
_set_callback :save, :before, :nope, :unless => :yes
_set_callback :save, :after, :tweedle
_set_callback :save, :before, "tweedle_dee"
_set_callback :save, :before, proc {|m| m.history << "yup" }
_set_callback :save, :before, :nope, :if => proc { false }
_set_callback :save, :before, :nope, :unless => proc { true }
_set_callback :save, :before, :yup, :if => proc { true }
_set_callback :save, :before, :yup, :unless => proc { false }
_set_callback :save, :around, :tweedle_dum
_set_callback :save, :around, :w0tyes, :if => :yes
_set_callback :save, :around, :w0tno, :if => :no
_set_callback :save, :around, :tweedle_deedle
set_callback :save, :before, :nope, :if => :no
set_callback :save, :before, :nope, :unless => :yes
set_callback :save, :after, :tweedle
set_callback :save, :before, "tweedle_dee"
set_callback :save, :before, proc {|m| m.history << "yup" }
set_callback :save, :before, :nope, :if => proc { false }
set_callback :save, :before, :nope, :unless => proc { true }
set_callback :save, :before, :yup, :if => proc { true }
set_callback :save, :before, :yup, :unless => proc { false }
set_callback :save, :around, :tweedle_dum
set_callback :save, :around, :w0tyes, :if => :yes
set_callback :save, :around, :w0tno, :if => :no
set_callback :save, :around, :tweedle_deedle
def no; false; end
def yes; true; end
......@@ -260,7 +260,7 @@ class HyphenatedCallbacks
define_callbacks :save
attr_reader :stuff
_set_callback :save, :before, :omg, :per_key => {:if => :yes}
set_callback :save, :before, :omg, :per_key => {:if => :yes}
def yes() true end
......@@ -354,15 +354,15 @@ class CallbackTerminator
define_callbacks :save, "result == :halt"
_set_callback :save, :before, :first
_set_callback :save, :before, :second
_set_callback :save, :around, :around_it
_set_callback :save, :before, :third
_set_callback :save, :after, :first
_set_callback :save, :around, :around_it
_set_callback :save, :after, :second
_set_callback :save, :around, :around_it
_set_callback :save, :after, :third
set_callback :save, :before, :first
set_callback :save, :before, :second
set_callback :save, :around, :around_it
set_callback :save, :before, :third
set_callback :save, :after, :first
set_callback :save, :around, :around_it
set_callback :save, :after, :second
set_callback :save, :around, :around_it
set_callback :save, :after, :third
attr_reader :history, :saved
......@@ -397,11 +397,11 @@ def save
end
class CallbackObject
def before_save(caller)
def before(caller)
caller.record << "before"
end
def around_save(caller)
def around(caller)
caller.record << "around before"
yield
caller.record << "around after"
......@@ -412,7 +412,7 @@ class UsingObjectBefore
include ActiveSupport::NewCallbacks
define_callbacks :save
_set_callback :save, :before, CallbackObject.new
set_callback :save, :before, CallbackObject.new
attr_accessor :record
def initialize
......@@ -430,7 +430,7 @@ class UsingObjectAround
include ActiveSupport::NewCallbacks
define_callbacks :save
_set_callback :save, :around, CallbackObject.new
set_callback :save, :around, CallbackObject.new
attr_accessor :record
def initialize
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册