我想要执行 10 个 Ruby 函数调用,每个调用都可能抛出异常。我想以相同的方式处理每个异常并继续。有没有办法做到这一点,而不将每一行包装在
begin
... rescue
... end
块中?
[编辑]:此用例是一个屏幕抓取/自动化工具,它使用 Selenium Web 驱动程序来填写表单。我不想费心检查选择元素中的选项是否存在,只需尽可能地填写它们即可。为此,我需要调用
Selenium::WebDriver::Support::Select.select_by
并在抛出“无法找到值为 x 的选项”异常时继续。
我找到了这个答案,它也能满足我的要求:
def action
yield
rescue
....
ensure
....
end
action { call1 }
action { call2 }
action { call3 }
你的意思是这样的吗?
class Wtf
def f1
raise "f1"
end
def f2
raise "f2"
end
end
obj= Wtf.new
[:f1, :f2].each do |f|
begin
obj.send f
rescue Exception=> e
p e
end
end
编辑:向示例添加更多代码
我喜欢 qwned 的 #send 方法,但对于并非所有方法都按顺序调用的情况来说,它并不理想。
Continuations 非常适合这类事情:
require 'continuation'
class Continuer
# Define five methods for testing
(1..5).each { |i| define_method("method#{i}") { puts "method#{i} called" } }
def do_these_things
cc = nil
callcc { |c| cc = c; method1; }
callcc { |c| cc = c; method2; raise }
# Do other things right here, maybe...
callcc { |c| cc = c; method3; raise }
callcc { |c| cc = c; method4; }
callcc { |c| cc = c; method5; }
rescue
puts 'Caught exception. Continuing.'
cc.call
end
end
Continuer.new.do_these_things
这是通过在执行每个容易失败的方法时在“cc”变量中记录延续来实现的。 然后救援声明就简单地继续下去。 这有点像带有动态标签的 goto 语句。
你可以这样做:
begin
do_something
do_something_else
do_do_do
rescue Exception1 => e
# error handling
rescue Exception2 => e
# error handling
如果 do_something 抛出异常,则其他调用将不会被调用。我认为这比做很多
begin.. rescue
块更好。只需处理不同的异常即可。
def f1; raise "X"; end
def f2; raise "Y"; end
#...
funcList = [:f1,:f2,...]
funcList.each{|f|
begin
send(f)
rescue Exception => e
#handle
end
}