2009-07-01 13 views
1

"HTML"と呼ばれるクラスを定義しようとしています Nokogiri - モジュールを使用しています。Ruby:モジュールを拡張するクラス

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

require 'nokogiri' 

class HTML 
    include Nokogiri 
end 

require 'nokogiri' 

class HTML 
    extend Nokogiri 
end 

これまでのところ、それは鋸山内のすべての関数のクラスHTMLを継承することを不可能となっています。だから、働いていないようなもの:

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

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

のためには、誰もが、私は、モジュールのすべてのメソッドを継承するクラスをプログラムするために管理することができる方法を知っていますか?

答えて

10

鋸山を継承するために、任意のインスタンスメソッドを持っていない:

irb> Nokogiri.instance_methods 
#=> [] 

しかし、通常、あなたが何をしたいのかextend

 
% ri extend 
---------------------------------------------------------- Object#extend 
    obj.extend(module, ...) => obj 
------------------------------------------------------------------------ 
    Adds to obj the instance methods from each module given as a 
    parameter. 

     module Mod 
      def hello 
      "Hello from Mod.\n" 
      end 
     end 

     class Klass 
      def hello 
      "Hello from Klass.\n" 
      end  end 

     k = Klass.new 
     k.hello   #=> "Hello from Klass.\n" 
     k.extend(Mod) #=> #<Klass:0x401b3bc8> 
     k.hello   #=> "Hello from Mod.\n" 

% 

を使用するには、鋸山のすべてのクラスのメソッドを使用していますモジュールをクラスのインスタンスメソッドとして使用します。これは少し非標準的なものなので、シンタックスはそれをサポートしていません。ほとんどのプログラマは、シングルトンパターンにはルビモジュールを使用しています.Nokogiriは1つだけ必要なので、他のものはそのメソッドを使用できません。

これを回避するには、UndefinedMethodsを使っていくつかのハッキングを行うことができますが、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 
calling Nokogiri directly 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> 
<html></html> 

calling Nokogiri through wrapper 
call for :HTML, <html></html>, and no block 
forwarding to Nokogiri 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> 
<html></html> 

calling non-Nokogiri method with wrapper 
call for :scooby_dooby_doo!, , and no block 
falling back to default behaviour 
["undefined method `scooby_dooby_doo!' for #<NokogiriWrapper:0x581f74>", ["nokogiri_wrapper.rb:12:in `method_missing'", "nokogiri_wrapper.rb:29"]] 

これはRubyで委任パターンを実装する1つの方法である(別の方法は、委任者のいずれかを使用することですクラス)。

+0

ありがとうございました。 – Benjamin