Domanda

Sto cercando di definire una classe denominata "HTML" per estendere Nokogiri -., Che utilizza moduli

Ho provato quanto segue:

require 'nokogiri'

class HTML
    include Nokogiri
end

e

require 'nokogiri'

class HTML
    extend Nokogiri
end

ma finora è stato impossibile che la classe HTML eredita di tutte le funzioni in nokogiri. Quindi, cose del genere non funzionano:

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

metodo non definito `HTML' per # (NoMethodError)

Qualcuno sa come potrei riuscire a programmare una classe che eredita di tutti i metodi di un modulo?

È stato utile?

Soluzione

Nokogiri non ha metodi di istanza di ereditare:

irb> Nokogiri.instance_methods
#=>  []

Ma normalmente, si può usare 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"

%

Che cosa si vuole fare è utilizzare tutti i metodi della classe del modulo Nokogiri come metodi della classe di istanza. Che è un po 'non standard, che è il motivo per cui la sintassi non lo supporta. La maggior parte dei programmatori utilizzano moduli rubino per il pattern Singleton -. Ci deve essere solo uno Nokogiri, quindi l'altro non dovrebbe essere in grado di utilizzare i suoi metodi

Si potrebbe fare un po 'di hacking con UndefinedMethods per aggirare il problema, ma considerando che Nokogiri ha qualche codice compilato nel backend, questo può produrre errori indefiniti.

Non vale a dire non si può chiamate l'ora di 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"]]

Questo è un modo per implementare il modello delegante in rubino (un altro modo è quello di utilizzare una delle classi Delegator).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top