module RescueAny::ClassMethods

Public Instance Methods

method_added(method_name) click to toggle source
# File lib/rescue_any.rb, line 65
def method_added(method_name)
  if rescue_statements.keys.include?(method_name)
    alias_method_name = "#{method_name}_without_rescue_any".to_sym

    unless self.instance_methods.include?(alias_method_name)
      self.send(:alias_method, alias_method_name, method_name)
      self.send(:define_method, method_name) do
        begin
          self.send(alias_method_name)
        rescue Exception => ex
          exception_handled = false

          exceptions_and_rescue_blocks = self.class.instance_eval { rescue_statements[method_name] }
          exceptions_and_rescue_blocks.keys.each do |rescue_exception|
            if ex.instance_of? rescue_exception
              self.class.instance_eval do
                rescue_handler = rescue_statements[method_name][rescue_exception]
                rescue_handler.arity != 0 ? rescue_handler.call(ex) : rescue_handler.call
              end
              exception_handled = true
              break
            end
          end

          raise ex unless exception_handled
        end
      end
    end
  end
end
rescue_any(exception_klass, options = {}) click to toggle source

Rescue exceptions raised by an object’s instance methods.

rescue_any receives an exception class, and a trailing hash containing a on: option listing one or more method names to apply the rescue to, and a with: option containing a code block for handling the exception.

The handling block can receive either zero or one argument, in the latter, it will be passed the rescued exception.

class RemoteUser
  include RescueAny

  rescue_any RuntimeError, on: [:create, :update, :delete], with: lambda {|ex| puts 'ohoh: ' + ex.message }

  def create
    raise RuntimeError.new("raised by #create")
  end

  def update
    raise RuntimeError.new("raised by #update")
  end

  def delete
    raise RuntimeError.new("raised by #delete")
  end
end

Exceptions raised inside the handler are not caught and will propogate up to the client class.

# File lib/rescue_any.rb, line 46
def rescue_any(exception_klass, options = {})

  unless exception_klass.is_a?(Class) && exception_klass <= Exception
    raise ArgumentError.new('First argument must be an Exception or sub-class of Exception')
  end

  unless options[:with]
    raise ArgumentError.new('Expected a handler, supply an option hash that as :with key as an argument')
  end

  method_block = options[:with]
  method_names = [options.fetch(:on, [])].flatten

  method_names.each do |method_name|
    rescue_statements[method_name] ||= {}
    rescue_statements[method_name][exception_klass] = method_block
  end
end