Ruby捕获所有异常类

时间:2018-04-21 02:58:40

标签: ruby exception

如何在ruby类中捕获所有异常:

class ServiceException
rescue => e
   puts 'Error!!!'
end

class ServiceA < ServiceException
   def say_hello
      error_code_here
   end
end

ServiceA.new.say_hello
# => Error!!!

1 个答案:

答案 0 :(得分:3)

好的,所以我设法用一些元编程完成这个。首先定义这个模块:

module MetaprogrammingStuff

  def rescue_all_methods(klass, *errors_to_rescue, &blk)
    patch_all_methods(klass) do |orig_method, *args, &caller_blk|
      begin
        orig_method.call *args, &caller_blk
      rescue *errors_to_rescue => e
        blk.call e
      end
    end
  end

  def patch_all_methods(klass, &blk)
    patch_class_methods(klass, &blk)
    patch_instance_methods(klass, &blk)
  end

  def patch_class_methods(klass, &blk)
    klass.methods(false).each do |fn_name|
      orig_method = klass.method fn_name
      klass.singleton_class.send(:define_method, fn_name) do |*args, &caller_blk|
        blk.call orig_method, *args, &caller_blk
      end
    end
  end

  def patch_instance_methods(klass, &blk)
    klass.instance_methods(false).each do |fn_name|
      orig_method = klass.instance_method fn_name
      klass.send(:define_method, fn_name) do |*args, &caller_blk|
        blk.call orig_method.bind(self), *args, &caller_blk
      end
    end
  end

end

然后将其扩展到一个类并运行rescue_all_methods

class TestClass
  extend MetaprogrammingStuff
  def foo
    raise ArgumentError
  end
  def self.foo
    raise RuntimeError
  end
  rescue_all_methods(self, ArgumentError, RuntimeError) do |error|
    puts "#{error.class} was raised."
  end
end

在定义方法后调用rescue_all_methods很重要。

你可以看到它在所有实例和类方法周围插入一个救援块:

TestClass.foo
# => RuntimeError was raised.

TestClass.new.foo
# => ArgumentError was raised.

它是如何工作的 - 基本上它使用methodinstance_method方法将方法转换为匿名函数,然后将这些方法名称重新分配给调用原始方法但使用begin的新方法。救援包装。