Skip to content
This repository
Browse code

First draft of ActiveSupport::Rescuable

Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
  • Loading branch information...
commit 964dfc15572d7c10771c81ac3cbfb455dd5e378e 1 parent 9599948
Norbert Crombach authored October 04, 2008 lifo committed October 04, 2008
74  activesupport/lib/active_support/rescuable.rb
... ...
@@ -0,0 +1,74 @@
  1
+module ActiveSupport
  2
+  module Rescuable
  3
+    def self.included(base) # :nodoc:
  4
+      base.class_inheritable_array :rescue_handlers
  5
+      base.rescue_handlers = []
  6
+      base.extend(ClassMethods)
  7
+    end
  8
+
  9
+    module ClassMethods
  10
+      def enable_rescue_for(*methods)
  11
+        methods.each do |method|
  12
+          class_eval <<-EOS
  13
+            def #{method}_with_rescue(*args, &block)
  14
+              #{method}_without_rescue(*args, &block)
  15
+            rescue Exception => exception
  16
+              rescue_with_handler(exception)
  17
+            end
  18
+
  19
+            alias_method_chain :#{method}, :rescue
  20
+          EOS
  21
+        end
  22
+      end
  23
+
  24
+      def rescue_from(*klasses, &block)
  25
+        options = klasses.extract_options!
  26
+        unless options.has_key?(:with)
  27
+          if block_given?
  28
+            options[:with] = block
  29
+          else
  30
+            raise ArgumentError, "Need a handler. Supply an options hash that has a :with key as the last argument."
  31
+          end
  32
+        end
  33
+
  34
+        klasses.each do |klass|
  35
+          key = if klass.is_a?(Class) && klass <= Exception
  36
+            klass.name
  37
+          elsif klass.is_a?(String)
  38
+            klass
  39
+          else
  40
+            raise ArgumentError, "#{klass} is neither an Exception nor a String"
  41
+          end
  42
+
  43
+          # put the new handler at the end because the list is read in reverse
  44
+          rescue_handlers << [key, options[:with]]
  45
+        end
  46
+      end
  47
+    end
  48
+
  49
+    def rescue_with_handler(exception)
  50
+      if handler = handler_for_rescue(exception)
  51
+        handler.arity != 0 ? handler.call(exception) : handler.call
  52
+      else
  53
+        raise exception
  54
+      end
  55
+    end
  56
+
  57
+    def handler_for_rescue(exception)
  58
+      # use reverse so what is added last is found first
  59
+      _, handler = *rescue_handlers.reverse.detect do |klass_name, handler|
  60
+        # allow strings to support constants that are not defined yet
  61
+        klass = self.class.const_get(klass_name) rescue nil
  62
+        klass ||= klass_name.constantize rescue nil
  63
+        exception.is_a?(klass) if klass
  64
+      end
  65
+
  66
+      case handler
  67
+      when Symbol
  68
+        method(handler)
  69
+      when Proc
  70
+        handler.bind(self)
  71
+      end
  72
+    end
  73
+  end
  74
+end

0 notes on commit 964dfc1

Please sign in to comment.
Something went wrong with that request. Please try again.