使用救援并确保代码中间

时间:2016-03-09 18:18:32

标签: ruby error-handling rescue

Ruby的新手 - 我已经看过一些似乎相似的问题的答案,但说实话,我无法理解他们。

我有一些代码可以读取.csv文件。数据被分成每个用户记录40-50行的组,并根据通过网站访问的数据库验证行中的数据。

每条记录都需要登录,但是一旦该用户登录了.csv文件中的每一行,就可以检查到达下一个用户,此时用户退出。

但是,如果发生错误(例如,网站上的结果与.csv文件上的预期结果不同),程序将停止工作。

我需要的东西会 a)告诉我文件中哪一行发生了错误 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

2 个答案:

答案 0 :(得分:1)

您似乎需要一些错误记录,因为您显然不知道您接收的错误类型或位置。如果此脚本是独立的,您可以将$stderr重定向到文件,以便您可以阅读出错的地方。

# put this line at the top of your script
$stderr = File.open("/path/to/your/logfile.log","a")

当发生错误时,ruby会自动将错误消息,类和回溯写入您指定的日志文件,以便您可以追溯事情未按预期进行的行。 (当您从命令行运行脚本时,通常此信息将在发生错误时脱口回到终端。)

例如,在我的桌面上,我创建了一个文件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,因为这会影响环境中运行的所有其他内容。 ($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

我希望这有帮助!

答案 1 :(得分:0)

这似乎不需要在这里拯救异常。但你可以做的是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
...

并且您可以制作自己的自定义错误,并仅拯救某种类型,以便您不会悄悄地挽救其他错误。