在代码中间使用 rescue 和 ensure
Using rescue and ensure in the middle of code
Ruby 还是个新手 - 我看过一些看似相似问题的答案,但老实说,我无法理解它们。
我有一些读取 .csv 文件的代码。数据被分成每组 40-50 行的用户记录,并根据通过网站访问的数据库验证行中的数据。
每条记录都需要登录,但是一旦该用户登录,就可以检查 .csv 文件中的每一行,直到到达下一个用户,此时用户注销。
一切正常,但是,如果发生错误(例如,网站上的结果与 .csv 文件上的预期结果不同),程序将停止。
我需要一些东西
a) at 告诉我错误发生在文件的哪一行
b) 完成后记录要输出的行 运行,以及
iii) 从 .csv 文件的下一行重新启动程序
我目前的代码如下
提前致谢,
彼得
require 'csv-mapper'
loginrequired = true
Given(/^I compare the User Details from rows "(.*?)" to "(.*?)"$/) do |firstrow, lastrow|
data = CsvMapper.import('C:/auto_test_data/User Data csv.csv') do
[dln, nino, pcode, endor_cd, ct_cd]
end
#Row number changed because Excel starts at 'row 1' and Ruby starts counting at 'row 0'
(firstrow.to_i-1..lastrow.to_i-1).each do |row|
@licnum1 = data.at(row).dln
@licnum2 = data.at(row+1).dln
@nino = data.at(row).nino
@postcode = data.at(row).pcode
@endor_cd = data.at(row).endor_cd
@ct_cd = data.at(row).ct_cd
#Login only required once for each new user-account
if
loginrequired == true
logon_to_vdr #def for this is in hooks
click_on 'P and D'
loginrequired = false
end
#This is the check against the database and is required for every line in the .csv file
check_ctcd #def for this is in hooks
#Need something in here to log errors and move on to the next line in the .csv file
#Compare the ID for the next record and logout if they're different
if @licnum1 == @licnum2
loginrequired = false
else
loginrequired = true`enter code here`
click_on 'Logout'
end
end
end
这里好像不需要rescue exception。但是你可以做的是在你的 check_ctcd
方法中,如果记录不匹配则引发错误。然后你可以从中解救出来。为了知道它是哪一行,在你的迭代中,你可以使用 #each_with_index
并在出现问题时记录索引。
(firstrow.to_i-1..lastrow.to_i-1).each_with_index do |row, i|
@licnum1 = data.at(row).dln
@licnum2 = data.at(row+1).dln
@nino = data.at(row).nino
@postcode = data.at(row).pcode
@endor_cd = data.at(row).endor_cd
@ct_cd = data.at(row).ct_cd
#Login only required once for each new user-account
if
loginrequired == true
logon_to_vdr #def for this is in hooks
click_on 'P and D'
loginrequired = false
end
#This is the check against the database and is required for every line in the .csv file
check_ctcd #def for this is in hooks
rescue => e
# log the error and index here
...
而且你可以自定义错误,只拯救特定类型的错误,这样你就不会默默地拯救其他错误。
您似乎需要一些错误记录,因为您显然不知道收到的错误类型或位置。如果这个脚本是独立的,你可以重定向 $stderr
到文件,这样你就可以看到哪里出了问题。
# put this line at the top of your script
$stderr = File.open("/path/to/your/logfile.log","a")
发生错误时,ruby会自动写入错误信息,class,并回溯到您指定的日志文件,这样您就可以回溯到事情没有进展的那一行预期的。 (当你从命令行 运行 一个脚本时,通常这个信息会在错误发生时直接返回到终端。)
例如,我在桌面上创建了一个文件 log_stderr.rb,其中包含以下内容(包括行号):
1 $stderr = File.open("C:/Users/me/Desktop/my_log.log","w")
2
3 #require a file which will raise an error to see the backtrace
4 require_relative 'raise_error.rb'
5
6 puts "code that will never be reached"
同样在我的桌面上,我使用以下内容创建了文件 raise_error.rb(以加深回溯以获得更好的示例输出):
1 # call raise to generate an error arbitrarily
2 # to halt execution and exit the program.
3 raise RuntimeError, 'the program stopped working!'
当我从命令行 运行 ruby log_stderr.rb
时,会在我的桌面上创建 my_log.log,其中包含以下内容:
C:/Users/me/Desktop/raise_error.rb:3:in `<top (required)>': the program stopped working! (RuntimeError)
from C:/Users/me/Desktop/log_stderr.rb:4:in `require_relative'
from C:/Users/me/Desktop/log_stderr.rb:4:in `<main>'
如果您在更大的环境中工作,您的脚本在其他脚本中被调用,那么您可能不想重定向 $stderr
因为这会影响环境中的其他所有内容 运行ning . ($stderr
是全局的,如 $
变量前缀所示。)如果是这种情况,您可能希望实现 begin; rescue; end
结构并创建自己的日志文件,这样您就不会影响 $stderr
.
同样,由于您不知道错误发生在何处,您希望用 begin; end
包装整个脚本
# at the very top of the script, begin watching for weirdness
begin
logfile = File.open("/path/to/your/logfile.log", "w")
require 'csv-mapper'
#. . .
# rescue and end at the very bottom to capture any errors that have happened
rescue => e
# capture details about the error in your logfile
logfile.puts "ERROR:", e.class, e.message, e.backtrace
# pass the error along since you don't know what it is
# and there may have been a very good reason to stop the program
raise e
end
如果您发现您的错误只发生在块 (firstrow.to_i-1..lastrow.to_i-1).each do |row|
中,您可以将 begin; end
放在该块内以访问本地 row
变量,否则创建一个独立于块的顶级变量,并在块的每次迭代期间分配它以报告到您的日志文件:
begin
logfile = File.open("/path/to/your/logfile.log", "w")
csv_row = "before csv"
#. . .
(firstrow.to_i-1..lastrow.to_i-1).each do |row|
csv_row = row
#. . .
end
csv_row = "after csv"
rescue => e
logfile.puts "ERROR AT ROW: #{csv_row}", e.class, e.message, e.backtrace
raise e
end
希望对您有所帮助!
Ruby 还是个新手 - 我看过一些看似相似问题的答案,但老实说,我无法理解它们。
我有一些读取 .csv 文件的代码。数据被分成每组 40-50 行的用户记录,并根据通过网站访问的数据库验证行中的数据。
每条记录都需要登录,但是一旦该用户登录,就可以检查 .csv 文件中的每一行,直到到达下一个用户,此时用户注销。
一切正常,但是,如果发生错误(例如,网站上的结果与 .csv 文件上的预期结果不同),程序将停止。
我需要一些东西 a) at 告诉我错误发生在文件的哪一行 b) 完成后记录要输出的行 运行,以及 iii) 从 .csv 文件的下一行重新启动程序
我目前的代码如下
提前致谢,
彼得
require 'csv-mapper'
loginrequired = true
Given(/^I compare the User Details from rows "(.*?)" to "(.*?)"$/) do |firstrow, lastrow|
data = CsvMapper.import('C:/auto_test_data/User Data csv.csv') do
[dln, nino, pcode, endor_cd, ct_cd]
end
#Row number changed because Excel starts at 'row 1' and Ruby starts counting at 'row 0'
(firstrow.to_i-1..lastrow.to_i-1).each do |row|
@licnum1 = data.at(row).dln
@licnum2 = data.at(row+1).dln
@nino = data.at(row).nino
@postcode = data.at(row).pcode
@endor_cd = data.at(row).endor_cd
@ct_cd = data.at(row).ct_cd
#Login only required once for each new user-account
if
loginrequired == true
logon_to_vdr #def for this is in hooks
click_on 'P and D'
loginrequired = false
end
#This is the check against the database and is required for every line in the .csv file
check_ctcd #def for this is in hooks
#Need something in here to log errors and move on to the next line in the .csv file
#Compare the ID for the next record and logout if they're different
if @licnum1 == @licnum2
loginrequired = false
else
loginrequired = true`enter code here`
click_on 'Logout'
end
end
end
这里好像不需要rescue exception。但是你可以做的是在你的 check_ctcd
方法中,如果记录不匹配则引发错误。然后你可以从中解救出来。为了知道它是哪一行,在你的迭代中,你可以使用 #each_with_index
并在出现问题时记录索引。
(firstrow.to_i-1..lastrow.to_i-1).each_with_index do |row, i|
@licnum1 = data.at(row).dln
@licnum2 = data.at(row+1).dln
@nino = data.at(row).nino
@postcode = data.at(row).pcode
@endor_cd = data.at(row).endor_cd
@ct_cd = data.at(row).ct_cd
#Login only required once for each new user-account
if
loginrequired == true
logon_to_vdr #def for this is in hooks
click_on 'P and D'
loginrequired = false
end
#This is the check against the database and is required for every line in the .csv file
check_ctcd #def for this is in hooks
rescue => e
# log the error and index here
...
而且你可以自定义错误,只拯救特定类型的错误,这样你就不会默默地拯救其他错误。
您似乎需要一些错误记录,因为您显然不知道收到的错误类型或位置。如果这个脚本是独立的,你可以重定向 $stderr
到文件,这样你就可以看到哪里出了问题。
# put this line at the top of your script
$stderr = File.open("/path/to/your/logfile.log","a")
发生错误时,ruby会自动写入错误信息,class,并回溯到您指定的日志文件,这样您就可以回溯到事情没有进展的那一行预期的。 (当你从命令行 运行 一个脚本时,通常这个信息会在错误发生时直接返回到终端。)
例如,我在桌面上创建了一个文件 log_stderr.rb,其中包含以下内容(包括行号):
1 $stderr = File.open("C:/Users/me/Desktop/my_log.log","w")
2
3 #require a file which will raise an error to see the backtrace
4 require_relative 'raise_error.rb'
5
6 puts "code that will never be reached"
同样在我的桌面上,我使用以下内容创建了文件 raise_error.rb(以加深回溯以获得更好的示例输出):
1 # call raise to generate an error arbitrarily
2 # to halt execution and exit the program.
3 raise RuntimeError, 'the program stopped working!'
当我从命令行 运行 ruby log_stderr.rb
时,会在我的桌面上创建 my_log.log,其中包含以下内容:
C:/Users/me/Desktop/raise_error.rb:3:in `<top (required)>': the program stopped working! (RuntimeError)
from C:/Users/me/Desktop/log_stderr.rb:4:in `require_relative'
from C:/Users/me/Desktop/log_stderr.rb:4:in `<main>'
如果您在更大的环境中工作,您的脚本在其他脚本中被调用,那么您可能不想重定向 $stderr
因为这会影响环境中的其他所有内容 运行ning . ($stderr
是全局的,如 $
变量前缀所示。)如果是这种情况,您可能希望实现 begin; rescue; end
结构并创建自己的日志文件,这样您就不会影响 $stderr
.
同样,由于您不知道错误发生在何处,您希望用 begin; end
# at the very top of the script, begin watching for weirdness
begin
logfile = File.open("/path/to/your/logfile.log", "w")
require 'csv-mapper'
#. . .
# rescue and end at the very bottom to capture any errors that have happened
rescue => e
# capture details about the error in your logfile
logfile.puts "ERROR:", e.class, e.message, e.backtrace
# pass the error along since you don't know what it is
# and there may have been a very good reason to stop the program
raise e
end
如果您发现您的错误只发生在块 (firstrow.to_i-1..lastrow.to_i-1).each do |row|
中,您可以将 begin; end
放在该块内以访问本地 row
变量,否则创建一个独立于块的顶级变量,并在块的每次迭代期间分配它以报告到您的日志文件:
begin
logfile = File.open("/path/to/your/logfile.log", "w")
csv_row = "before csv"
#. . .
(firstrow.to_i-1..lastrow.to_i-1).each do |row|
csv_row = row
#. . .
end
csv_row = "after csv"
rescue => e
logfile.puts "ERROR AT ROW: #{csv_row}", e.class, e.message, e.backtrace
raise e
end
希望对您有所帮助!