2010-03-09 11 views
5

Come follow-up a How can I reverse ruby's include function, a cui è stata data una risposta soddisfacente ma la mia semplificazione del problema reale ha significato che la soluzione non era applicabile.Come "sostituire" un modulo incluso tramite ruby ​​include la funzione

Ora sto di fronte a questo (i nomi cambiati per proteggere le identità!):

module OldFormHelpers 
    def foo 
    puts "foo" 
    end 
    def bar 
    puts "bar" 
    end 
end 

module Helpers 
    include OldFormHelpers 
end 

Questo mi dà:

Helpers.instance_methods 
=> ["bar", "foo"] 
Helpers.ancestors 
=> [Helpers, OldFormHelpers] 

Questo è il codice che in realtà non hanno accesso alle modificare, senza biforcazione.

Quello che voglio fare è creare un nuovo modulo;

module BetterFormHelpers 
    def foo 
    puts "better foo" 
    end 
end 

Questo deve per rimuovere i comportamenti da OldFormHelpers, e quindi aggiungere il nuovo roba da BetterFormHelpers

La soluzione precedente era di utilizzare undef_method in questo modo:

Helpers.module_eval do 
    OldFormHelpers.instance_methods do |m| 
    undef_method(m) 
    end 
end 

Tuttavia, dopo aver incluso BetterFormHelpers, Helpers.instance_methods non contiene "pippo". La ragione di questo è spiegato in http://ruby-doc.org/core/classes/Module.src/M001652.html

Utilizzando remove_method mi dice che Helpers non si ha il metodo di "foo", quindi credo che ho bisogno di un modo per rimuovere il primo inserimento dalla catena antenati ...

Questo è stato un po 'lungo, quindi ho smesso di inserire così tanti frammenti verso la fine, ma aggiungo una sessione irb che mostra il comportamento di undef/remove e quindi un include.

+0

"Questo è un codice che non ho realmente accesso alla modifica": la patch delle scimmie non è un'opzione? –

+0

Le patch per le scimmie sono un'opzione, una specie di - ma il modo in cui il modulo che stiamo sostituendo funziona, definisce i moduli e quindi li include - è piuttosto difficile inserire il codice da qualche parte in questa catena per fermare l'evento. Anche se dopo aver seguito questa linea per un po ', sto iniziando ad orientarmi di più in quella direzione. – Glenjamin

risposta

2

Non puoi undefinare solo i metodi che non verranno sovrascritti?

Helpers.module_eval do 
    (OldFormHelpers.instance_methods - BetterFormHelpers.instance_methods).each do |m| 
    undef_method(m) 
    end 
end 

(Il modulo incluso ultimi saranno cercati prima in modo che nessun metodo OldFormHelpers verrà eseguito se BetterFormHelpers definisce anche.)

Se si desidera sovrascrivere dinamicamente ulteriori metodi del modulo OldFormHelpers, tuttavia, il problema rimane lo stesso.

Problemi correlati