布尔方法在不同情况下不返回 [RUBY]

Boolean method not returning in different situations [RUBY]

我正在构建一个简单的网络抓取工具(从 indeed.com 抓取工作)用于练习,我正在尝试实现以下方法 (low_salary?(salary))。该方法的目的是比较最低(即期望)薪水,将其与工作对象(@salary)中包含的提供薪水进行比较:

class Job

  attr_reader :title, :company, :location, :salary, :url

  def initialize(title, company, location, salary, url)
    @title = title
    @company = company
    @location = location
    @salary = salary
    @url = url
  end

  def low_salary?(minimum_salary)
    return if !@salary

    minimum_salary < @salary.split(/[^\d]/)[1..2].join.to_i
  end

end

当comapring @salary 和给它的min_salary 变量时,该方法工作正常,delete_if 适当地删除return 对low_salary 正确的元素?并且 returns 在@salary 为 nil 时正确(实际上列表并不总是包括薪水,所以我的假设是会有一些 nil 值)在以下测试程序中(另外:我不确定为什么 minimum_salary < @salary 有效,但 @salary < minimum_salary 无效,但这正是我想要的):

require_relative('job_class.rb')
job = Job.new("designer", "company", "location", "£23,000 a year", "url")
job_results = []
job_results.push(job)

min_salary = 50000

print job.low_salary?(min_salary)

job_results.delete_if { |job| job.low_salary?(min_salary) }

print job_results

但是在我的抓取程序中,调用方法时出现无方法错误:job_class.rb:16:in "low_salary?": undefined method `join' for nil:NilClass (NoMethodError)

require 'nokogiri'
require 'open-uri'
require_relative 'job_class.rb'

class JobSearchTool

  def initialize(job_title, location, salary)
    @document = Nokogiri::HTML(open("https://uk.indeed.com/jobs?q=#{job_title.gsub('-', '+')}&l=#{location}"))
    @job_listings = @document.css('div.mosaic-provider-jobcards > a')
    @salary = salary.to_i
    @job_results = []
  end

  def scrape_jobs
    @job_listings.each do |job_card|
        @job_results.push(Job.new(
          job_card.css('h2 > span').text, #title
          job_card.css('span.companyName').text, #company
          job_card.css('div.companyLocation').text, #location
          job_card.css('span.salary-snippet').text, #salary
          job_card['href']) #url
        )
    end
  end

  def format_jobs
    @job_results.each do |job|
      puts <<~JOB
        #{job.title} - #{job.company} in #{job.location} :#{job.salary}
        Apply at: #{job.url}
        ---------------------------------------------------------------------------------
      JOB
    end
  end

  def check_salary
    @job_results.delete_if { |job| job.low_salary?(@salary) }
  end
  
  def run
    scrape_jobs

    check_salary

    format_jobs
  end

if __FILE__ == [=13=]
  job_search_tool = JobSearchTool.new(ARGV[0], ARGV[1], ARGV[2])
  job_search_tool.run
end

显然,抓取程序中的某些内容以某种方式影响了该方法,但我不明白它可能是什么。我以与测试程序完全相同的方式使用该方法,那么当@salary 为 nil 时导致该方法不 return 的区别是什么?

快速搜索您正在抓取的 URL 显示有没有薪水的职位发布,因此,当您从该 HTML 元素获取数据并初始化一个新的 Job 对象,薪水是一个空字符串,并且知道 "".split(/[^\d]/)[1..2] returns nil,这就是你得到的错误。

您必须添加一种方法来处理没有薪水的招聘职位:

class Job
  attr_reader :title, :company, :location, :salary, :url

  def initialize(title, company, location, salary, url)
    @title = title
    @company = company
    @location = location
    @salary = salary.to_s # Explicit conversion of nil to string
    @url = url
  end

  def low_salary?(minimum_salary)
    return if parsed_salary.zero? # parsed_salary returns always an integer,
                                  # so you can check when is zero,
                                  # and not just when is falsy

    minimum_salary < parsed_salary
  end

  private

  def parsed_salary
    salary[/(?<=£)(\d|,)*(?=\s)/]
      .to_s        # converts nil to "" if the regex doesn't capture anything
      .tr(",", "") # removes the commas to parse the string as an integer
      .to_i        # parses the string to its corresponding integer representation
  end
end

请注意,正则表达式并不意味着捕获所有内容,但它适用于网站中呈现的薪水。