aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support/rescuable.rb
diff options
context:
space:
mode:
authorNorbert Crombach <norbert.crombach@primetheory.org>2008-10-04 20:28:08 +0100
committerPratik Naik <pratiknaik@gmail.com>2008-10-04 20:28:08 +0100
commit964dfc15572d7c10771c81ac3cbfb455dd5e378e (patch)
tree93c3e129b92ef16255509429eaf47bff684f53f5 /activesupport/lib/active_support/rescuable.rb
parent9599948fbcd67c1c2c5fecc2dca148e998479e33 (diff)
downloadrails-964dfc15572d7c10771c81ac3cbfb455dd5e378e.tar.gz
rails-964dfc15572d7c10771c81ac3cbfb455dd5e378e.tar.bz2
rails-964dfc15572d7c10771c81ac3cbfb455dd5e378e.zip
First draft of ActiveSupport::Rescuable
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
Diffstat (limited to 'activesupport/lib/active_support/rescuable.rb')
-rw-r--r--activesupport/lib/active_support/rescuable.rb74
1 files changed, 74 insertions, 0 deletions
diff --git a/activesupport/lib/active_support/rescuable.rb b/activesupport/lib/active_support/rescuable.rb
new file mode 100644
index 0000000000..d1a4366636
--- /dev/null
+++ b/activesupport/lib/active_support/rescuable.rb
@@ -0,0 +1,74 @@
+module ActiveSupport
+ module Rescuable
+ def self.included(base) # :nodoc:
+ base.class_inheritable_array :rescue_handlers
+ base.rescue_handlers = []
+ base.extend(ClassMethods)
+ end
+
+ module ClassMethods
+ def enable_rescue_for(*methods)
+ methods.each do |method|
+ class_eval <<-EOS
+ def #{method}_with_rescue(*args, &block)
+ #{method}_without_rescue(*args, &block)
+ rescue Exception => exception
+ rescue_with_handler(exception)
+ end
+
+ alias_method_chain :#{method}, :rescue
+ EOS
+ end
+ end
+
+ def rescue_from(*klasses, &block)
+ options = klasses.extract_options!
+ unless options.has_key?(:with)
+ if block_given?
+ options[:with] = block
+ else
+ raise ArgumentError, "Need a handler. Supply an options hash that has a :with key as the last argument."
+ end
+ end
+
+ klasses.each do |klass|
+ key = if klass.is_a?(Class) && klass <= Exception
+ klass.name
+ elsif klass.is_a?(String)
+ klass
+ else
+ raise ArgumentError, "#{klass} is neither an Exception nor a String"
+ end
+
+ # put the new handler at the end because the list is read in reverse
+ rescue_handlers << [key, options[:with]]
+ end
+ end
+ end
+
+ def rescue_with_handler(exception)
+ if handler = handler_for_rescue(exception)
+ handler.arity != 0 ? handler.call(exception) : handler.call
+ else
+ raise exception
+ end
+ end
+
+ def handler_for_rescue(exception)
+ # use reverse so what is added last is found first
+ _, handler = *rescue_handlers.reverse.detect do |klass_name, handler|
+ # allow strings to support constants that are not defined yet
+ klass = self.class.const_get(klass_name) rescue nil
+ klass ||= klass_name.constantize rescue nil
+ exception.is_a?(klass) if klass
+ end
+
+ case handler
+ when Symbol
+ method(handler)
+ when Proc
+ handler.bind(self)
+ end
+ end
+ end
+end