diff options
Diffstat (limited to 'activesupport/lib')
-rw-r--r-- | activesupport/lib/active_support.rb | 1 | ||||
-rw-r--r-- | activesupport/lib/active_support/callbacks.rb | 94 | ||||
-rw-r--r-- | activesupport/lib/active_support/testing/setup_and_teardown.rb | 50 |
3 files changed, 99 insertions, 46 deletions
diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index c4b7cc8cba..7a0476b729 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -26,6 +26,7 @@ $:.unshift(File.dirname(__FILE__)) require 'active_support/vendor' require 'active_support/basic_object' require 'active_support/inflector' +require 'active_support/callbacks' require 'active_support/core_ext' diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb new file mode 100644 index 0000000000..ac9f1a9d5f --- /dev/null +++ b/activesupport/lib/active_support/callbacks.rb @@ -0,0 +1,94 @@ +module ActiveSupport + module Callbacks + class Callback + def self.run(callbacks, object, options = {}, &terminator) + enumerator = options[:enumerator] || :each + + unless block_given? + callbacks.send(enumerator) { |callback| callback.call(object) } + else + callbacks.send(enumerator) do |callback| + result = callback.call(object) + break result if terminator.call(result, object) + end + end + end + + attr_reader :kind, :method, :identifier, :options + + def initialize(kind, method, options = {}) + @kind = kind + @method = method + @identifier = options[:identifier] + @options = options + end + + def call(object) + evaluate_method(method, object) if should_run_callback?(object) + end + + private + def evaluate_method(method, object) + case method + when Symbol + object.send(method) + when String + eval(method, object.instance_eval { binding }) + when Proc, Method + method.call(object) + else + if method.respond_to?(kind) + method.send(kind, object) + else + raise ArgumentError, + "Callbacks must be a symbol denoting the method to call, a string to be evaluated, " + + "a block to be invoked, or an object responding to the callback method." + end + end + end + + def should_run_callback?(object) + if options[:if] + evaluate_method(options[:if], object) + elsif options[:unless] + !evaluate_method(options[:unless], object) + else + true + end + end + end + + def self.included(base) + base.extend ClassMethods + end + + module ClassMethods + def define_callbacks(*callbacks) + callbacks.each do |callback| + class_eval <<-"end_eval" + def self.#{callback}(*methods, &block) + options = methods.extract_options! + methods << block if block_given? + callbacks = methods.map { |method| Callback.new(:#{callback}, method, options) } + (@#{callback}_callbacks ||= []).concat callbacks + end + + def self.#{callback}_callback_chain + @#{callback}_callbacks ||= [] + + if superclass.respond_to?(:#{callback}_callback_chain) + superclass.#{callback}_callback_chain + @#{callback}_callbacks + else + @#{callback}_callbacks + end + end + end_eval + end + end + end + + def run_callbacks(kind, options = {}, &block) + Callback.run(self.class.send("#{kind}_callback_chain"), self, options, &block) + end + end +end diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb index 1639462fae..b2a937edd0 100644 --- a/activesupport/lib/active_support/testing/setup_and_teardown.rb +++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb @@ -2,7 +2,8 @@ module ActiveSupport module Testing module SetupAndTeardown def self.included(base) - base.extend ClassMethods + base.send :include, ActiveSupport::Callbacks + base.define_callbacks :setup, :teardown begin require 'mocha' @@ -12,38 +13,6 @@ module ActiveSupport end end - module ClassMethods - def setup(*method_names, &block) - method_names << block if block_given? - (@setup_callbacks ||= []).concat method_names - end - - def teardown(*method_names, &block) - method_names << block if block_given? - (@teardown_callbacks ||= []).concat method_names - end - - def setup_callback_chain - @setup_callbacks ||= [] - - if superclass.respond_to?(:setup_callback_chain) - superclass.setup_callback_chain + @setup_callbacks - else - @setup_callbacks - end - end - - def teardown_callback_chain - @teardown_callbacks ||= [] - - if superclass.respond_to?(:teardown_callback_chain) - superclass.teardown_callback_chain + @teardown_callbacks - else - @teardown_callbacks - end - end - end - # This redefinition is unfortunate but test/unit shows us no alternative. def run_with_callbacks(result) #:nodoc: return if @method_name.to_s == "default_test" @@ -63,7 +32,7 @@ module ActiveSupport ensure begin teardown - run_callbacks :teardown, :reverse_each + run_callbacks :teardown, :enumerator => :reverse_each rescue Test::Unit::AssertionFailedError => e add_failure(e.message, e.backtrace) rescue *Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS @@ -98,7 +67,7 @@ module ActiveSupport ensure begin teardown - run_callbacks :teardown, :reverse_each + run_callbacks :teardown, :enumerator => :reverse_each rescue Test::Unit::AssertionFailedError => e add_failure(e.message, e.backtrace) rescue StandardError, ScriptError @@ -111,17 +80,6 @@ module ActiveSupport result.add_run yield(Test::Unit::TestCase::FINISHED, name) end - - protected - def run_callbacks(kind, enumerator = :each) - self.class.send("#{kind}_callback_chain").send(enumerator) do |callback| - case callback - when Proc; callback.call(self) - when String, Symbol; send!(callback) - else raise ArgumentError, "Unrecognized callback #{callback.inspect}" - end - end - end end end end |