在代码中间使用 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

希望对您有所帮助!