如何在ruby类中捕获所有异常:
class ServiceException
rescue => e
puts 'Error!!!'
end
class ServiceA < ServiceException
def say_hello
error_code_here
end
end
ServiceA.new.say_hello
# => Error!!!
答案 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.
它是如何工作的 - 基本上它使用method
和instance_method
方法将方法转换为匿名函数,然后将这些方法名称重新分配给调用原始方法但使用begin的新方法。救援包装。