2013-03-04 14 views
5

Sto provando a usare i metodi riflessivi in ​​Ruby e sto imbattendo in un comportamento che trovo davvero sorprendente.Perché Module.methods() e respond_to? funziona diversamente in irb che in script?

Gli esempi che seguono sembra funzionare in modo diverso in IRB e quando viene chiamato uno script ruby:

Esempio 1:

def myfun; end 
p respond_to?(:myfun) 

In IRB, questo dice 'vero', In script: 'false' .

Esempio 2:

ml = methods 
def myfun; end 
p methods - ml 

In IRB, questo dice [: myfun]. Nella sceneggiatura: [].

Ho trovato questo sotto 1.8, 1.9 MRI, JRuby 1.5.6, ecc., Quindi presumo che questo sia normale.

Perché la differenza?

Ero abbastanza sicuro di rispondere "a?" è il modo di vedere se un metodo è disponibile - perché non funziona nel caso precedente?

risposta

5

Questa funzione - metodo sull'oggetto "principale" - è definita come privata nello script ruby. È possibile controllare questo facilmente:

ml = private_methods 
def myfun; end 
p private_methods - ml #=> [:myfun] 
p respond_to?(:myfun, true) #=> true 

Se si chiama in modo esplicito su auto si otterrà un errore:

self.myfun 
# NoMethodError: private method ‘myfun’ called for main:Object 

D'altra parte, nel tuo metodo IRB è definito come pubblico. Sotto il cofano è simile a questa:

class Object 
    def irb_binding 
    # this is where your entered code is evaluated 
    def myfun; :ok; end # you can define methods in other methods 
    self.myfun # and they are public by default 
    end 
end 

p irb_binding # :ok 

IRB potrebbe facilmente valutare al livello più alto, ma invece si crea un ambiente separato con il metodo in modo che le variabili locali non sono condivise:

require "irb" 
foo = :ok 
IRB.start 
#>> foo 
# NameError: undefined local variable or method `foo' for main:Object 

I pensare che i metodi siano pubblici è solo una coincidenza dovuta all'implementazione e non importa molto. Questi metodi sono comunque temporanei.

+0

Molto buono a sapersi - è incredibile che non mi sia imbattuto in questo dopo anni di esposizione Ruby .. Sì, mi interessa perché IRB li rende pubblici sta cercando di essere più amichevole-è vero? :) Capisco perché normalmente sono privati ​​- per evitare confusione come "def f; end; class A; end; A.new.f", o qualcosa del genere? – inger

+0

Sono stato sorpreso di imparare anche questo. –

+0

@Semyon Puoi spiegare perché i metodi 'irb' sono pubblici? E perché in 'irb'' myfun' e 'self.myfun' si riferiscono allo stesso metodo? – codeit