Ruby // Nokogiri 尝试将各种对象的选择器存储在哈希中

Ruby // Nokogiri trying to store selectors for various objects in a hash

我正在尝试将选择器存储在分配给适当主题的哈希中,然后我将从网页上抓取这些主题。但是,当我这样做时,我遇到了“css”方法的 'undefined method' 错误。

示例:

@@letters_hash = {
      "a" => {
         uppercase: "A",
         history: css('div.class_1').css('div.class_2').text,
         url: "www.alphabet.com"
      }
}

有没有办法封装这个?或者,如果我将它存储为字符串,是否有办法删除该字符串并将其返回给方法?

感谢您的宝贵时间。

css('div.class_1').css('div.class_2').textself.css('div.class_1').css('div.class_2').textself 是你的 Database class。它没有 css 方法。您需要在具有 css 方法的对象上调用该方法,例如 Nokogiri 节点。

回调

如果你想存储一组方法来调用你稍后会得到的一些 Nokogiri 节点,你可以 a callback using a little anonymous function called a lambda.

@letters = {
      "a" => {
         uppercase: "A",
         history: ->(node) { node.css('div.class_1').css('div.class_2').text },
         url: "www.alphabet.com"
      }
}

将节点作为参数并调用节点上的方法。

然后当你有一个节点时你可以调用这个函数。

@letters_hash[letter][:history].call(node)

对象

此时它已被编译,应该封装在一个对象中。

class LetterTopic
  def initialize(letter)
    @letter = letter
  end

  def node_history(node)
    node.css('div.class_1').css('div.class_2').text
  end

  def uppercase
    @letter.upcase
  end

  def url
    "www.alphabet.com"
  end
end

letters = {
  "a" => LetterTopic.new("a")
}

node = ...get a Nokogiri node...

letters[letter].node_history(node)

关于 Class 变量的注意事项

@@letters_hash并没有按照你的想法去做。 Class Ruby 中的变量由子class 共享。如果您子 class 数据库,它们将共享一个 @@letters_hash 变量。

class Database
  @@letters = {}

  def self.letters
    @@letters
  end
end

class Databasement < Database
end

Database.letters[:a] = 'database'
Databasement.letters[:a] = 'databasement'

p Database.letters     # {:a=>"databasement"}
p Databasement.letters # {:a=>"databasement"}

而是使用 Class 实例变量。与 Ruby 中的其他所有内容一样,数据库 class 是一个对象,可以拥有自己的实例变量。

class Database
  # Everything inside `class << self` works on the class object.
  class << self
    def letters
      @letters ||= {}
    end
  end
end

class Databasement < Database
end

Database.letters[:a] = 'database'
Databasement.letters[:a] = 'databasement'

p Database.letters       # {:a=>"database"}
p Databasement.letters   # {:a=>"databasement"}