2011-08-25 17 views
10

Estoy haciendo una clase extraña donde quiero ver todos los métodos enviados a un objeto de la clase. Puedo lograr la mayor parte de lo que quiero con method_missing, p.Ruby: capturando todos los métodos enviados a un objeto

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

El problema entonces son todos los métodos de instancia que MyClass hereda de Object. Podría revisar cada método uno a uno y redefinirlos, pero esperaba un enfoque más flexible. Todos los métodos de metaprogramación que he probado se han quejado con NameError cuando intento tocar esos métodos de instancia.

Respuesta

11

Como se señaló en los comentarios y la respuesta de @DanCheail, Si está usando ruby ​​1.9+, debería usar un BasicObject en lugar de métodos indefinidos de Object. En el momento de esta publicación, el uso de 1.8.x todavía era bastante frecuente, a pesar de que 1.9 había sido lanzado por algún tiempo.


En lugar de intentar "redefinir" cualquier cosa, usted podría envolver su objeto en una blanqueada (en su mayor parte) objeto proxy, algo así como:

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

¡Eso es exactamente lo que estaba buscando! – Max

+0

Es mucho mejor usar un BasicObject, ya que logra lo mismo y es mucho más seguro. – Max

+0

observado. Cuando se publicó esta respuesta, 1.8 todavía era bastante común en los escenarios de producción, y como tal 'BasicObject' aún no existía. – numbers1311407

5

Si está usando Ruby 1.9, usted puede tener su clase herede de BasicObject para obtener una pizarra limpia para trabajar a partir de:

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

+0

Ese es el tipo de cosa que estoy buscando, pero un intento trivial me da un 'SystemStackError: stack level too deep' al definir' method_missing'. Hm ... – Max

+2

¿Qué haces dentro de 'method_missing'? Si hiciste algo como 'puts * args' vas a obtener un bucle infinito' method_missing'. Si necesita un método 'Kernel' tendría que llamar a' :: Kernel.puts', etc. – numbers1311407

1

Si está utilizando Rubí 1.8 puede considerar usar la gema blankslate.

Cuestiones relacionadas