2013-05-09 66 views
0

我写了一个使用外部宝石红宝石的程序。由于我对此采取了许多不同的行动,因此我希望能够全方位地拯救和处理异常情况,而不是每次调用方法时都实施它。使用外部宝石时捕捉异常

这样做的最好方法是什么?
我应该写我自己的方法,只是简单地调用外部宝石,也拯救异常?还是有另一种方式来做类似“当这种类型的异常出现在程序中的任何地方,这样处理”?

我知道,如果我写了外部宝石代码,我可以添加像这样的错误处理,但这是不可行的。

回答

1

对此的基本答案可能是包装您正在使用的课程;由于Ruby具有method_missing和一个非常动态的类环境,因此Ruby为此提供了很大的灵活性。下面是一个例子(这可能会或可能不会是致命的缺陷,但是它展示了一个道理:

# A Foo class that throws a nasty exception somewhere. 
class Foo 
    class SpecialException < Exception; end 

    def bar 
    raise SpecialException.new("Barf!") 
    end 
end 

# This will rescue all exceptions and optionally call a callback instead 
# of raising. 
class RescueAllTheThings 
    def initialize(instance, callback=nil) 
    @instance = instance 
    @callback = callback 
    end 

    def method_missing(method, *args, &block) 
    if @instance.respond_to? method 
     begin 
     @instance.send(method, *args, &block) 
     rescue Exception => e 
     @callback.call(e) if @callback 
     end 
    else 
     super 
    end 
    end 
end 

# A normal non-wrapped Foo. Exceptions will propagate. 
raw_foo = Foo.new 

# We'll wrap it here with a rescue so that we don't exit when it raises. 
begin 
    raw_foo.bar 
rescue Foo::SpecialException 
    puts "Uncaught exception here! I would've exited without this local rescue!" 
end 

# Wrap the raw_foo instance with RescueAllTheThings, which will pass through 
# all method calls, but will rescue all exceptions and optionally call the 
# callback instead. Using lambda{} is a fancy way to create a temporary class 
# with a #call method that runs the block of code passed. This code is executed 
# in the context *here*, so local variables etc. are usable from wherever the 
# lambda is placed. 
safe_foo = RescueAllTheThings.new(raw_foo, lambda { |e| puts "Caught an exception: #{e.class}: #{e.message}" }) 

# No need to rescue anything, it's all handled! 
safe_foo.bar 

puts "Look ma, I didn't exit!" 

是否有意义使用的包装类的一个非常通用的版本,如RescueAllTheThings级以上,或更多的东西具体到你要包装的东西将取决于上下文和你正在寻求解决的具体问题。