Ruby如何仅在对象不为nil时调用方法

发布于 2024-12-09 23:12:22 字数 2435 浏览 0 评论 0原文

我正在编写一个简单的脚本,它从 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

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

这是添加了 except 块的整个脚本

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>'

I'm writing a simple script, that fetches the details of some packages from the debian website. I encounter a problem when dealing with virtual packages that ave no version no associated with them.

I get the following error message

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

The culprit line is

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

I tried to put it into an if conditional like this but that doesn't work.

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

So I'd like to know how I can check if the object is not nil and then try to extract the sub-string from it.

Here is the entire script with the unless block added

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

now the error message is

/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>'

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

巴黎夜雨 2024-12-16 23:12:22

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

foo&.bar

如果 foonil,它将返回 nil,而不是引发 NoMethodError

Ruby 2.3.0 added a safe navigation operator (&.) that checks for nil before calling a method.

foo&.bar

It will return nil if foo is nil, rather than raising NoMethodError.

青芜 2024-12-16 23:12:22

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

示例 -

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

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

从你的异常 doc.css('#content h1').text.strip.scan( /\(([^>]*)\)/).last 似乎为零。所以你可以检查一下。

Depends what is being returned nil doc.css('#content h1') or doc.css('#content h1').text or doc.css('#content h1').text.strip.scan( /\(([^>]*)\)/).last

Example -

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

you can include the proper condition in the unless clause.

From your exception doc.css('#content h1').text.strip.scan( /\(([^>]*)\)/).last seems to be nil. So you can check on this.

差↓一点笑了 2024-12-16 23:12:22

你用过试试吗?

类似 This 的内容

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 为空怎么办?

Have you used try?

Something like

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

This will work if you're including active_support in your project or if you are working in a Rails app.

Lookup the syntax and documentation of the "try" method.

Updated:

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

Just FYI: I know this doesnt really apply to your question, but perhaps chaining methods this long without checks for null in between is probably coupling very very hard to the input's document structure. What if .css("#content h1").text is null?

巴黎盛开的樱花 2024-12-16 23:12:22

在您的情况下使用

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-pottial-nil-objects-in-rails

Use

try(method, *args, &block)

in your case:

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

For more info see:

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文