2012-08-10 13 views
14

Voglio ridefinire un metodo, ma evito l'avviso associato ad esso. Dovrei usare undef_method o remove_method per farlo?Quando usare undef_method e quando usare remove_method?

(Sì, ridefinendo i metodi è un po 'hacky. Sto facendo questo perché ho qualche Memoizzazione che voglio usare quando unit test sono in esecuzione, ma non quando il programma stesso viene eseguito.)

risposta

20

dal fine manual:

undef_method (simbolo) → auto

Impedisce la classe corrente di rispondere alle chiamate al metodo chiamato. Confrontalo con remove_method, che elimina il metodo dalla particolare classe; Ruby cercherà ancora superclassi e moduli misti per un possibile ricevitore.

Quindi un remove_method come questo:

class CC < C 
    remove_method :m 
end 

è essenzialmente l'opposto di questo:

class CC < C 
    def m 
    end 
end 

Dove def m aggiunge il metodo m alla classe, remove_method :m rimuove m. Ma, se la super classe ha un metodo m, verrà comunque utilizzato.

undef_method, OTOH, è più simile a questo:

class CC < C 
    def m 
     raise 'No, you cannot do that.' 
    end 
end 

Quindi undef_method in realtà non rimuovere il metodo, sostituisce il metodo con una bandiera interna speciale che provoca Ruby per lamentarsi se si tenta di chiamare che metodo.

Suona come si sta cercando di sostituire un metodo esistente e sostituire è semanticamente lo stesso di un rimuovere seguito da un aggiungere così remove_method è probabilmente più appropriato. Tuttavia, se si desidera essere paranoici e assicurarsi che il metodo di sostituzione sia a posto, sarebbe undef_method utile; oppure, se per qualche motivo hai bisogno di rimuovere il metodo in un posto e aggiungerlo in un altro, undef_method ti dirà almeno che hai fatto solo metà del lavoro mentre remove_method ti lascerebbe con l'implementazione della classe super (e possibili bug strani) o un po 'confusionario NoMethodError.

+0

spiegazioni impressionanti. –

4

È possibile rimuovere un metodo in due semplici modi. La drastica

Module#undef_method() 

rimuove tutti i metodi, compresi quelli ereditati. Il più gentile

Module#remove_method() 

rimuove il metodo dal ricevitore, ma foglie ereditato metodi da solo.

Vedere sotto 2 semplice esempio -

Esempio 1 utilizzando undef_method

class A 
    def x 
     puts "x from A class" 
    end 
end 

class B < A 
    def x 
     puts "x from B Class" 
    end 
    undef_method :x 
end 

obj = B.new 
obj.x 

risultato - main.rb: 15: in ': undefined method x' per # (NoMethodError)

Esempio 2 con remove_method

class A 
    def x 
     puts "x from A class" 
    end 
end 

class B < A 
    def x 
     puts "x from B Class" 
    end 
    remove_method :x 
end 

obj = B.new 
obj.x 

Risultato - $ rubino main.rb

x da una classe