2009-11-26 10 views

Respuesta

12

Como sé, necesita el método public_send:

----------------------------------------------------- Object#public_send 
    obj.public_send(symbol [, args...]) => obj 

    From Ruby 1.9.1 
------------------------------------------------------------------------ 
    Invokes the method identified by _symbol_, passing it any arguments 
    specified. Unlike send, public_send calls public methods only. 

     1.public_send(:puts, "hello") # causes NoMethodError 
+1

esto no está disponible en ruby ​​1.8.7 – johannes

+0

En realidad, enviar es suficiente en 1.9 creo. Se rumorea que envía preocupaciones en 1.9 pero __send__ no. Pero no he confirmado esto. –

0

Pensé que no entendía por qué quieres hacerlo, puedes usar eval.

class Klass 
    private 
    def private_method(arg) 
    end 
end 

k = Klass.new 
m = "private_method" 
eval "k.#{m}('an arg')" 

NoMethodError: private method `private_method' called for #<Klass:0x128a7c0> 
    from (irb):15 
    from (irb):15 
+0

Eval es realmente malo. Debe verificar de antemano, si m realmente contiene solo un nombre de método. 'l =" inspeccionar; \ 'rm -rf * \ '; puts" 'Entonces el atacante intentará engañarte pensando en algo que te parezca un nombre de método, pero realmente no lo es. – johannes

3

Si está utilizando rubí-1.9, puede utilizar Object#public_send el que hace lo que quiere.

Si utilizar rubí 1.8.7 o anterior hay que escribir su propia Object#public_send

class Object 
    def public_send(name, *args) 
    unless public_methods.include?(name.to_s) 
     raise NoMethodError.new("undefined method `#{name}' for \"#{self.inspect}\":#{self.class}") 
    end 
    send(name, *args) 
    end 
end 

O usted podría escribir su propia Object#public_method que se comporta como Object#method pero sólo para los métodos públicos

class Object 
    def public_method(name) 
    unless public_methods.include?(name.to_s) 
     raise NameError.new("undefined method `#{name}' for class `#{self.class}'") 
    end 
    method(name) 
    end 
end 
0

Es cierto, eval realmente es, creo que es la única manera de hacerlo realmente antes de 1.9. Si desea leer más sobre la visibilidad, Jamis Buck escribió un awesome article sobre qué método realmente significa la visibilidad en Ruby.

Al igual que otras cosas en Ruby, la visibilidad es ligeramente diferente de otros idiomas.

0

Si se quiere evitar eval, send o public_send, o si desea better performance, utilizar los public_methodmethod:

obj.public_method('my_method_name').call

Puede añadir argumentos de esta manera:

obj.public_method('my_method_name').call('some_argument_1', 'some_argument_2')

Cuestiones relacionadas