aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport/lib')
-rw-r--r--activesupport/lib/active_support.rb1
-rw-r--r--activesupport/lib/active_support/callbacks.rb94
-rw-r--r--activesupport/lib/active_support/testing/setup_and_teardown.rb50
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