Руби, как вызывать метод только тогда, когда объект не ноль - PullRequest
2 голосов
/ 17 октября 2011

Я пишу простой скрипт, который извлекает детали некоторых пакетов с сайта Debian.Я сталкиваюсь с проблемой при работе с виртуальными пакетами, которые не имеют никакой версии, связанной с ними.

Я получаю следующее сообщение об ошибке

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

Строка виновника:

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

Я пытался поместить его в условное выражение, подобное этому, но это не сработало.

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

Ответы [ 4 ]

9 голосов
/ 06 января 2016

В Ruby 2.3.0 добавлен безопасный оператор навигации (&.), который проверяет nil перед вызовом метода.

foo&.bar

Возвращается nil, если foo равно nil, вместо повышения NoMethodError.

3 голосов
/ 17 октября 2011

Зависит от того, что возвращается nil doc.css('#content h1') или doc.css('#content h1').text или doc.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

Вы можете включить надлежащее условие в условие "исключение".

Из вашего исключения doc.css('#content h1').text.strip.scan( /\(([^>]*)\)/).last кажется нулевым. Так что вы можете проверить это.

2 голосов
/ 17 октября 2011

Вы использовали try?

Что-то вроде

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.

Просто к сведению: я знаю, что это не относится к вашему вопросу, но, возможно, методы цепочки этоlong без проверок на null между ними, вероятно, очень-очень сильно связывается со структурой документа ввода.Что делать, если .css ("# content h1"). Text равен нулю?

0 голосов
/ 12 мая 2014

Используйте

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

...