使用外部gem时捕获异常

时间:2013-05-09 01:45:50

标签: ruby twitter gem rescue

我编写了一个利用外部红宝石宝石的程序。由于我正在做很多不同的操作,我希望能够全面挽救和处理异常,而不是每次调用方法时都实现异常。

最好的方法是什么?
我应该编写自己的方法,只需调用外部gem并同时解救异常吗?或者是否有另一种方法可以执行“每当程序中的任何地方出现此类异常时,以这种方式处理它”?

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

1 个答案:

答案 0 :(得分:1)

对此的基本答案可能是包装你正在使用的课程; Ruby具有很大的灵活性,因为它具有method_missing和非常动态的类环境。这是一个例子(可能存在或可能没有致命缺陷,但证明了原则:

# 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类,或者你想要包装的东西更具体的东西将在很大程度上取决于上下文和具体问题你我正在寻求解决。