1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

AS::Callbacks::Callback refactor

In order to make Callbacks code always operate on valid peaces of code
Concatenated Callback#start and Callback#end method into #apply
method.
This commit is contained in:
Bogdan Gusiev 2011-11-15 10:33:25 +02:00
parent c7ab43ff06
commit 3dc80b7fdf

View file

@ -158,19 +158,10 @@ module ActiveSupport
RUBY_EVAL RUBY_EVAL
end end
# This will supply contents for before and around filters, and no # Wraps code with filter
# contents for after filters (for the forward pass). def apply(code, key=nil, object=nil)
def start(key=nil, object=nil)
return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?")
# options[0] is the compiled form of supplied conditions
# options[1] is the "end" for the conditional
#
case @kind case @kind
when :before when :before
# if condition # before_save :filter_name, :if => :condition
# filter_name
# end
<<-RUBY_EVAL <<-RUBY_EVAL
if !halted && #{@compiled_options} if !halted && #{@compiled_options}
# This double assignment is to prevent warnings in 1.9.3. I would # This double assignment is to prevent warnings in 1.9.3. I would
@ -180,62 +171,64 @@ module ActiveSupport
result = result = #{@filter} result = result = #{@filter}
halted = (#{chain.config[:terminator]}) halted = (#{chain.config[:terminator]})
end end
#{code}
RUBY_EVAL RUBY_EVAL
when :around
# Compile around filters with conditions into proxy methods
# that contain the conditions.
#
# For `around_save :filter_name, :if => :condition':
#
# def _conditional_callback_save_17
# if condition
# filter_name do
# yield self
# end
# else
# yield self
# end
# end
#
name = "_conditional_callback_#{@kind}_#{next_id}"
@klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
def #{name}(halted)
if #{@compiled_options} && !halted
#{@filter} do
yield self
end
else
yield self
end
end
RUBY_EVAL
"#{name}(halted) do"
end
end
# This will supply contents for around and after filters, but not
# before filters (for the backward pass).
def end(key=nil, object=nil)
return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?")
case @kind
when :after when :after
# after_save :filter_name, :if => :condition
<<-RUBY_EVAL <<-RUBY_EVAL
#{code}
if #{@compiled_options} if #{@compiled_options}
#{@filter} #{@filter}
end end
RUBY_EVAL RUBY_EVAL
when :around when :around
name = define_conditional_callback
<<-RUBY_EVAL <<-RUBY_EVAL
#{name}(halted) do
#{code}
value value
end end
RUBY_EVAL RUBY_EVAL
end end
end end
def one_time_conditions_valid?(object)
object.send("_one_time_conditions_valid_#{@callback_id}?")
end
private private
# Compile around filters with conditions into proxy methods
# that contain the conditions.
#
# For `around_save :filter_name, :if => :condition':
#
# def _conditional_callback_save_17
# if condition
# filter_name do
# yield self
# end
# else
# yield self
# end
# end
#
def define_conditional_callback
name = "_conditional_callback_#{@kind}_#{next_id}"
@klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
def #{name}(halted)
if #{@compiled_options} && !halted
#{@filter} do
yield self
end
else
yield self
end
end
RUBY_EVAL
name
end
# Options support the same options as filters themselves (and support # Options support the same options as filters themselves (and support
# symbols, string, procs, and objects), so compile a conditional # symbols, string, procs, and objects), so compile a conditional
# expression based on the options # expression based on the options
@ -338,10 +331,20 @@ module ActiveSupport
method << "value = nil" method << "value = nil"
method << "halted = false" method << "halted = false"
each do |callback| callbacks = yielding
method << callback.start(key, object) applicable_callbacks_for(key, object).reverse_each do |callback|
callbacks = callback.apply(callbacks, key, object)
end end
method << callbacks
method << "raise rescued_error if rescued_error" if config[:rescuable]
method << "halted ? false : (block_given? ? value : true)"
method.flatten.compact.join("\n")
end
# Returns part of method that evaluates the callback block
def yielding
method = []
if config[:rescuable] if config[:rescuable]
method << "rescued_error = nil" method << "rescued_error = nil"
method << "begin" method << "begin"
@ -354,14 +357,15 @@ module ActiveSupport
method << "rescued_error = e" method << "rescued_error = e"
method << "end" method << "end"
end end
method.join("\n")
end
reverse_each do |callback| # Selects callbacks that have valid <tt>:per_key</tt> condition
method << callback.end(key, object) def applicable_callbacks_for(key, object)
return self unless key
select do |callback|
callback.one_time_conditions_valid?(object)
end end
method << "raise rescued_error if rescued_error" if config[:rescuable]
method << "halted ? false : (block_given? ? value : true)"
method.compact.join("\n")
end end
end end