2010-03-02 11 views
7

¿Es posible cambiar el enlace de un procedimiento durante el tiempo de invocación?Cambiar el enlace `Proc` durante la invocación

class AllValidator 
    def age_validator 
    Proc.new {|value| self.age > value } 
    end 
end 

class Bar 
    attr_accessor :age 
    def doSomething 
    validator = AllValidator.new.age_validator 
    validator.call(25) # How to pass self as the binding? 
    end 
end 

En el código anterior, ¿cómo cambio la vinculación del proceso durante la invocación? ¿Hay alguna manera de pasar el enlace de forma muy similar a la función eval?

Nota Si el ejemplo anterior fuera real, usaría mixin/inheritence etc. Estoy utilizando el código para demostrar mi escenario problema.

Respuesta

12

Puede utilizar instance_eval:

class Bar 
    def do_something 
    validator = AllValidator.new.age_validator 

    # Evaluate validator in the context of self. 
    instance_eval &validator 
    end 
end 

Si quiere pasar argumentos (como se menciona en el comentario más abajo), se puede utilizar en lugar de instance_execinstance_eval si utiliza Ruby 1.9 o Ruby 1.8.7:

class Bar 
    def do_something 
    validator = AllValidator.new.age_validator 

    # instance_exec is like instance_eval with arguments. 
    instance_exec 5, &validator 
    end 
end 

Si usted tiene que hacer que funcione con Ruby 1.8.6 y por debajo, así, la mejor opción es para unir el proc como método de Bar:

class Bar 
    def do_something 
    self.class.send :define_method, :validate, &AllValidator.new.age_validator 
    self.validate 5 
    end 
end 

Una alternativa es implementar instance_exec versiones anteriores de Ruby (example here). Todo lo que hace es definir un método antes de llamarlo y no definirlo una vez que haya terminado.

+0

¿Eso le permite pasar un argumento a 'validator'? –

+0

'instance_eval' tiene un método hermano que le permite hacer eso, consulte la actualización anterior. – molf

+0

+1 Gracias por la respuesta detallada. –

Cuestiones relacionadas