【问题标题】:Can you pass a block of code that returns an error to a method?你能传递一个返回错误的代码块给一个方法吗?
【发布时间】:2017-03-28 16:03:23
【问题描述】:

我经常发现自己要处理这些情况:

require 'nokogiri'
require "open-uri"

url = "https://www.random_website.com/contains_info_I_want_to_parse"
nokodoc = Nokogiri::HTML(open(url))
# Let's say one of the following line breaks the ruby script
# because the element I'm searching doesn't contain an attribute.
a = nokodoc.search('#element-1').attribute('href').text
b = nokodoc.search('#element-2').attribute('href').text.gsub("a", "A")
c = nokodoc.search('#element-3 h1').attribute('style').text.strip

我将创建大约 30 个变量来搜索页面中的不同元素,并且我将在多个页面上循环该代码。但是,其中一些页面的布局可能略有不同,并且不会有其中一个 div。这将破坏我的代码(例如,因为您不能在 nil 上调用 .attribute 或 .gsub )。但我永远无法事先猜到哪一行。 我的首选解决方案通常是在每一行周围加上:

begin
  line #n
rescue
  puts "line #n caused an error"
end

我希望能够做类似的事情:

url = "https://www.random_website.com/contains_info_I_want_to_parse"
nokodoc = Nokogiri::HTML(open(url))

catch_error(a, nokodoc.search('#element-1').attribute('href').text)
catch_error(b, nokodoc.search('#element-2').attribute('href').text.gsub("a", "A"))
catch_error(c, nokodoc.search('#element-3 h1').attribute('style').text.strip)

def catch_error(variable_name, code)
  begin
    variable_name = code
  rescue
    puts "Code in #{variable_name} caused an error"
  end
  variable_name
end

我知道在每个新方法之前加上 & 是有效的:

nokodoc.search('#element-1')&.attribute('href')&.text

但我希望能够在我的终端中使用“puts”来显示错误,以查看我的代码何时出现错误。

有可能吗?

【问题讨论】:

    标签: ruby methods error-handling nokogiri rescue


    【解决方案1】:

    您不能将 code 作为常规参数传递给方法,因为它会在传递给您的 catch_error 方法之前被评估(并引发异常)。你可以将它作为一个块传递——类似于

    a = catch_error('element_1 href text') do 
      nokodoc.search('#element-1').attribute('href').text
    end
    
    def catch_error(error_description)
      yield
    rescue
      puts "#{error_description} caused an error"
    end
    

    请注意,您不能将a 作为variable_name 传递给该方法:在调用该方法之前尚未在任何地方定义它,因此您将收到undefined local variable or method 错误。即使您之前定义了a,它也无法正常工作。如果您的代码在没有引发异常的情况下工作,则该方法将返回正确的值,但该值不会存储在方法范围之外的任何地方。如果出现异常,variable_name 将具有 a 在方法之前的任何值(nil,如果您在未设置的情况下定义它),因此您的错误消息将输出类似 Code in caused an error 的内容。这就是我添加error_description 参数的原因。

    如果您不想每次都指定错误描述,也可以尝试记录消息和回溯。

    a = catch_error(nokodoc) do |doc|
      doc.search('#element-1').attribute('href').text
    end
    
    def catch_error(doc)
      yield doc
    rescue => ex
      puts doc.title # Or something else that identifies the document
      puts ex.message
      puts ex.backtrace.join("\n")
    end
    

    我在此处进行了一项额外更改:将文档作为参数传入,以便rescue 可以轻松记录识别文档的内容,以防万一。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-07
      • 2010-12-29
      • 1970-01-01
      相关资源
      最近更新 更多