How to rescue all exceptions under a certain namespace?

Here is a more generic solution, in the case you wanted to rescue some Errno types and not others.

Create a custom module to be included by all the error classes we want to rescue

module MyErrnoModule; end

Customize this array to your liking, up to the "each" call.

Errno.constants.map {|name|
  Errno.const_get(name)
}.select{|const|
  Class === const
}.uniq.each {|klass|
  klass.class_eval {
    include MyErrnoModule
  }
}

Test:

begin
  raise Errno::EPERM
rescue MyErrnoModule
  p "rescued #{$!.inspect}"
end

Test result:

"rescued #<Errno::EPERM: Operation not permitted>"

I would guess this performs slightly better than a solution that needs to check the name of the exception.


Here is another interesting alternative. Can be adapted to what you want.

Pasting most interesting part:

def match_message(regexp)
  lambda{ |error| regexp === error.message }
end

begin
  raise StandardError, "Error message about a socket."
rescue match_message(/socket/) => error
  puts "Error #{error} matches /socket/; ignored."
end

See the original site for ruby 1.8.7 solution.

It turns out lambda not accepted my more recent ruby versions. It seems the option is to use what worked in 1.8.7 but that's IM slower (to create a new class in all comparisons. So I don't recommend using it and have not even tried it:

def exceptions_matching(&block)
  Class.new do
    def self.===(other)
      @block.call(other)
    end
  end.tap do |c|
    c.instance_variable_set(:@block, block)
  end
end

begin
  raise "FOOBAR: We're all doomed!"
rescue exceptions_matching { |e| e.message =~ /^FOOBAR/ }
  puts "rescued!"
end

If somebody knows when ruby removed lambda support in rescue please comment.


All classes under Errno are subclasses of SystemCallError. And all subclasses of SystemCallError are classes under Errno. The 2 sets are identical, so just rescue SystemCallError. This assumes that you're not using an external lib that adds to one and not the other.

Verify the identity of the 2 sets (using active_support):

Errno.constants.map {|name|
  Errno.const_get(name)
}.select{|const|
  Class === const
}.uniq.map(&:to_s).sort ==
    SystemCallError.subclasses.map(&:to_s).sort

This returns true for me.

So, applied to your example:

begin
  # my code
rescue SystemCallError
  # handle exception
end

All the Errno exceptions subclass SystemCallError:

Module Errno is created dynamically to map these operating system errors to Ruby classes, with each error number generating its own subclass of SystemCallError. As the subclass is created in module Errno, its name will start Errno::.

So you could trap SystemCallError and then do a simple name check:

rescue SystemCallError => e
  raise e if(e.class.name.start_with?('Errno::'))
  # do your thing...
end