2013-05-09 62 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級以上,或更多的東西具體到你要包裝的東西將取決於上下文和你正在尋求解決的具體問題。