2009-07-01 103 views
1

我試圖去定義一個名爲「HTML」的類擴展 Nokogiri - 它使用模塊。Ruby:一個擴展模塊的類

我試過如下:

require 'nokogiri' 

class HTML 
    include Nokogiri 
end 

require 'nokogiri' 

class HTML 
    extend Nokogiri 
end 

但到目前爲止,它已經不可能在引入nokogiri所有功能的類HTML繼承。所以喜歡的東西不工作:

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

未定義的方法`HTML」爲#(NoMethodError)

有誰知道我是怎樣把程序模塊的所有方法是繼承的類?

回答

10

引入nokogiri沒有任何實例方法的繼承:

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的所有類的方法是什麼模塊作爲你的類的實例方法。這有點不標準,這就是語法不支持它的原因。大多數程序員在Singleton模式中使用ruby模塊 - 只需要一個Nokogiri,所以其他的東西不能使用它的方法。

你可以用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 
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中實現對被代理模式(另一種方法是使用代理方之一的一種方式類)。

+0

謝謝你。 – Benjamin 2009-07-01 05:12:59