public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
rails / activesupport / lib / active_support / rescuable.rb
f8dbd416 » jeremy 2009-03-24 Explicit dependency on clas... 1 require 'active_support/core_ext/class/inheritable_attributes'
148da357 » jeremy 2009-03-28 Explicit dependency on Proc... 2 require 'active_support/core_ext/proc'
f8dbd416 » jeremy 2009-03-24 Explicit dependency on clas... 3
964dfc15 » norbert 2008-10-04 First draft of ActiveSuppor... 4 module ActiveSupport
259a7a84 » lifo 2008-10-04 Add tests for ActiveSupport... 5 # Rescuable module adds support for easier exception handling.
964dfc15 » norbert 2008-10-04 First draft of ActiveSuppor... 6 module Rescuable
7b169ed1 » josh 2009-10-13 Extend Callbacks and Rescua... 7 extend Concern
259a7a84 » lifo 2008-10-04 Add tests for ActiveSupport... 8
7b169ed1 » josh 2009-10-13 Extend Callbacks and Rescua... 9 included do
10 class_inheritable_accessor :rescue_handlers
11 self.rescue_handlers = []
964dfc15 » norbert 2008-10-04 First draft of ActiveSuppor... 12 end
13
14 module ClassMethods
259a7a84 » lifo 2008-10-04 Add tests for ActiveSupport... 15 # Rescue exceptions raised in controller actions.
16 #
17 # <tt>rescue_from</tt> receives a series of exception classes or class
18 # names, and a trailing <tt>:with</tt> option with the name of a method
19 # or a Proc object to be called to handle them. Alternatively a block can
20 # be given.
21 #
22 # Handlers that take one argument will be called with the exception, so
23 # that the exception can be inspected when dealing with it.
24 #
25 # Handlers are inherited. They are searched from right to left, from
26 # bottom to top, and up the hierarchy. The handler of the first class for
27 # which <tt>exception.is_a?(klass)</tt> holds true is the one invoked, if
28 # any.
29 #
30 # class ApplicationController < ActionController::Base
31 # rescue_from User::NotAuthorized, :with => :deny_access # self defined exception
32 # rescue_from ActiveRecord::RecordInvalid, :with => :show_errors
33 #
34 # rescue_from 'MyAppError::Base' do |exception|
35 # render :xml => exception, :status => 500
36 # end
37 #
38 # protected
39 # def deny_access
40 # ...
41 # end
42 #
43 # def show_errors(exception)
44 # exception.record.new_record? ? ...
45 # end
46 # end
964dfc15 » norbert 2008-10-04 First draft of ActiveSuppor... 47 def rescue_from(*klasses, &block)
48 options = klasses.extract_options!
259a7a84 » lifo 2008-10-04 Add tests for ActiveSupport... 49
964dfc15 » norbert 2008-10-04 First draft of ActiveSuppor... 50 unless options.has_key?(:with)
51 if block_given?
52 options[:with] = block
53 else
54 raise ArgumentError, "Need a handler. Supply an options hash that has a :with key as the last argument."
55 end
56 end
57
58 klasses.each do |klass|
59 key = if klass.is_a?(Class) && klass <= Exception
60 klass.name
61 elsif klass.is_a?(String)
62 klass
63 else
64 raise ArgumentError, "#{klass} is neither an Exception nor a String"
65 end
66
67 # put the new handler at the end because the list is read in reverse
68 rescue_handlers << [key, options[:with]]
69 end
70 end
71 end
72
259a7a84 » lifo 2008-10-04 Add tests for ActiveSupport... 73 # Tries to rescue the exception by looking up and calling a registered handler.
964dfc15 » norbert 2008-10-04 First draft of ActiveSuppor... 74 def rescue_with_handler(exception)
75 if handler = handler_for_rescue(exception)
76 handler.arity != 0 ? handler.call(exception) : handler.call
259a7a84 » lifo 2008-10-04 Add tests for ActiveSupport... 77 true # don't rely on the return value of the handler
964dfc15 » norbert 2008-10-04 First draft of ActiveSuppor... 78 end
79 end
80
81 def handler_for_rescue(exception)
259a7a84 » lifo 2008-10-04 Add tests for ActiveSupport... 82 # We go from right to left because pairs are pushed onto rescue_handlers
83 # as rescue_from declarations are found.
0214d337 » jeremy 2009-11-13 Rescue handlers should neve... 84 _, rescuer = rescue_handlers.reverse.detect do |klass_name, handler|
259a7a84 » lifo 2008-10-04 Add tests for ActiveSupport... 85 # The purpose of allowing strings in rescue_from is to support the
86 # declaration of handler associations for exception classes whose
87 # definition is yet unknown.
88 #
89 # Since this loop needs the constants it would be inconsistent to
90 # assume they should exist at this point. An early raised exception
91 # could trigger some other handler and the array could include
92 # precisely a string whose corresponding constant has not yet been
93 # seen. This is why we are tolerant to unknown constants.
94 #
95 # Note that this tolerance only matters if the exception was given as
96 # a string, otherwise a NameError will be raised by the interpreter
97 # itself when rescue_from CONSTANT is executed.
964dfc15 » norbert 2008-10-04 First draft of ActiveSuppor... 98 klass = self.class.const_get(klass_name) rescue nil
99 klass ||= klass_name.constantize rescue nil
100 exception.is_a?(klass) if klass
101 end
102
983dc807 » jeremy 2008-11-06 Don't shadow local with bla... 103 case rescuer
964dfc15 » norbert 2008-10-04 First draft of ActiveSuppor... 104 when Symbol
983dc807 » jeremy 2008-11-06 Don't shadow local with bla... 105 method(rescuer)
964dfc15 » norbert 2008-10-04 First draft of ActiveSuppor... 106 when Proc
983dc807 » jeremy 2008-11-06 Don't shadow local with bla... 107 rescuer.bind(self)
964dfc15 » norbert 2008-10-04 First draft of ActiveSuppor... 108 end
109 end
110 end
111 end