From 3dc80b7fdf7f9d11c64f3de9feb78edf83a9e2a8 Mon Sep 17 00:00:00 2001 From: Bogdan Gusiev Date: Tue, 15 Nov 2011 10:33:25 +0200 Subject: [PATCH] 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. --- activesupport/lib/active_support/callbacks.rb | 120 +++++++++--------- 1 file changed, 62 insertions(+), 58 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index ea37355fc1..66767bfbb6 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -158,19 +158,10 @@ module ActiveSupport RUBY_EVAL end - # This will supply contents for before and around filters, and no - # contents for after filters (for the forward pass). - 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 - # + # Wraps code with filter + def apply(code, key=nil, object=nil) case @kind when :before - # if condition # before_save :filter_name, :if => :condition - # filter_name - # end <<-RUBY_EVAL if !halted && #{@compiled_options} # This double assignment is to prevent warnings in 1.9.3. I would @@ -180,62 +171,64 @@ module ActiveSupport result = result = #{@filter} halted = (#{chain.config[:terminator]}) end + #{code} 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 - # after_save :filter_name, :if => :condition <<-RUBY_EVAL + #{code} if #{@compiled_options} #{@filter} end RUBY_EVAL when :around + name = define_conditional_callback <<-RUBY_EVAL + #{name}(halted) do + #{code} value end RUBY_EVAL end end + + def one_time_conditions_valid?(object) + object.send("_one_time_conditions_valid_#{@callback_id}?") + end + 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 # symbols, string, procs, and objects), so compile a conditional # expression based on the options @@ -338,10 +331,20 @@ module ActiveSupport method << "value = nil" method << "halted = false" - each do |callback| - method << callback.start(key, object) + callbacks = yielding + applicable_callbacks_for(key, object).reverse_each do |callback| + callbacks = callback.apply(callbacks, key, object) 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] method << "rescued_error = nil" method << "begin" @@ -354,14 +357,15 @@ module ActiveSupport method << "rescued_error = e" method << "end" end + method.join("\n") + end - reverse_each do |callback| - method << callback.end(key, object) + # Selects callbacks that have valid :per_key condition + def applicable_callbacks_for(key, object) + return self unless key + select do |callback| + callback.one_time_conditions_valid?(object) end - - method << "raise rescued_error if rescued_error" if config[:rescuable] - method << "halted ? false : (block_given? ? value : true)" - method.compact.join("\n") end end