2011-08-25 10 views
10

Sto creando una classe strana in cui voglio catturare tutti i metodi inviati a un oggetto della classe. Posso ottenere la maggior parte di ciò che voglio con method_missing, ad es.Ruby: cattura tutti i metodi inviati a un oggetto

class MyClass 
    def method_missing m, *args 
     # do stuff 
    end 
end 

Il problema è allora tutti i metodi di istanza MyClass eredita da Object. Potrei passare attraverso ogni metodo uno per uno e ridefinirli, ma speravo in un approccio più flessibile. Tutti i metodi di metaprogrammazione che ho provato si sono lamentati con un NameError quando provo a toccare quei metodi di istanza.

risposta

11

Come notato nei commenti e la risposta da @DanCheail, se stai usando Ruby 1.9+ dovresti usare un metodo BasicObject piuttosto che undefinire Object. Al momento di questo post, l'uso di 1.8.x era ancora abbastanza diffuso, anche se 1.9 era stato rilasciato per qualche tempo.


Piuttosto che tentare di "ridefinire" qualsiasi cosa, si potrebbe avvolgere il vostro oggetto in un oscurata (per la maggior parte) oggetto proxy, qualcosa di simile a:

class MyProxy 
    instance_methods.each do |meth| 
    # skipping undef of methods that "may cause serious problems" 
    undef_method(meth) if meth !~ /^(__|object_id)/ 
    end 

    def initialize(object) 
    @object = object 
    end  

    def method_missing(*args) 
    # do stuff 
    p args 
    # ... 
    @object.send(*args) 
    end 
end 

MyProxy.new(MyClass.new).whatever 
+0

Questo è esattamente quello che stavo cercando! – Max

+0

È molto meglio utilizzare BasicObject, poiché realizza la stessa operazione ed è molto più sicuro. – Max

+0

Notato. Quando questa risposta è stata pubblicata, 1.8 era ancora abbastanza comune negli scenari di produzione, e come tale 'BasicObject' non esisteva ancora. – numbers1311407

5

Se stai usando Ruby 1.9, si può avere l'eredita dalla classe BasicObject per ottenere una tabula rasa su cui lavorare:

http://ruby-doc.org/core-1.9/classes/BasicObject.html

+0

Questo è il tipo di cosa che sto cercando, ma un tentativo banale mi dà un 'SystemStackError: stack level too deep' quando si definisce' method_missing'. Hm ... – Max

+2

Cosa stai facendo all'interno di 'method_missing'? Se hai fatto qualcosa come 'puts * args', otterrai un ciclo infinito' method_missing'. Se hai bisogno di un metodo 'Kernel' dovresti chiamare' :: Kernel.puts', ecc. – numbers1311407

1

Se stai usando Ruby 1.8 puoi considerare l'utilizzo della gemma blankslate.

Problemi correlati