From 6189e2714b730d4ae0da11884b8082cbee0fb44c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 8 May 2013 14:23:10 -0700 Subject: conditions in callbacks return consistent lambdas --- activesupport/lib/active_support/callbacks.rb | 52 ++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 6fe7e0f4fb..d998747162 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -183,7 +183,7 @@ module ActiveSupport case @kind when :before <<-RUBY_EVAL - if !halted && #{@compiled_options} + if !halted && #{@compiled_options}(value) # This double assignment is to prevent warnings in 1.9.3 as # the `result` variable is not always used except if the # terminator code refers to it. @@ -198,14 +198,14 @@ module ActiveSupport when :after <<-RUBY_EVAL #{code} - if #{!chain.config[:skip_after_callbacks_if_terminated] || "!halted"} && #{@compiled_options} + if #{!chain.config[:skip_after_callbacks_if_terminated] || "!halted"} && #{@compiled_options}(value) #{@source} end RUBY_EVAL when :around name = define_conditional_callback <<-RUBY_EVAL - #{name}(halted) do + #{name}(halted, value) do #{code} value end @@ -241,8 +241,8 @@ module ActiveSupport 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 + def #{name}(halted, value) + if #{@compiled_options}(value) && !halted #{@source} do yield self end @@ -258,17 +258,24 @@ module ActiveSupport # symbols, string, procs, and objects), so compile a conditional # expression based on the options. def recompile_options! - conditions = ["true"] + conditions = [] unless options[:if].empty? - conditions << Array(_compile_source(options[:if])) + conditions.concat Array(_compile_options(options[:if])) end unless options[:unless].empty? - conditions << Array(_compile_source(options[:unless])).map {|f| "!#{f}"} + conditions.concat Array(_compile_options(options[:unless])).map { |f| + lambda { |*args,&blk| !f.call(*args, &blk) } + } end - @compiled_options = conditions.flatten.join(" && ") + method_name = "_callback_#{@kind}_#{next_id}" + @klass.send(:define_method, method_name) do |*args,&block| + conditions.all? { |c| c.call(self, *args, &block) } + end + + @compiled_options = method_name end def _method_name_for_object_filter(kind, filter, append_next_id = true) @@ -333,6 +340,33 @@ module ActiveSupport end end + def _compile_options(filter) + case filter + when Array + filter.map {|f| _compile_options(f)} + when Symbol + lambda { |target, value| target.send filter } + when String + l = eval "lambda { |value| #{filter} }" + lambda { |target,value| target.instance_exec(value, &l) } + when ::Proc + method_name = "_callback_#{@kind}_#{next_id}" + @klass.send(:define_method, method_name, &filter) + + if filter.arity <= 0 + return lambda { |target, _| target.instance_exec(&filter) } + end + + if filter.arity == 1 + lambda { |target, _| target.send method_name, target } + else + lambda { |target, _,&blk| target.send method_name, target, &blk } + end + else + raise + end + end + def _normalize_legacy_filter(kind, filter) if !filter.respond_to?(kind) && filter.respond_to?(:filter) message = "Filter object with #filter method is deprecated. Define method corresponding " \ -- cgit v1.2.3 From 2b1500d69597ecd0ff914dea1fbc265669abdbee Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 8 May 2013 17:11:12 -0700 Subject: wrap all options in lambas --- activesupport/lib/active_support/callbacks.rb | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index d998747162..0c550cced5 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -345,25 +345,31 @@ module ActiveSupport when Array filter.map {|f| _compile_options(f)} when Symbol - lambda { |target, value| target.send filter } + lambda { |target, value| target.public_send filter } when String l = eval "lambda { |value| #{filter} }" lambda { |target,value| target.instance_exec(value, &l) } when ::Proc - method_name = "_callback_#{@kind}_#{next_id}" - @klass.send(:define_method, method_name, &filter) - if filter.arity <= 0 return lambda { |target, _| target.instance_exec(&filter) } end if filter.arity == 1 - lambda { |target, _| target.send method_name, target } + lambda { |target, _| + target.instance_exec(target, &filter) + } else - lambda { |target, _,&blk| target.send method_name, target, &blk } + lambda { |target, _| + target.instance_exec target, ::Proc.new, &filter + } end else - raise + scopes = Array(chain.config[:scope]) + method_to_call = scopes.map{ |s| public_send(s) }.join("_") + + lambda { |target, _, &blk| + filter.public_send method_to_call, target, &blk + } end end -- cgit v1.2.3 From 07da9603feb445431e2d2707ca5b1798c7f86e3f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 8 May 2013 17:51:08 -0700 Subject: using lambas for the callback bodies --- activesupport/lib/active_support/callbacks.rb | 44 ++++++++------------------- 1 file changed, 12 insertions(+), 32 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 0c550cced5..abbb5956d0 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -187,7 +187,7 @@ module ActiveSupport # This double assignment is to prevent warnings in 1.9.3 as # the `result` variable is not always used except if the # terminator code refers to it. - result = result = #{@source} + result = result = #{@source}(value) halted = (#{chain.config[:terminator]}) if halted halted_callback_hook(#{@raw_filter.inspect.inspect}) @@ -199,7 +199,7 @@ module ActiveSupport <<-RUBY_EVAL #{code} if #{!chain.config[:skip_after_callbacks_if_terminated] || "!halted"} && #{@compiled_options}(value) - #{@source} + #{@source}(value) end RUBY_EVAL when :around @@ -243,7 +243,7 @@ module ActiveSupport @klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def #{name}(halted, value) if #{@compiled_options}(value) && !halted - #{@source} do + #{@source}(value) do yield self end else @@ -309,35 +309,13 @@ module ActiveSupport # a method is created that calls the before_foo method # on the object. def _compile_source(filter) - case filter - when Array - filter.map {|f| _compile_source(f)} - when Symbol - filter - when String - "(#{filter})" - when ::Proc - method_name = "_callback_#{@kind}_#{next_id}" - @klass.send(:define_method, method_name, &filter) - return method_name if filter.arity <= 0 - - method_name << (filter.arity == 1 ? "(self)" : "(self, ::Proc.new)") - else - method_name = _method_name_for_object_filter(kind, filter) - @klass.send(:define_method, "#{method_name}_object") { filter } - - _normalize_legacy_filter(kind, filter) - scopes = Array(chain.config[:scope]) - method_to_call = scopes.map{ |s| public_send(s) }.join("_") - - @klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 - def #{method_name}(&blk) - #{method_name}_object.send(:#{method_to_call}, self, &blk) - end - RUBY_EVAL + l = _compile_options filter - method_name + method_name = "_callback_#{@kind}_#{next_id}" + @klass.send(:define_method, method_name) do |*args,&block| + l.call(self, *args, &block) end + method_name end def _compile_options(filter) @@ -345,9 +323,11 @@ module ActiveSupport when Array filter.map {|f| _compile_options(f)} when Symbol - lambda { |target, value| target.public_send filter } + lambda { |target, value, &blk| + target.send filter, &blk + } when String - l = eval "lambda { |value| #{filter} }" + l = eval "lambda { |value| #{filter} }", __FILE__, __LINE__ lambda { |target,value| target.instance_exec(value, &l) } when ::Proc if filter.arity <= 0 -- cgit v1.2.3 From bf6429c438bcc74e5b1248c4293bcf6bbbce228e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 8 May 2013 17:57:06 -0700 Subject: fix method names --- activesupport/lib/active_support/callbacks.rb | 84 ++++++++++++++------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index abbb5956d0..192e0b2597 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -215,6 +215,45 @@ module ActiveSupport private + def invert_lambda(l) + lambda { |*args, &blk| !l.call(*args, &blk) } + end + + def make_lambda(filter) + case filter + when Array + filter.map {|f| _compile_options(f)} + when Symbol + lambda { |target, value, &blk| + target.send filter, &blk + } + when String + l = eval "lambda { |value| #{filter} }" + lambda { |target,value| target.instance_exec(value, &l) } + when ::Proc + if filter.arity <= 0 + return lambda { |target, _| target.instance_exec(&filter) } + end + + if filter.arity == 1 + lambda { |target, _| + target.instance_exec(target, &filter) + } + else + lambda { |target, _| + target.instance_exec target, ::Proc.new, &filter + } + end + else + scopes = Array(chain.config[:scope]) + method_to_call = scopes.map{ |s| public_send(s) }.join("_") + + lambda { |target, _, &blk| + filter.public_send method_to_call, target, &blk + } + end + end + def compute_identifier(filter) case filter when String, ::Proc @@ -261,13 +300,13 @@ module ActiveSupport conditions = [] unless options[:if].empty? - conditions.concat Array(_compile_options(options[:if])) + lambdas = Array(options[:if]).map { |c| make_lambda c } + conditions.concat lambdas end unless options[:unless].empty? - conditions.concat Array(_compile_options(options[:unless])).map { |f| - lambda { |*args,&blk| !f.call(*args, &blk) } - } + lambdas = Array(options[:unless]).map { |c| make_lambda c } + conditions.concat lambdas.map { |l| invert_lambda l } end method_name = "_callback_#{@kind}_#{next_id}" @@ -309,7 +348,7 @@ module ActiveSupport # a method is created that calls the before_foo method # on the object. def _compile_source(filter) - l = _compile_options filter + l = make_lambda filter method_name = "_callback_#{@kind}_#{next_id}" @klass.send(:define_method, method_name) do |*args,&block| @@ -318,41 +357,6 @@ module ActiveSupport method_name end - def _compile_options(filter) - case filter - when Array - filter.map {|f| _compile_options(f)} - when Symbol - lambda { |target, value, &blk| - target.send filter, &blk - } - when String - l = eval "lambda { |value| #{filter} }", __FILE__, __LINE__ - lambda { |target,value| target.instance_exec(value, &l) } - when ::Proc - if filter.arity <= 0 - return lambda { |target, _| target.instance_exec(&filter) } - end - - if filter.arity == 1 - lambda { |target, _| - target.instance_exec(target, &filter) - } - else - lambda { |target, _| - target.instance_exec target, ::Proc.new, &filter - } - end - else - scopes = Array(chain.config[:scope]) - method_to_call = scopes.map{ |s| public_send(s) }.join("_") - - lambda { |target, _, &blk| - filter.public_send method_to_call, target, &blk - } - end - end - def _normalize_legacy_filter(kind, filter) if !filter.respond_to?(kind) && filter.respond_to?(:filter) message = "Filter object with #filter method is deprecated. Define method corresponding " \ -- cgit v1.2.3 From cc0fd31f9e8b62ec650766f02a0c8ec5f0b37a10 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 8 May 2013 17:58:02 -0700 Subject: remove dead code --- activesupport/lib/active_support/callbacks.rb | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 192e0b2597..3f4973a35f 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -317,16 +317,6 @@ module ActiveSupport @compiled_options = method_name end - def _method_name_for_object_filter(kind, filter, append_next_id = true) - class_name = filter.kind_of?(Class) ? filter.to_s : filter.class.to_s - class_name.gsub!(/<|>|#/, '') - class_name.gsub!(/\/|:/, "_") - - method_name = "_callback_#{kind}_#{class_name}" - method_name << "_#{next_id}" if append_next_id - method_name - end - # Filters support: # # Arrays:: Used in conditions. This is used to specify -- cgit v1.2.3 From 23122ab2d4e239d35a154d5ec28c2afefdd012de Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 May 2013 11:58:55 -0700 Subject: callbacks are wrapped with lambdas --- activemodel/test/cases/validations_test.rb | 2 +- activerecord/test/cases/callbacks_test.rb | 2 +- activesupport/lib/active_support/callbacks.rb | 182 +++++++++++--------------- 3 files changed, 78 insertions(+), 108 deletions(-) diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb index 3241a03b53..3e84297cc2 100644 --- a/activemodel/test/cases/validations_test.rb +++ b/activemodel/test/cases/validations_test.rb @@ -166,7 +166,7 @@ class ValidationsTest < ActiveModel::TestCase def test_invalid_validator Topic.validate :i_dont_exist - assert_raise(NameError) do + assert_raises(NoMethodError) do t = Topic.new t.valid? end diff --git a/activerecord/test/cases/callbacks_test.rb b/activerecord/test/cases/callbacks_test.rb index 187cad9599..c8f56e3c73 100644 --- a/activerecord/test/cases/callbacks_test.rb +++ b/activerecord/test/cases/callbacks_test.rb @@ -43,7 +43,7 @@ class CallbackDeveloper < ActiveRecord::Base end class CallbackDeveloperWithFalseValidation < CallbackDeveloper - before_validation proc { |model| model.history << [:before_validation, :returning_false]; return false } + before_validation proc { |model| model.history << [:before_validation, :returning_false]; false } before_validation proc { |model| model.history << [:before_validation, :should_never_get_here] } end diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 3f4973a35f..05204d34e4 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -119,8 +119,6 @@ module ActiveSupport @raw_filter, @options = filter, options @key = compute_identifier filter - @source = _compile_source(filter) - recompile_options! end def filter @@ -174,42 +172,57 @@ module ActiveSupport def recompile!(_options) deprecate_per_key_option(_options) _update_filter(self.options, _options) - - recompile_options! end # Wraps code with filter def apply(code) + conditions = conditions_lambdas + source = make_lambda @raw_filter + case @kind when :before - <<-RUBY_EVAL - if !halted && #{@compiled_options}(value) - # This double assignment is to prevent warnings in 1.9.3 as - # the `result` variable is not always used except if the - # terminator code refers to it. - result = result = #{@source}(value) - halted = (#{chain.config[:terminator]}) + halted_lambda = eval "lambda { |result| #{chain.config[:terminator]} }" + lambda { |target, halted, value, &block| + if !halted && conditions.all? { |c| c.call(target, value) } + result = source.call target, value + halted = halted_lambda.call result if halted - halted_callback_hook(#{@raw_filter.inspect.inspect}) + target.send :halted_callback_hook, @raw_filter.inspect end end - #{code} - RUBY_EVAL + code.call target, halted, value, &block + } when :after - <<-RUBY_EVAL - #{code} - if #{!chain.config[:skip_after_callbacks_if_terminated] || "!halted"} && #{@compiled_options}(value) - #{@source}(value) + if chain.config[:skip_after_callbacks_if_terminated] + lambda { |target, halted, value, &block| + target, halted, value = code.call target, halted, value, &block + if !halted && conditions.all? { |c| c.call(target, value) } + source.call target, value + end + [target, halted, value] + } + else + lambda { |target, halted, value, &block| + target, halted, value = code.call target, halted, value, &block + if conditions.all? { |c| c.call(target, value) } + source.call target, value + end + [target, halted, value] + } end - RUBY_EVAL when :around - name = define_conditional_callback - <<-RUBY_EVAL - #{name}(halted, value) do - #{code} - value - end - RUBY_EVAL + lambda { |target, halted, value, &block| + if !halted && conditions.all? { |c| c.call(target, value) } + retval = nil + source.call(target, value) { + retval = code.call(target, halted, value, &block) + retval.last + } + retval + else + code.call target, halted, value, &block + end + } end end @@ -219,6 +232,26 @@ module ActiveSupport lambda { |*args, &blk| !l.call(*args, &blk) } end + # Filters support: + # + # Arrays:: Used in conditions. This is used to specify + # multiple conditions. Used internally to + # merge conditions from skip_* filters. + # Symbols:: A method to call. + # Strings:: Some content to evaluate. + # Procs:: A proc to call with the object. + # Objects:: An object with a before_foo method on it to call. + # + # All of these objects are compiled into methods and handled + # the same after this point: + # + # Arrays:: Merged together into a single filter. + # Symbols:: Already methods. + # Strings:: class_eval'ed into methods. + # Procs:: define_method'ed into methods. + # Objects:: + # a method is created that calls the before_foo method + # on the object. def make_lambda(filter) case filter when Array @@ -263,40 +296,7 @@ module ActiveSupport end end - # Compile around filters with conditions into proxy methods - # that contain the conditions. - # - # For `set_callback :save, :around, :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, value) - if #{@compiled_options}(value) && !halted - #{@source}(value) 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. - def recompile_options! + def conditions_lambdas conditions = [] unless options[:if].empty? @@ -308,43 +308,7 @@ module ActiveSupport lambdas = Array(options[:unless]).map { |c| make_lambda c } conditions.concat lambdas.map { |l| invert_lambda l } end - - method_name = "_callback_#{@kind}_#{next_id}" - @klass.send(:define_method, method_name) do |*args,&block| - conditions.all? { |c| c.call(self, *args, &block) } - end - - @compiled_options = method_name - end - - # Filters support: - # - # Arrays:: Used in conditions. This is used to specify - # multiple conditions. Used internally to - # merge conditions from skip_* filters. - # Symbols:: A method to call. - # Strings:: Some content to evaluate. - # Procs:: A proc to call with the object. - # Objects:: An object with a before_foo method on it to call. - # - # All of these objects are compiled into methods and handled - # the same after this point: - # - # Arrays:: Merged together into a single filter. - # Symbols:: Already methods. - # Strings:: class_eval'ed into methods. - # Procs:: define_method'ed into methods. - # Objects:: - # a method is created that calls the before_foo method - # on the object. - def _compile_source(filter) - l = make_lambda filter - - method_name = "_callback_#{@kind}_#{next_id}" - @klass.send(:define_method, method_name) do |*args,&block| - l.call(self, *args, &block) - end - method_name + conditions end def _normalize_legacy_filter(kind, filter) @@ -380,15 +344,19 @@ module ActiveSupport end def compile - method = ["value = nil", "halted = false"] - callbacks = "value = !halted && (!block_given? || yield)" + callbacks = lambda { |target,halted,value,&block| + value = !halted && (!block || block.call) + [target, halted, value] + } reverse_each do |callback| callbacks = callback.apply(callbacks) end - method << callbacks - method << "value" - method.join("\n") + lambda { |target, &block| + value = nil + halted = false + callbacks.call(target, halted, value, &block)[2] + } end def append(*callbacks) @@ -426,10 +394,12 @@ module ActiveSupport name = __callback_runner_name(kind) unless object.respond_to?(name, true) str = object.send("_#{kind}_callbacks").compile - class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 - def #{name}() #{str} end - protected :#{name} - RUBY_EVAL + class_eval do + define_method(name) do |&block| + str.call self, &block + end + protected name + end end name end -- cgit v1.2.3 From f5478d9263e9aa036a09199be7a5fe0644e02031 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 May 2013 11:59:39 -0700 Subject: make_lambda is never called with an Array --- activesupport/lib/active_support/callbacks.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 05204d34e4..d869770489 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -254,8 +254,6 @@ module ActiveSupport # on the object. def make_lambda(filter) case filter - when Array - filter.map {|f| _compile_options(f)} when Symbol lambda { |target, value, &blk| target.send filter, &blk -- cgit v1.2.3 From 6514ee9044f94a3e4dae01297103bbd354acc221 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 May 2013 12:06:47 -0700 Subject: no need for variable assignments, just pass the values in --- activesupport/lib/active_support/callbacks.rb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index d869770489..ca6937eeb3 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -255,9 +255,7 @@ module ActiveSupport def make_lambda(filter) case filter when Symbol - lambda { |target, value, &blk| - target.send filter, &blk - } + lambda { |target, value, &blk| target.send filter, &blk } when String l = eval "lambda { |value| #{filter} }" lambda { |target,value| target.instance_exec(value, &l) } @@ -351,9 +349,7 @@ module ActiveSupport end lambda { |target, &block| - value = nil - halted = false - callbacks.call(target, halted, value, &block)[2] + callbacks.call(target, false, nil, &block)[2] } end -- cgit v1.2.3 From a50088a4cc4c0575c7fffdf10e0fc3a773485f03 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 May 2013 13:39:17 -0700 Subject: callback sequence is no longer used --- activesupport/lib/active_support/callbacks.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index ca6937eeb3..4ee8cf2457 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -89,8 +89,6 @@ module ActiveSupport end class Callback #:nodoc:# - @@_callback_sequence = 0 - class Basic < Callback end @@ -150,10 +148,6 @@ module ActiveSupport chain.name end - def next_id - @@_callback_sequence += 1 - end - def matches?(_kind, _filter) @kind == _kind && filter == _filter end -- cgit v1.2.3 From d5fdc0d4480f3558de9d260be26d4c7782ebc781 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 May 2013 14:40:01 -0700 Subject: reduce the number of lambas --- activesupport/lib/active_support/callbacks.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 4ee8cf2457..027b5becf1 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -341,10 +341,7 @@ module ActiveSupport reverse_each do |callback| callbacks = callback.apply(callbacks) end - - lambda { |target, &block| - callbacks.call(target, false, nil, &block)[2] - } + callbacks end def append(*callbacks) @@ -384,7 +381,7 @@ module ActiveSupport str = object.send("_#{kind}_callbacks").compile class_eval do define_method(name) do |&block| - str.call self, &block + str.call(self, false, nil, &block)[2] end protected name end -- cgit v1.2.3 From 2b1d7ea335afa46fa167a680492cdf5461c46064 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 May 2013 14:47:17 -0700 Subject: fix variable name --- activesupport/lib/active_support/callbacks.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 027b5becf1..328db8c890 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -169,7 +169,7 @@ module ActiveSupport end # Wraps code with filter - def apply(code) + def apply(next_callback) conditions = conditions_lambdas source = make_lambda @raw_filter @@ -184,12 +184,12 @@ module ActiveSupport target.send :halted_callback_hook, @raw_filter.inspect end end - code.call target, halted, value, &block + next_callback.call target, halted, value, &block } when :after if chain.config[:skip_after_callbacks_if_terminated] lambda { |target, halted, value, &block| - target, halted, value = code.call target, halted, value, &block + target, halted, value = next_callback.call target, halted, value, &block if !halted && conditions.all? { |c| c.call(target, value) } source.call target, value end @@ -197,7 +197,7 @@ module ActiveSupport } else lambda { |target, halted, value, &block| - target, halted, value = code.call target, halted, value, &block + target, halted, value = next_callback.call target, halted, value, &block if conditions.all? { |c| c.call(target, value) } source.call target, value end @@ -209,12 +209,12 @@ module ActiveSupport if !halted && conditions.all? { |c| c.call(target, value) } retval = nil source.call(target, value) { - retval = code.call(target, halted, value, &block) + retval = next_callback.call(target, halted, value, &block) retval.last } retval else - code.call target, halted, value, &block + next_callback.call target, halted, value, &block end } end -- cgit v1.2.3 From 9b5202692065ea3ed116a0098a0312a9236e9983 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 May 2013 14:55:15 -0700 Subject: fixing more variable names --- activesupport/lib/active_support/callbacks.rb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 328db8c890..850e307857 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -170,15 +170,15 @@ module ActiveSupport # Wraps code with filter def apply(next_callback) - conditions = conditions_lambdas - source = make_lambda @raw_filter + user_conditions = conditions_lambdas + user_callback = make_lambda @raw_filter case @kind when :before halted_lambda = eval "lambda { |result| #{chain.config[:terminator]} }" lambda { |target, halted, value, &block| - if !halted && conditions.all? { |c| c.call(target, value) } - result = source.call target, value + if !halted && user_conditions.all? { |c| c.call(target, value) } + result = user_callback.call target, value halted = halted_lambda.call result if halted target.send :halted_callback_hook, @raw_filter.inspect @@ -190,25 +190,25 @@ module ActiveSupport if chain.config[:skip_after_callbacks_if_terminated] lambda { |target, halted, value, &block| target, halted, value = next_callback.call target, halted, value, &block - if !halted && conditions.all? { |c| c.call(target, value) } - source.call target, value + if !halted && user_conditions.all? { |c| c.call(target, value) } + user_callback.call target, value end [target, halted, value] } else lambda { |target, halted, value, &block| target, halted, value = next_callback.call target, halted, value, &block - if conditions.all? { |c| c.call(target, value) } - source.call target, value + if user_conditions.all? { |c| c.call(target, value) } + user_callback.call target, value end [target, halted, value] } end when :around lambda { |target, halted, value, &block| - if !halted && conditions.all? { |c| c.call(target, value) } + if !halted && user_conditions.all? { |c| c.call(target, value) } retval = nil - source.call(target, value) { + user_callback.call(target, value) { retval = next_callback.call(target, halted, value, &block) retval.last } -- cgit v1.2.3 From d4dcd6e41f4a7c202270e7d510434351ce333ebc Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 May 2013 15:04:51 -0700 Subject: pass the run block as a normal variable to the rest of the callbacks --- activesupport/lib/active_support/callbacks.rb | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 850e307857..511162f20f 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -176,7 +176,7 @@ module ActiveSupport case @kind when :before halted_lambda = eval "lambda { |result| #{chain.config[:terminator]} }" - lambda { |target, halted, value, &block| + lambda { |target, halted, value, run_block| if !halted && user_conditions.all? { |c| c.call(target, value) } result = user_callback.call target, value halted = halted_lambda.call result @@ -184,20 +184,20 @@ module ActiveSupport target.send :halted_callback_hook, @raw_filter.inspect end end - next_callback.call target, halted, value, &block + next_callback.call target, halted, value, run_block } when :after if chain.config[:skip_after_callbacks_if_terminated] - lambda { |target, halted, value, &block| - target, halted, value = next_callback.call target, halted, value, &block + lambda { |target, halted, value, run_block| + target, halted, value = next_callback.call target, halted, value, run_block if !halted && user_conditions.all? { |c| c.call(target, value) } user_callback.call target, value end [target, halted, value] } else - lambda { |target, halted, value, &block| - target, halted, value = next_callback.call target, halted, value, &block + lambda { |target, halted, value, run_block| + target, halted, value = next_callback.call target, halted, value, run_block if user_conditions.all? { |c| c.call(target, value) } user_callback.call target, value end @@ -205,16 +205,16 @@ module ActiveSupport } end when :around - lambda { |target, halted, value, &block| + lambda { |target, halted, value, run_block| if !halted && user_conditions.all? { |c| c.call(target, value) } retval = nil user_callback.call(target, value) { - retval = next_callback.call(target, halted, value, &block) + retval = next_callback.call(target, halted, value, run_block) retval.last } retval else - next_callback.call target, halted, value, &block + next_callback.call target, halted, value, run_block end } end @@ -334,8 +334,8 @@ module ActiveSupport end def compile - callbacks = lambda { |target,halted,value,&block| - value = !halted && (!block || block.call) + callbacks = lambda { |target, halted, value, run_block| + value = run_block.call if run_block && !halted [target, halted, value] } reverse_each do |callback| @@ -381,7 +381,7 @@ module ActiveSupport str = object.send("_#{kind}_callbacks").compile class_eval do define_method(name) do |&block| - str.call(self, false, nil, &block)[2] + str.call(self, false, nil, block)[2] end protected name end -- cgit v1.2.3 From 95e7e56efcad98b6b89e407ced78512ea16268e6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 May 2013 15:12:31 -0700 Subject: object based callbacks cannot be duplicated --- activesupport/lib/active_support/callbacks.rb | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 511162f20f..2ea41ab2f2 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -89,10 +89,7 @@ module ActiveSupport end class Callback #:nodoc:# - class Basic < Callback - end - - class Object < Callback + class Unduplicable < Callback # :nodoc: def duplicates?(other) false end @@ -100,10 +97,10 @@ module ActiveSupport def self.build(chain, filter, kind, options, _klass) klass = case filter - when Array, Symbol, String - Callback::Basic + when Symbol, String + Callback else - Callback::Object + Callback::Unduplicable end klass.new chain, filter, kind, options, _klass end -- cgit v1.2.3 From 355169012011d9ef565ed75ce8b734346fe8c00c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 May 2013 15:22:27 -0700 Subject: use an environment object to hold state about the filter calls --- activesupport/lib/active_support/callbacks.rb | 62 ++++++++++++++++++--------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 2ea41ab2f2..141c246396 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -88,6 +88,10 @@ module ActiveSupport def halted_callback_hook(filter) end + module Filters + Environment = Struct.new(:target, :halted, :value, :run_block) + end + class Callback #:nodoc:# class Unduplicable < Callback # :nodoc: def duplicates?(other) @@ -173,45 +177,60 @@ module ActiveSupport case @kind when :before halted_lambda = eval "lambda { |result| #{chain.config[:terminator]} }" - lambda { |target, halted, value, run_block| + lambda { |env| + target = env.target + value = env.value + halted = env.halted + if !halted && user_conditions.all? { |c| c.call(target, value) } result = user_callback.call target, value - halted = halted_lambda.call result - if halted + env.halted = halted_lambda.call result + if env.halted target.send :halted_callback_hook, @raw_filter.inspect end end - next_callback.call target, halted, value, run_block + next_callback.call env } when :after if chain.config[:skip_after_callbacks_if_terminated] - lambda { |target, halted, value, run_block| - target, halted, value = next_callback.call target, halted, value, run_block + lambda { |env| + env = next_callback.call env + target = env.target + value = env.value + halted = env.halted + if !halted && user_conditions.all? { |c| c.call(target, value) } user_callback.call target, value end - [target, halted, value] + env } else - lambda { |target, halted, value, run_block| - target, halted, value = next_callback.call target, halted, value, run_block + lambda { |env| + env = next_callback.call env + target = env.target + value = env.value + halted = env.halted + if user_conditions.all? { |c| c.call(target, value) } user_callback.call target, value end - [target, halted, value] + env } end when :around - lambda { |target, halted, value, run_block| + lambda { |env| + target = env.target + value = env.value + halted = env.halted + if !halted && user_conditions.all? { |c| c.call(target, value) } - retval = nil user_callback.call(target, value) { - retval = next_callback.call(target, halted, value, run_block) - retval.last + env = next_callback.call env + env.value } - retval + env else - next_callback.call target, halted, value, run_block + next_callback.call env end } end @@ -331,9 +350,9 @@ module ActiveSupport end def compile - callbacks = lambda { |target, halted, value, run_block| - value = run_block.call if run_block && !halted - [target, halted, value] + callbacks = lambda { |env| + env.value = env.run_block.call if env.run_block && !env.halted + env } reverse_each do |callback| callbacks = callback.apply(callbacks) @@ -375,10 +394,11 @@ module ActiveSupport def __define_callbacks(kind, object) #:nodoc: name = __callback_runner_name(kind) unless object.respond_to?(name, true) - str = object.send("_#{kind}_callbacks").compile + filter_chain = object.send("_#{kind}_callbacks").compile class_eval do define_method(name) do |&block| - str.call(self, false, nil, block)[2] + e = Filters::Environment.new(self, false, nil, block) + filter_chain.call(e).value end protected name end -- cgit v1.2.3 From 5bc4740dec7ec9846915f7af459056d486b9c89d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 May 2013 10:53:46 -0700 Subject: fixing activemodel tests --- activesupport/lib/active_support/callbacks.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 141c246396..7c71524ffe 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -351,7 +351,8 @@ module ActiveSupport def compile callbacks = lambda { |env| - env.value = env.run_block.call if env.run_block && !env.halted + block = env.run_block + env.value = !env.halted && (!block || block.call) env } reverse_each do |callback| -- cgit v1.2.3 From 3aee9126aa6309538ee64064dcabcd34d7cc7d26 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 May 2013 10:56:09 -0700 Subject: use delegation over inheritance so we can figure when to cache / bust cache --- activesupport/lib/active_support/callbacks.rb | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 7c71524ffe..13dccf328c 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -338,7 +338,9 @@ module ActiveSupport end # An Array with a compile method. - class CallbackChain < Array #:nodoc:# + class CallbackChain #:nodoc:# + include Enumerable + attr_reader :name, :config def initialize(name, config) @@ -347,6 +349,18 @@ module ActiveSupport :terminator => "false", :scope => [ :kind ] }.merge!(config) + @chain = [] + end + + def each(&block); @chain.each(&block); end + def index(o); @chain.index(o); end + def insert(index, o); @chain.insert(index, o); end + def delete(o); @chain.delete(o); end + def clear; @chain.clear; self; end + def empty?; @chain.empty?; end + + def initialize_copy(other) + @chain = other.chain.dup end def compile @@ -355,7 +369,7 @@ module ActiveSupport env.value = !env.halted && (!block || block.call) env } - reverse_each do |callback| + @chain.reverse_each do |callback| callbacks = callback.apply(callbacks) end callbacks @@ -369,20 +383,23 @@ module ActiveSupport callbacks.each { |c| prepend_one(c) } end + protected + def chain; @chain; end + private def append_one(callback) remove_duplicates(callback) - push(callback) + @chain.push(callback) end def prepend_one(callback) remove_duplicates(callback) - unshift(callback) + @chain.unshift(callback) end def remove_duplicates(callback) - delete_if { |c| callback.duplicates?(c) } + @chain.delete_if { |c| callback.duplicates?(c) } end end -- cgit v1.2.3 From ade7d365e434b586a4c1747d917beb986cb35fc7 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 May 2013 11:00:25 -0700 Subject: cache compiled callbacks --- activesupport/lib/active_support/callbacks.rb | 34 +++++++++++++++++++++------ 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 13dccf328c..32234431a6 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -350,29 +350,46 @@ module ActiveSupport :scope => [ :kind ] }.merge!(config) @chain = [] + @callbacks = nil end def each(&block); @chain.each(&block); end def index(o); @chain.index(o); end - def insert(index, o); @chain.insert(index, o); end - def delete(o); @chain.delete(o); end - def clear; @chain.clear; self; end def empty?; @chain.empty?; end + def insert(index, o) + @callbacks = nil + @chain.insert(index, o) + end + + def delete(o) + @callbacks = nil + @chain.delete(o) + end + + def clear + @callbacks = nil + @chain.clear + self + end + def initialize_copy(other) - @chain = other.chain.dup + @callbacks = nil + @chain = other.chain.dup end def compile - callbacks = lambda { |env| + return @callbacks if @callbacks + + @callbacks = lambda { |env| block = env.run_block env.value = !env.halted && (!block || block.call) env } @chain.reverse_each do |callback| - callbacks = callback.apply(callbacks) + @callbacks = callback.apply(@callbacks) end - callbacks + @callbacks end def append(*callbacks) @@ -389,16 +406,19 @@ module ActiveSupport private def append_one(callback) + @callbacks = nil remove_duplicates(callback) @chain.push(callback) end def prepend_one(callback) + @callbacks = nil remove_duplicates(callback) @chain.unshift(callback) end def remove_duplicates(callback) + @callbacks = nil @chain.delete_if { |c| callback.duplicates?(c) } end -- cgit v1.2.3 From d1316bb128b1905995ba9f3e4ff35a628b845780 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 May 2013 11:05:47 -0700 Subject: just run compiled callbacks since they are cached --- activesupport/lib/active_support/callbacks.rb | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 32234431a6..4b5c1ed538 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -76,8 +76,9 @@ module ActiveSupport # save # end def run_callbacks(kind, &block) - runner_name = self.class.__define_callbacks(kind, self) - send(runner_name, &block) + runner = self.class.__define_callbacks(kind, self) + e = Filters::Environment.new(self, false, nil, block) + runner.call(e).value end private @@ -430,18 +431,7 @@ module ActiveSupport # if it was not yet defined. # This generated method plays caching role. def __define_callbacks(kind, object) #:nodoc: - name = __callback_runner_name(kind) - unless object.respond_to?(name, true) - filter_chain = object.send("_#{kind}_callbacks").compile - class_eval do - define_method(name) do |&block| - e = Filters::Environment.new(self, false, nil, block) - filter_chain.call(e).value - end - protected name - end - end - name + object.send("_#{kind}_callbacks").compile end def __reset_runner(symbol) -- cgit v1.2.3 From a3e9d6bb22774c3f7ec22c3f8bfeabf56ed8436d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 May 2013 11:06:27 -0700 Subject: __define_callbacks method is not necessary anymore --- activesupport/lib/active_support/callbacks.rb | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 4b5c1ed538..715e4cf8a1 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -76,7 +76,7 @@ module ActiveSupport # save # end def run_callbacks(kind, &block) - runner = self.class.__define_callbacks(kind, self) + runner = send("_#{kind}_callbacks").compile e = Filters::Environment.new(self, false, nil, block) runner.call(e).value end @@ -427,13 +427,6 @@ module ActiveSupport module ClassMethods - # This method defines callback chain method for the given kind - # if it was not yet defined. - # This generated method plays caching role. - def __define_callbacks(kind, object) #:nodoc: - object.send("_#{kind}_callbacks").compile - end - def __reset_runner(symbol) name = __callback_runner_name(symbol) undef_method(name) if method_defined?(name) -- cgit v1.2.3 From c5ed42a60281c24c34a0f7b28a72835a52ea7fc7 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 May 2013 11:08:25 -0700 Subject: callback chain is in charge of the cache, so remove method based cache --- activesupport/lib/active_support/callbacks.rb | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 715e4cf8a1..faa24d09de 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -427,23 +427,6 @@ module ActiveSupport module ClassMethods - def __reset_runner(symbol) - name = __callback_runner_name(symbol) - undef_method(name) if method_defined?(name) - end - - 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: @@ -454,7 +437,6 @@ module ActiveSupport ([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse.each do |target| chain = target.send("_#{name}_callbacks") yield target, chain.dup, type, filters, options - target.__reset_runner(name) end end @@ -539,12 +521,9 @@ module ActiveSupport chain = target.send("_#{symbol}_callbacks").dup callbacks.each { |c| chain.delete(c) } target.send("_#{symbol}_callbacks=", chain) - target.__reset_runner(symbol) end self.send("_#{symbol}_callbacks=", callbacks.dup.clear) - - __reset_runner(symbol) end # Define sets of events in the object lifecycle that support callbacks. -- cgit v1.2.3 From 17dfee0a991038ed0098309ddb4fd542f31dbf57 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 May 2013 11:45:48 -0700 Subject: push duplicates? logic to the instance --- activesupport/lib/active_support/callbacks.rb | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index faa24d09de..db86a532ff 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -94,20 +94,8 @@ module ActiveSupport end class Callback #:nodoc:# - class Unduplicable < Callback # :nodoc: - def duplicates?(other) - false - end - end - def self.build(chain, filter, kind, options, _klass) - klass = case filter - when Symbol, String - Callback - else - Callback::Unduplicable - end - klass.new chain, filter, kind, options, _klass + new chain, filter, kind, options, _klass end attr_accessor :chain, :kind, :options, :klass, :raw_filter @@ -155,9 +143,12 @@ module ActiveSupport end def duplicates?(other) - return false unless self.class == other.class - - matches?(other.kind, other.filter) + case @raw_filter + when Symbol, String + matches?(other.kind, other.filter) + else + false + end end def _update_filter(filter_options, new_options) -- cgit v1.2.3 From 40bdad34a5fb39cdd20887f498d4efeeae6d83c6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 May 2013 11:50:50 -0700 Subject: rename instance variables --- activesupport/lib/active_support/callbacks.rb | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index db86a532ff..0b7e73a5af 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -98,20 +98,22 @@ module ActiveSupport new chain, filter, kind, options, _klass end - attr_accessor :chain, :kind, :options, :klass, :raw_filter + attr_accessor :chain, :kind, :options, :klass def initialize(chain, filter, kind, options, klass) - @chain, @kind, @klass = chain, kind, klass + @chain = chain + @kind = kind + @klass = klass + @filter = filter + @options = options + @key = compute_identifier filter + deprecate_per_key_option(options) normalize_options!(options) - - @raw_filter, @options = filter, options - @key = compute_identifier filter end - def filter - @key - end + def filter; @key; end + def raw_filter; @filter; end def deprecate_per_key_option(options) if options[:per_key] @@ -143,7 +145,7 @@ module ActiveSupport end def duplicates?(other) - case @raw_filter + case @filter when Symbol, String matches?(other.kind, other.filter) else @@ -164,9 +166,9 @@ module ActiveSupport # Wraps code with filter def apply(next_callback) user_conditions = conditions_lambdas - user_callback = make_lambda @raw_filter + user_callback = make_lambda @filter - case @kind + case kind when :before halted_lambda = eval "lambda { |result| #{chain.config[:terminator]} }" lambda { |env| @@ -178,7 +180,7 @@ module ActiveSupport result = user_callback.call target, value env.halted = halted_lambda.call result if env.halted - target.send :halted_callback_hook, @raw_filter.inspect + target.send :halted_callback_hook, @filter.inspect end end next_callback.call env -- cgit v1.2.3 From 2efe6ce538a89c1c143d40ae5455ff85d9e21a54 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 May 2013 11:55:27 -0700 Subject: remove klass because it is not used --- activesupport/lib/active_support/callbacks.rb | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 0b7e73a5af..bdcc539749 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -94,16 +94,15 @@ module ActiveSupport end class Callback #:nodoc:# - def self.build(chain, filter, kind, options, _klass) - new chain, filter, kind, options, _klass + def self.build(chain, filter, kind, options) + new chain, filter, kind, options end - attr_accessor :chain, :kind, :options, :klass + attr_accessor :chain, :kind, :options - def initialize(chain, filter, kind, options, klass) + def initialize(chain, filter, kind, options) @chain = chain @kind = kind - @klass = klass @filter = filter @options = options @key = compute_identifier filter @@ -121,10 +120,9 @@ module ActiveSupport end end - def clone(chain, klass) + def clone(chain) obj = super() obj.chain = chain - obj.klass = klass obj.options = @options.dup obj.options[:if] = @options[:if].dup obj.options[:unless] = @options[:unless].dup @@ -473,7 +471,7 @@ module ActiveSupport __update_callbacks(name, filter_list, block) do |target, chain, type, filters, options| mapped ||= filters.map do |filter| - Callback.build(chain, filter, type, options.dup, self) + Callback.build(chain, filter, type, options.dup) end options[:prepend] ? chain.prepend(*mapped) : chain.append(*mapped) @@ -495,7 +493,7 @@ module ActiveSupport filter = chain.find {|c| c.matches?(type, filter) } if filter && options.any? - new_filter = filter.clone(chain, self) + new_filter = filter.clone(chain) chain.insert(chain.index(filter), new_filter) new_filter.recompile!(options) end -- cgit v1.2.3 From 91e002e31eb50329a5936dab3286b41571868653 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 May 2013 12:00:35 -0700 Subject: dup the callback and set the chain --- activesupport/lib/active_support/callbacks.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index bdcc539749..b7c0f1d484 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -120,13 +120,12 @@ module ActiveSupport end end - def clone(chain) - obj = super() - obj.chain = chain - obj.options = @options.dup - obj.options[:if] = @options[:if].dup - obj.options[:unless] = @options[:unless].dup - obj + def initialize_copy(other) + super + @options = { + :if => other.options[:if].dup, + :unless => other.options[:unless].dup + } end def normalize_options!(options) @@ -493,7 +492,8 @@ module ActiveSupport filter = chain.find {|c| c.matches?(type, filter) } if filter && options.any? - new_filter = filter.clone(chain) + new_filter = filter.dup + new_filter.chain = chain chain.insert(chain.index(filter), new_filter) new_filter.recompile!(options) end -- cgit v1.2.3 From 929658c98d48eeba7f65ec4afb0f8cbedadaf270 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 May 2013 14:12:56 -0700 Subject: push merge code to the callback itself --- activesupport/lib/active_support/callbacks.rb | 28 ++++++++++----------------- 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index b7c0f1d484..0370a27f32 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -120,12 +120,16 @@ module ActiveSupport end end - def initialize_copy(other) - super - @options = { - :if => other.options[:if].dup, - :unless => other.options[:unless].dup + def merge(chain, new_options) + _options = { + :if => @options[:if].dup, + :unless => @options[:unless].dup } + + _options[:if].concat Array(new_options.fetch(:unless, [])) + _options[:unless].concat Array(new_options.fetch(:if, [])) + + self.class.new chain, @filter, @kind, _options end def normalize_options!(options) @@ -150,16 +154,6 @@ module ActiveSupport end 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) - end - - def recompile!(_options) - deprecate_per_key_option(_options) - _update_filter(self.options, _options) - end - # Wraps code with filter def apply(next_callback) user_conditions = conditions_lambdas @@ -492,10 +486,8 @@ module ActiveSupport filter = chain.find {|c| c.matches?(type, filter) } if filter && options.any? - new_filter = filter.dup - new_filter.chain = chain + new_filter = filter.merge(chain, options) chain.insert(chain.index(filter), new_filter) - new_filter.recompile!(options) end chain.delete(filter) -- cgit v1.2.3 From f0a9f814a3ea7237275b2c89df8b378b08e248f8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 May 2013 14:18:57 -0700 Subject: fix deprecation test --- activesupport/lib/active_support/callbacks.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 0370a27f32..76fc7a76a6 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -126,6 +126,8 @@ module ActiveSupport :unless => @options[:unless].dup } + deprecate_per_key_option new_options + _options[:if].concat Array(new_options.fetch(:unless, [])) _options[:unless].concat Array(new_options.fetch(:if, [])) -- cgit v1.2.3 From b97ff316ec6d3fa962dc804d5aeb83aa81b2d847 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 May 2013 15:43:34 -0700 Subject: do not keep a reference to the chain in the callback objects --- activesupport/lib/active_support/callbacks.rb | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 76fc7a76a6..e733257b67 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -95,13 +95,15 @@ module ActiveSupport class Callback #:nodoc:# def self.build(chain, filter, kind, options) - new chain, filter, kind, options + new chain.name, filter, kind, options, chain.config end - attr_accessor :chain, :kind, :options + attr_accessor :kind, :options, :name + attr_reader :chain_config - def initialize(chain, filter, kind, options) - @chain = chain + def initialize(name, filter, kind, options, chain_config) + @chain_config = chain_config + @name = name @kind = kind @filter = filter @options = options @@ -131,7 +133,7 @@ module ActiveSupport _options[:if].concat Array(new_options.fetch(:unless, [])) _options[:unless].concat Array(new_options.fetch(:if, [])) - self.class.new chain, @filter, @kind, _options + self.class.build chain, @filter, @kind, _options end def normalize_options!(options) @@ -139,10 +141,6 @@ module ActiveSupport options[:unless] = Array(options[:unless]) end - def name - chain.name - end - def matches?(_kind, _filter) @kind == _kind && filter == _filter end @@ -163,7 +161,7 @@ module ActiveSupport case kind when :before - halted_lambda = eval "lambda { |result| #{chain.config[:terminator]} }" + halted_lambda = eval "lambda { |result| #{chain_config[:terminator]} }" lambda { |env| target = env.target value = env.value @@ -179,7 +177,7 @@ module ActiveSupport next_callback.call env } when :after - if chain.config[:skip_after_callbacks_if_terminated] + if chain_config[:skip_after_callbacks_if_terminated] lambda { |env| env = next_callback.call env target = env.target @@ -271,7 +269,7 @@ module ActiveSupport } end else - scopes = Array(chain.config[:scope]) + scopes = Array(chain_config[:scope]) method_to_call = scopes.map{ |s| public_send(s) }.join("_") lambda { |target, _, &blk| -- cgit v1.2.3 From 19b9f7ba334108bd669ec6ae3bdf11d707a7d689 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 13 May 2013 12:05:22 -0700 Subject: pass the actual filter, not a string --- activesupport/lib/active_support/callbacks.rb | 2 +- activesupport/test/callbacks_test.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index e733257b67..4819fe71de 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -171,7 +171,7 @@ module ActiveSupport result = user_callback.call target, value env.halted = halted_lambda.call result if env.halted - target.send :halted_callback_hook, @filter.inspect + target.send :halted_callback_hook, @filter end end next_callback.call env diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb index 091fe90bcc..68878c0189 100644 --- a/activesupport/test/callbacks_test.rb +++ b/activesupport/test/callbacks_test.rb @@ -718,7 +718,7 @@ module CallbacksTest def test_termination_invokes_hook terminator = CallbackTerminator.new terminator.save - assert_equal ":second", terminator.halted + assert_equal :second, terminator.halted end def test_block_never_called_if_terminated -- cgit v1.2.3 From b308f0d4f160307d03c5c7816d536042dc69941d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 13 May 2013 15:50:16 -0700 Subject: raise an argument error if the filter arity is greater than 1 --- activesupport/lib/active_support/callbacks.rb | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 2eec360042..fc797262d9 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -250,23 +250,17 @@ module ActiveSupport def make_lambda(filter) case filter when Symbol - lambda { |target, value, &blk| target.send filter, &blk } + lambda { |target, _, &blk| target.send filter, &blk } when String l = eval "lambda { |value| #{filter} }" - lambda { |target,value| target.instance_exec(value, &l) } + lambda { |target, value| target.instance_exec(value, &l) } when ::Proc - if filter.arity <= 0 - return lambda { |target, _| target.instance_exec(&filter) } - end + raise ArgumentError if filter.arity > 1 - if filter.arity == 1 - lambda { |target, _| - target.instance_exec(target, &filter) - } + if filter.arity <= 0 + lambda { |target, _| target.instance_exec(&filter) } else - lambda { |target, _| - target.instance_exec target, ::Proc.new, &filter - } + lambda { |target, _| target.instance_exec(target, &filter) } end else scopes = Array(chain_config[:scope]) -- cgit v1.2.3 From 9caf0cf9c8c7b42737ae78c470a5dd2f583ada75 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 13 May 2013 15:54:45 -0700 Subject: we never pass blocks, so remove this --- activesupport/lib/active_support/callbacks.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index fc797262d9..d175465d4d 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -250,7 +250,7 @@ module ActiveSupport def make_lambda(filter) case filter when Symbol - lambda { |target, _, &blk| target.send filter, &blk } + lambda { |target, _| target.send filter } when String l = eval "lambda { |value| #{filter} }" lambda { |target, value| target.instance_exec(value, &l) } -- cgit v1.2.3 From 877964dc61d56f7579871ad434622748f4e208f9 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 13 May 2013 16:17:29 -0700 Subject: Arrays are no longer supported --- activesupport/lib/active_support/callbacks.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index d175465d4d..6ffe8a750d 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -229,9 +229,6 @@ module ActiveSupport # Filters support: # - # Arrays:: Used in conditions. This is used to specify - # multiple conditions. Used internally to - # merge conditions from skip_* filters. # Symbols:: A method to call. # Strings:: Some content to evaluate. # Procs:: A proc to call with the object. @@ -240,7 +237,6 @@ module ActiveSupport # All of these objects are compiled into methods and handled # the same after this point: # - # Arrays:: Merged together into a single filter. # Symbols:: Already methods. # Strings:: class_eval'ed into methods. # Procs:: define_method'ed into methods. -- cgit v1.2.3 From ccbefff684d63c71e13fbb7507fa41d3400c0c95 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 13 May 2013 16:43:27 -0700 Subject: if there is nothing to compile, then do not bother compiling --- activesupport/lib/active_support/callbacks.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 6ffe8a750d..8422d4f5f3 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -76,9 +76,14 @@ module ActiveSupport # save # end def run_callbacks(kind, &block) - runner = send("_#{kind}_callbacks").compile - e = Filters::Environment.new(self, false, nil, block) - runner.call(e).value + cbs = send("_#{kind}_callbacks") + if cbs.empty? + yield if block_given? + else + runner = cbs.compile + e = Filters::Environment.new(self, false, nil, block) + runner.call(e).value + end end private -- cgit v1.2.3 From d2c0571bf6161e859ccc9c91a7d87b2bffa35dd5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 13 May 2013 16:53:08 -0700 Subject: Revert "we never pass blocks, so remove this" This reverts commit 9caf0cf9c8c7b42737ae78c470a5dd2f583ada75. --- activesupport/lib/active_support/callbacks.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 8422d4f5f3..fa37b24f51 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -251,7 +251,7 @@ module ActiveSupport def make_lambda(filter) case filter when Symbol - lambda { |target, _| target.send filter } + lambda { |target, _, &blk| target.send filter, &blk } when String l = eval "lambda { |value| #{filter} }" lambda { |target, value| target.instance_exec(value, &l) } -- cgit v1.2.3 From 73aefee3f23f54786c69f1bafa5b1f0b5aee8398 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 13 May 2013 16:59:05 -0700 Subject: use a singleton end node --- activesupport/lib/active_support/callbacks.rb | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index fa37b24f51..3be23c17e1 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -96,6 +96,15 @@ module ActiveSupport module Filters Environment = Struct.new(:target, :halted, :value, :run_block) + + class End + def call(env) + block = env.run_block + env.value = !env.halted && (!block || block.call) + env + end + end + ENDING = End.new end class Callback #:nodoc:# @@ -361,11 +370,7 @@ module ActiveSupport def compile return @callbacks if @callbacks - @callbacks = lambda { |env| - block = env.run_block - env.value = !env.halted && (!block || block.call) - env - } + @callbacks = Filters::ENDING @chain.reverse_each do |callback| @callbacks = callback.apply(@callbacks) end -- cgit v1.2.3 From eac50bc3359ca3dabfe5d8fea31c6a904362dbf3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 May 2013 11:20:34 -0700 Subject: polymorphic before callbacks --- activesupport/lib/active_support/callbacks.rb | 70 +++++++++++++++++++++------ 1 file changed, 54 insertions(+), 16 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 3be23c17e1..7ea77d5857 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -105,6 +105,59 @@ module ActiveSupport end end ENDING = End.new + + class Before + def self.build(next_callback, user_callback, user_conditions, chain_config, filter) + if chain_config.key?(:terminator) && user_conditions.any? + halted_lambda = eval "lambda { |result| #{chain_config[:terminator]} }" + lambda { |env| + target = env.target + value = env.value + halted = env.halted + + if !halted && user_conditions.all? { |c| c.call(target, value) } + result = user_callback.call target, value + env.halted = halted_lambda.call result + if env.halted + target.send :halted_callback_hook, filter + end + end + next_callback.call env + } + elsif chain_config.key? :terminator + halted_lambda = eval "lambda { |result| #{chain_config[:terminator]} }" + lambda { |env| + target = env.target + value = env.value + halted = env.halted + + if !halted + result = user_callback.call target, value + env.halted = halted_lambda.call result + if env.halted + target.send :halted_callback_hook, filter + end + end + next_callback.call env + } + elsif user_conditions.any? + lambda { |env| + target = env.target + value = env.value + + if user_conditions.all? { |c| c.call(target, value) } + user_callback.call target, value + end + next_callback.call env + } + else + lambda { |env| + user_callback.call env.target, env.value + next_callback.call env + } + end + end + end end class Callback #:nodoc:# @@ -175,21 +228,7 @@ module ActiveSupport case kind when :before - halted_lambda = eval "lambda { |result| #{chain_config[:terminator]} }" - lambda { |env| - target = env.target - value = env.value - halted = env.halted - - if !halted && user_conditions.all? { |c| c.call(target, value) } - result = user_callback.call target, value - env.halted = halted_lambda.call result - if env.halted - target.send :halted_callback_hook, @filter - end - end - next_callback.call env - } + Filters::Before.build(next_callback, user_callback, user_conditions, chain_config, @filter) when :after if chain_config[:skip_after_callbacks_if_terminated] lambda { |env| @@ -335,7 +374,6 @@ module ActiveSupport def initialize(name, config) @name = name @config = { - :terminator => "false", :scope => [ :kind ] }.merge!(config) @chain = [] -- cgit v1.2.3 From bd95ff84f3199fba2c35c2727182672ac75c08b2 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 May 2013 11:27:24 -0700 Subject: push the before filter lambdas to factory methods --- activesupport/lib/active_support/callbacks.rb | 98 ++++++++++++++++----------- 1 file changed, 58 insertions(+), 40 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 7ea77d5857..d0c3f4bde9 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -110,52 +110,70 @@ module ActiveSupport def self.build(next_callback, user_callback, user_conditions, chain_config, filter) if chain_config.key?(:terminator) && user_conditions.any? halted_lambda = eval "lambda { |result| #{chain_config[:terminator]} }" - lambda { |env| - target = env.target - value = env.value - halted = env.halted - - if !halted && user_conditions.all? { |c| c.call(target, value) } - result = user_callback.call target, value - env.halted = halted_lambda.call result - if env.halted - target.send :halted_callback_hook, filter - end - end - next_callback.call env - } + terminal_and_conditional(next_callback, user_callback, user_conditions, halted_lambda, filter) elsif chain_config.key? :terminator halted_lambda = eval "lambda { |result| #{chain_config[:terminator]} }" - lambda { |env| - target = env.target - value = env.value - halted = env.halted + terminal(next_callback, user_callback, halted_lambda, filter) + elsif user_conditions.any? + conditional(next_callback, user_callback, user_conditions) + else + simple next_callback, user_callback + end + end + + private + + def self.terminal_and_conditional(next_callback, user_callback, user_conditions, halted_lambda, filter) + lambda { |env| + target = env.target + value = env.value + halted = env.halted - if !halted - result = user_callback.call target, value - env.halted = halted_lambda.call result - if env.halted - target.send :halted_callback_hook, filter - end + if !halted && user_conditions.all? { |c| c.call(target, value) } + result = user_callback.call target, value + env.halted = halted_lambda.call result + if env.halted + target.send :halted_callback_hook, filter end - next_callback.call env - } - elsif user_conditions.any? - lambda { |env| - target = env.target - value = env.value + end + next_callback.call env + } + end - if user_conditions.all? { |c| c.call(target, value) } - user_callback.call target, value + def self.terminal(next_callback, user_callback, halted_lambda, filter) + lambda { |env| + target = env.target + value = env.value + halted = env.halted + + if !halted + result = user_callback.call target, value + env.halted = halted_lambda.call result + if env.halted + target.send :halted_callback_hook, filter end - next_callback.call env - } - else - lambda { |env| - user_callback.call env.target, env.value - next_callback.call env - } - end + end + next_callback.call env + } + end + + def self.conditional(next_callback, user_callback, user_conditions) + lambda { |env| + target = env.target + value = env.value + + if user_conditions.all? { |c| c.call(target, value) } + user_callback.call target, value + end + next_callback.call env + } + end + + def self.simple(next_callback, user_callback) + lambda { |env| + user_callback.call env.target, env.value + next_callback.call env + } end end end -- cgit v1.2.3 From c5953f7dba20a6706a9f3dcce4cb43d7d91aad33 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 May 2013 11:30:14 -0700 Subject: rename terminal to halting, try to keep naming consistent --- activesupport/lib/active_support/callbacks.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index d0c3f4bde9..0f6610825f 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -110,10 +110,10 @@ module ActiveSupport def self.build(next_callback, user_callback, user_conditions, chain_config, filter) if chain_config.key?(:terminator) && user_conditions.any? halted_lambda = eval "lambda { |result| #{chain_config[:terminator]} }" - terminal_and_conditional(next_callback, user_callback, user_conditions, halted_lambda, filter) + halting_and_conditional(next_callback, user_callback, user_conditions, halted_lambda, filter) elsif chain_config.key? :terminator halted_lambda = eval "lambda { |result| #{chain_config[:terminator]} }" - terminal(next_callback, user_callback, halted_lambda, filter) + halting(next_callback, user_callback, halted_lambda, filter) elsif user_conditions.any? conditional(next_callback, user_callback, user_conditions) else @@ -123,7 +123,7 @@ module ActiveSupport private - def self.terminal_and_conditional(next_callback, user_callback, user_conditions, halted_lambda, filter) + def self.halting_and_conditional(next_callback, user_callback, user_conditions, halted_lambda, filter) lambda { |env| target = env.target value = env.value @@ -140,7 +140,7 @@ module ActiveSupport } end - def self.terminal(next_callback, user_callback, halted_lambda, filter) + def self.halting(next_callback, user_callback, halted_lambda, filter) lambda { |env| target = env.target value = env.value -- cgit v1.2.3 From e8ddd4f9e5b7665d7569bfebd4c8a813f8781925 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 May 2013 11:37:34 -0700 Subject: polymorphic after filter --- activesupport/lib/active_support/callbacks.rb | 95 ++++++++++++++++++++------- 1 file changed, 70 insertions(+), 25 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 0f6610825f..0ae69832bd 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -176,6 +176,75 @@ module ActiveSupport } end end + + class After + def self.build(next_callback, user_callback, user_conditions, chain_config) + if chain_config[:skip_after_callbacks_if_terminated] + if chain_config.key?(:terminator) && user_conditions.any? + halting_and_conditional(next_callback, user_callback, user_conditions) + elsif chain_config.key?(:terminator) + halting(next_callback, user_callback) + elsif user_conditions.any? + conditional next_callback, user_callback, user_conditions + else + simple next_callback, user_callback + end + else + if user_conditions.any? + conditional next_callback, user_callback, user_conditions + else + simple next_callback, user_callback + end + end + end + + private + + def self.halting_and_conditional(next_callback, user_callback, user_conditions) + lambda { |env| + env = next_callback.call env + target = env.target + value = env.value + halted = env.halted + + if !halted && user_conditions.all? { |c| c.call(target, value) } + user_callback.call target, value + end + env + } + end + + def self.halting(next_callback, user_callback) + lambda { |env| + env = next_callback.call env + if !env.halted + user_callback.call env.target, env.value + end + env + } + end + + def self.conditional(next_callback, user_callback, user_conditions) + lambda { |env| + env = next_callback.call env + target = env.target + value = env.value + + if user_conditions.all? { |c| c.call(target, value) } + user_callback.call target, value + end + env + } + end + + def self.simple(next_callback, user_callback) + lambda { |env| + env = next_callback.call env + user_callback.call env.target, env.value + env + } + end + end end class Callback #:nodoc:# @@ -248,31 +317,7 @@ module ActiveSupport when :before Filters::Before.build(next_callback, user_callback, user_conditions, chain_config, @filter) when :after - if chain_config[:skip_after_callbacks_if_terminated] - lambda { |env| - env = next_callback.call env - target = env.target - value = env.value - halted = env.halted - - if !halted && user_conditions.all? { |c| c.call(target, value) } - user_callback.call target, value - end - env - } - else - lambda { |env| - env = next_callback.call env - target = env.target - value = env.value - halted = env.halted - - if user_conditions.all? { |c| c.call(target, value) } - user_callback.call target, value - end - env - } - end + Filters::After.build(next_callback, user_callback, user_conditions, chain_config) when :around lambda { |env| target = env.target -- cgit v1.2.3 From 87378b0b6d5361d380ce85e4c08b147a9e7c375b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 May 2013 11:48:04 -0700 Subject: polymorphic around callbacks --- activesupport/lib/active_support/callbacks.rb | 94 ++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 15 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 0ae69832bd..cc4f589203 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -245,6 +245,84 @@ module ActiveSupport } end end + + class Around + def self.build(next_callback, user_callback, user_conditions, chain_config) + if chain_config.key?(:terminator) && user_conditions.any? + halting_and_conditional(next_callback, user_callback, user_conditions) + elsif chain_config.key? :terminator + halting(next_callback, user_callback) + elsif user_conditions.any? + conditional(next_callback, user_callback, user_conditions) + else + simple(next_callback, user_callback) + end + end + + private + + def self.halting_and_conditional(next_callback, user_callback, user_conditions) + lambda { |env| + target = env.target + value = env.value + halted = env.halted + + if !halted && user_conditions.all? { |c| c.call(target, value) } + user_callback.call(target, value) { + env = next_callback.call env + env.value + } + env + else + next_callback.call env + end + } + end + + def self.halting(next_callback, user_callback) + lambda { |env| + target = env.target + value = env.value + + if !env.halted + user_callback.call(target, value) { + env = next_callback.call env + env.value + } + env + else + next_callback.call env + end + } + end + + def self.conditional(next_callback, user_callback, user_conditions) + lambda { |env| + target = env.target + value = env.value + + if user_conditions.all? { |c| c.call(target, value) } + user_callback.call(target, value) { + env = next_callback.call env + env.value + } + env + else + next_callback.call env + end + } + end + + def self.simple(next_callback, user_callback) + lambda { |env| + user_callback.call(env.target, env.value) { + env = next_callback.call env + env.value + } + env + } + end + end end class Callback #:nodoc:# @@ -319,21 +397,7 @@ module ActiveSupport when :after Filters::After.build(next_callback, user_callback, user_conditions, chain_config) when :around - lambda { |env| - target = env.target - value = env.value - halted = env.halted - - if !halted && user_conditions.all? { |c| c.call(target, value) } - user_callback.call(target, value) { - env = next_callback.call env - env.value - } - env - else - next_callback.call env - end - } + Filters::Around.build(next_callback, user_callback, user_conditions, chain_config) end end -- cgit v1.2.3 From 78202055c971659689f6a96a5b4aa2c138cb44d2 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 May 2013 12:03:33 -0700 Subject: fix shadowed variable warnings --- activesupport/lib/active_support/callbacks.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index cc4f589203..ab3bb23e88 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -507,9 +507,9 @@ module ActiveSupport @callbacks = nil end - def each(&block); @chain.each(&block); end - def index(o); @chain.index(o); end - def empty?; @chain.empty?; end + def each(&block); @chain.each(&block); end + def index(o); @chain.index(o); end + def empty?; @chain.empty?; end def insert(index, o) @callbacks = nil @@ -629,9 +629,9 @@ module ActiveSupport # existing chain rather than appended. def set_callback(name, *filter_list, &block) type, filters, options = normalize_callback_params(name, filter_list, block) - chain = get_callbacks name + self_chain = get_callbacks name mapped = filters.map do |filter| - Callback.build(chain, filter, type, options.dup) + Callback.build(self_chain, filter, type, options.dup) end __update_callbacks(name) do |target, chain| -- cgit v1.2.3