2008-09-25 19 views
11

Entonces, quiero definir un método singleton para un objeto, pero quiero hacerlo usando un cierre.¿Es posible definir un método singleton de Ruby usando un bloque?

Por ejemplo,

def define_say(obj, msg) 
    def obj.say 
    puts msg 
    end 
end 

o = Object.new 
define_say o, "hello world!" 
o.say 

Esto no funciona porque la definición de un método singleton a través de "def" no es un cierre, por lo que obtener una excepción que "msg" es una variable no definida o método.

Lo que me gustaría hacer es algo así como usar el método "define_method" en la clase Module, pero hasta donde puedo decir, esto solo se puede usar para definir un método en una clase ... pero quiero un método de Singleton ...

Por lo tanto, me encantaría escribir algo como esto:

def define_say(obj, msg) 
    obj.define_singleton_method(:say) { 
    puts msg 
    } 
end 

¿alguien sabe cómo puedo lograr esto sin tener que crear un método para almacenar una Proc y luego usar el Proc dentro de un método singleton? (Básicamente, quiero una manera limpia, no hacky de hacer esto)

Respuesta

8

Aquí es una respuesta que hace lo que usted está buscando

def define_say(obj, msg) 
    # Get a handle to the singleton class of obj 
    metaclass = class << obj; self; end 

    # add the method using define_method instead of def x.say so we can use a closure 
    metaclass.send :define_method, :say do 
    puts msg 
    end 
end 

Uso (pegar desde IRB)

>> s = "my string" 
=> "my string" 
>> define_say(s, "I am S") 
=> #<Proc:[email protected](irb):11> 
>> s.say 
I am S 
=> nil 

Para más información (y una pequeña biblioteca que hace que sea menos sucio) lee esto:

http://viewsourcecode.org/why/hacking/seeingMetaclassesClearly.html

Como comentario aparte, si eres programador de ruby ​​y NO HAS LEÍDO, ¡hazlo ahora ~! se añadió

+0

brillante! ¡Funciona perfectamente! Gracias toneladas! –

+0

Cambié el enlace, porque _por qué se quedó sin permiso desde que se publicó esta respuesta. –

Cuestiones relacionadas