【问题标题】:Ruby how to call a method only when the object is not nilRuby如何仅在对象不为零时调用方法
【发布时间】:2011-12-09 02:22:40
【问题描述】:

我正在编写一个简单的脚本,它从 debian 网站获取一些软件包的详细信息。在处理没有与之关联的版本的虚拟包时,我遇到了一个问题。

我收到以下错误消息

undefined method `first' for nil:NilClass (NoMethodError)

罪魁祸首是

version = doc.css('#content h1').text.strip.scan( /\(([^>]*)\)/).last.first

我尝试将它放入这样的 if 条件中,但这不起作用。

if doc.css('#content h1').text 
         version = doc.css('#content h1').text.strip.scan( /\(([^>]*)\)/).last.first
      end

所以我想知道如何检查对象是否不为零,然后尝试从中提取子字符串。

这是添加了除非块的整个脚本

require 'rubygems'
require 'nokogiri'
require 'open-uri'


# additional code to make sure that we can resume after a break seamlessly
last_package = 0
File.open('lastbreak','r') { |fptr| last_package = fptr.gets.to_i }
puts "Resuming from package:#{last_package}" if last_package != 0

# to read each package from packageslist.txt and fetch the required info
# also to store this into a file that can easily be read by the c++ program
BASE_URL = "http://packages.debian.org/stable/"

File.open('packages_list.txt','r') do | fptr |
  while line = fptr.gets
    package_id = line.split[0].to_i
    package = line.split[1]
    dependencies = ""
    url = BASE_URL + package
    if package_id >= last_package
      doc = doc = Nokogiri::HTML(open(url))
      doc.css(".uldep a").each do |dependency|
        dependencies << dependency.text + ","
      end
      dependencies = dependencies.split(',').uniq.join(',')
      description = doc.css('#pdesc').text.strip
      version = ""
      unless doc.css('#content h1').nil?
          version = doc.css('#content h1').text.strip.scan( /\(([^>]*)\)/).last.first
      end

      File.open("packages/#{package}","w") do |wfptr|
      wfptr.puts "PackageId:#{package_id}"
      wfptr.puts "Name:#{package}"
      wfptr.puts "Version:#{version}"
      wfptr.puts "Deps:#{dependencies}"
      end
      File.open("packages/#{package}.description",'w') {|wf| wf.write(description.capitalize)}

      package_id += 1
      puts "Now Processing #{package_id}"
      File.open('lastbreak','w') { |fptr| fptr.puts "#{package_id}" }
    end
  end
end

现在错误信息是

/Users/ccuser008/Documents/oops_project/repo/repobuilder.rb:30:in `block': undefined method `first' for nil:NilClass (NoMethodError)
    from /Users/ccuser008/Documents/oops_project/repo/repobuilder.rb:15:in `<main>'

【问题讨论】:

标签: ruby methods undefined null


【解决方案1】:

取决于返回的内容 nil doc.css('#content h1')doc.css('#content h1').textdoc.css('#content h1').text.strip.scan( /\(([^&gt;]*)\)/).last

示例 -

unless doc.css('#content h1').text.strip.scan( /\(([^>]*)\)/).last.nil?
    version = doc.css('#content h1').text.strip.scan( /\(([^>]*)\)/).last.first
end

您可以在 unless 子句中包含适当的条件。

从你的例外doc.css('#content h1').text.strip.scan( /\(([^&gt;]*)\)/).last 看来是零。所以你可以检查一下。

【讨论】:

  • 你检查了什么 nil ?检查 doc.css('#content h1').text.strip.scan( /(([^>]*))/).last.nil?因为这是它似乎正在打破的重点。
  • 一个建议!如果您打算花费 CPU 周期来完成整个 doc.css.text.strip.scan.last dance .. 为什么不将结果存储在一个变量中,这样您就可以检查它是否为空,然后首先应用到该变量再次进行整个链式方法调用? :)
【解决方案2】:

你用过吗?

有点像

doc.css('#content h1').text.strip.scan( /\(([^>]*)\)/).last.try(:first)

如果您在项目中包含 active_support 或在 Rails 应用程序中工作,这将起作用。

查找“try”方法的语法和文档。

更新:

x = doc.css('#content h1').text.strip.scan( /\(([^>]*)\)/).last
version = x.first if !x.nil? # why bother.

仅供参考:我知道这并不真正适用于您的问题,但也许链接方法这么长而不检查两者之间的 null 可能非常难以耦合到输入的文档结构。如果 .css("#content h1").text 为空怎么办?

【讨论】:

  • 我没有使用 Rails,只是一个简单的脚本来从 debian repos 中获取包的详细信息。
【解决方案3】:

使用

try(method, *args, &block)

在你的情况下:

doc.css('#content h1').text.strip.scan( /\(([^>]*)\)/).last.try(:first)

更多信息见:

http://www.intridea.com/blog/2010/11/2/calling-methods-on-potential-nil-objects-in-rails

【讨论】:

    【解决方案4】:

    Ruby 2.3.0 添加了一个安全导航运算符 (&amp;.),它在调用方法之前检查 nil。

    foo&.bar
    

    如果foonil,它将返回nil,而不是提高NoMethodError

    【讨论】:

    • 这正是我想要的。相当于 Swift 的 foo?.bar :) 谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-06
    相关资源
    最近更新 更多