1

モジュールを使用するNokogiriを拡張するために「HTML」というクラスを定義しようとしています。

私は次のことを試しました:

require 'nokogiri'

class HTML
    include Nokogiri
end

require 'nokogiri'

class HTML
    extend Nokogiri
end

しかし、これまでのところ、クラスHTMLがnokogiriのすべての関数を継承することは不可能でした。したがって、次のようなものは機能していません。

doc = HTML.new
doc.HTML(open('http://www.google.com/search?q=tenderlove'))

#の未定義のメソッド `HTML'(NoMethodError)

モジュールのすべてのメソッドを継承するクラスをプログラムする方法を知っている人はいますか?

4

1 に答える 1

10

Nokogiri には、継承するインスタンス メソッドがありません。

irb> Nokogiri.instance_methods
#=>  []

しかし、通常は、extend

% ri 拡張
-------------------------------------------------- -------- オブジェクト#拡張
     obj.extend(モジュール、...) => obj
-------------------------------------------------- ----------------------
     として指定された各モジュールのインスタンス メソッドを obj に追加します。
     パラメータ。

        モジュールモッド
          デフハロー
            「Mod からこんにちは。\n」
          終わり
        終わり

        クラス クラス
          デフハロー
            「クラスからこんにちは。\n」
          終了 終了

        k = クラス.新しい
        k.hello #=> "クラスからこんにちは。\n"
        k.extend(Mod) #=> #<クラス:0x401b3bc8>
        k.hello #=> "モッズからこんにちは\n"

%

やりたいことは、Nokogiri モジュールのすべてのクラス メソッドをクラスのインスタンス メソッドとして使用することです。これは少し非標準であるため、構文でサポートされていません。ほとんどのプログラマーはシングルトン パターンに ruby​​ モジュールを使用します。ノコギリは 1 つだけあればよいので、他のものはそのメソッドを使用できないはずです。

これを回避するために UndefinedMethods をハッキングすることもできますが、Nokogiri のバックエンドにコンパイル済みコードがあることを考えると、未定義のバグが発生する可能性があります。

通話を Nokogiri に転送できないと言っているわけではありません。

# nokogiri_wrapper.rb
require 'rubygems'
require 'nokogiri'

class NokogiriWrapper
  def method_missing(meth, *args, &blk)
    puts "call for #{meth.inspect}, #{args}, #{blk ? "with block" : "and no block"}"
    if Nokogiri.methods.include? meth.to_s
      puts "forwarding to Nokogiri"
      Nokogiri.send(meth, *args, &blk)
    else
      puts "falling back to default behaviour"
      super
    end
  end
end

html = "<html></html>"

puts "calling Nokogiri directly"
p Nokogiri.HTML(html)

wrapper = NokogiriWrapper.new

puts "calling Nokogiri through wrapper"
p wrapper.HTML(html)

puts "calling non-Nokogiri method with wrapper"
p(begin
    wrapper.scooby_dooby_doo!
  rescue NoMethodError => e
    [e.message, e.backtrace]
  end)
% ruby​​ nokogiri_wrapper.rb
のこぎりに直接電話する
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html></html>

ラッパーを介して Nokogiri を呼び出す
:HTML、<html></html> の呼び出し、およびブロックなし
ノコギリに転送
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html></html>

ラッパーで Nokogiri 以外のメソッドを呼び出す
:scooby_dooby_doo! の呼び出し、ブロックなし
デフォルトの動作にフォールバックする
["未定義メソッド `scooby_dooby_doo!' for #<NokogiriWrapper:0x581f74>", ["nokogiri_wrapper.rb:12:in `method_missing'", "nokogiri_wrapper.rb:29"]]

これは、ruby で委任パターンを実装する 1 つの方法です (別の方法は、Delegator クラスの 1 つを使用することです)。

于 2009-07-01T03:54:46.660 に答える