我正在运行一个经常超时的 API 脚本。发生这种情况时,我正在使用begin/rescue
块来使其redo
,但希望在运行redo
命令之前记录命令行发生的情况。
begin
#...api query...
rescue ErrorClass
puts("retrying #{id}") && redo
end
不幸的是,上面的脚本不起作用。仅运行第一个命令。
我想强制救援块运行多行代码,如下所示:
begin
# api query
rescue ErrorClass do ###or:# rescue ErrorClass do |e|
puts "retrying #{id}"
redo
end
但这些也不起作用。
我很幸运地创建了一个单独的方法来运行,如下所示:
def example
id = 34314
begin
5/0
rescue ZeroDivisionError
eval(handle_zerodiv_error(id))
end
end
def handle_zerodiv_error(id)
puts "retrying #{id}"
"redo"
end
。这确实有效。但在我看来,它需要太多的代码行,并且它使用的 eval 根据我的导师的说法绝不是犹太洁食。
您使用&&
或do
使事情变得不必要地复杂化。&&
版本不起作用,因为puts
返回nil
,所以通过&&
的快捷方式求值,后面的部分不会被求值。如果您改用||
或;
,那么它将起作用:
begin
...
rescue ErrorClass
puts("retrying #{id}") || redo
end
begin
...
rescue ErrorClass
puts("retrying #{id}"); redo
end
但即使这样也没有必要。您似乎以某种方式认为您需要在rescue
内使用一个块来编写多行,但这没有意义,因为您没有使用单行块。没有 Ruby 构造仅在您有多条线时才需要一个块。因此,只需将它们放在多行中:
begin
...
rescue ErrorClass
puts("retrying #{id}")
redo
end
内置了一个retry
。这个例子来自"Ruby编程语言"第162页。
require "open-uri"
tries = 0
begin
tries +=1
open("http://www.example.com/"){|f| puts f.readlines}
rescue OpenURI::HTTPError => e
puts e.message
if (tries < 4)
sleep (2**tries) # wait for 2, 4 or 8 seconds
retry # and try again
end
end