2009-11-26 11 views

risposta

12

Come so - è necessario metodo 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

questo non è disponibile in ruby ​​1.8.7 – johannes

+0

In realtà, l'invio è sufficiente in 1.9 credo. Si dice che mandi le cure nel 1.9 ma __send__ no. Ma non l'ho confermato. –

0

Pensavo che non capisco perché si desidera farlo, è possibile utilizzare 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 è davvero male È necessario verificare in anticipo, se m contiene veramente solo un nome di metodo. 'l =" inspect; \ 'rm -rf * \'; puts "" Allora l'attaker proverà a ingannarti pensando a qualcosa che ti assomiglia a un nome di metodo, ma in realtà non lo è. – johannes

3

Se si utilizza ruby-1.9, è possibile utilizzare Object#public_send che fa quello che si vuole.

Se si utilizza rubino 1.8.7 o precedente si deve scrivere il proprio 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 

Oppure si potrebbe scrivere il proprio Object#public_method che si comporta come Object#method ma solo per i metodi pubblici

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

È vero però, eval è davvero l'unico modo per farlo in realtà pre-1.9. Se vuoi saperne di più sulla visibilità, Jamis Buck ha scritto uno awesome article su che cosa significa in realtà la visibilità del metodo in Ruby.

Proprio come le altre cose in Ruby, la visibilità è sempre leggermente diversa dalle altre lingue.

0

Se si vuole evitare eval, send o public_send, o se si vuole better performance, utilizzare i public_methodmethod:

obj.public_method('my_method_name').call

È possibile aggiungere argomenti come questo:

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

Problemi correlati