重构嵌套的救援语句

时间:2013-06-13 18:29:37

标签: ruby rescue

Rescue语句在连续过滤不同错误时效果很好:

o = Object.new
begin
  o.foo
rescue ArgumentError
  puts "Object o does define #foo, but you got the argument number wrong!"
rescue NoMethodError
  puts "Object o does not respond to #foo!"
else
  puts "That's right!"
end

但是当涉及用不同的参数挽救相同的错误时,这就是我在我的代码中使用的内容:

o = Object.new
begin
  o.foo
rescue NoMethodError
  begin
    o.bar
  rescue NoMethodError
    begin
      o.quux
    rescue NoMethodError
      warn "Object o responds not to basic methods!"
    end
  end
end

毋庸置疑,我不喜欢它。难道没有更聪明的方法吗?

2 个答案:

答案 0 :(得分:2)

可能这不回答你的问题,但在这种情况下,我会在调用之前询问o是否responds_to?我要调用的方法:

method = [:foo, :bar, :baz].find { |m| o.respond_to?(m) }
if method
  o.public_send(method)
else
  warn "Object o responds not to basic methods!"
end

答案 1 :(得分:1)

def send_messages_maybe(object, messages, *parameters)
  object.send(messages.first, *parameters)
rescue NoMethodError
  messages = messages[1..-1]
  if messages.empty?
    warn "Object does not respond to basic methods!"
  else
    retry
  end
end

module Quux
  def quux(*args)
    puts "quux method called with #{args.inspect}"
  end
end

messages = %i{foo bar quux}
send_messages_maybe(Object.new, messages)
send_messages_maybe(Object.new.extend(Quux), messages, 10, :hello, 'world')

输出:

Object does not respond to basic methods!
quux method called with [10, :hello, "world"]

这适用于没有定义#respond_to_missing?方法的对象,这很常见 - 我见过的大多数使用#method_missing的代码属于此类别。