Ho cercato di capire come estendere il comportamento di initialize
da un modulo. Voglio farlo senza chiamare super in initialize
della classe che viene mescolata in. Voglio supportare il normale schema di chiamata include
Non riesco a capirlo. Ho letto tutto quello che posso trovare sulla questione e, mentre le persone hanno suggerimenti, nessuno di loro sembra funzionare (almeno nelle mie mani).È possibile sovrascrivere #initialize in un modulo Ruby?
Ecco quello che (credo) lo so:
- Se può essere fatto a tutti, deve essere fatto utilizzando il gancio sul
include
(vale a direModule.included(base)
). - Il gancio
include
verrà eseguito prima che la classe inclusa definiscainitialize
, quindi non c'è motivo di provare semplicemente a definireinitialize
conbase.instance_eval
perché verrà sovrascritto. È stato suggerito di utilizzare il gancio
method_added
e gestirlo lì. Questo è quello che sto provando ora, ma sembra che l'hook venga eseguito all'inizio della definizione del metodo in modo da ottenere ciò che vedi qui sotto.module Mo def self.included(klass) klass.instance_eval do def method_added(method) puts "Starting creation of #{method} for #{self.name}" case method when :initialize alias_method :original_initialize, :initialize puts "About to define initialize in Mo" def initialize original_initialize puts "Hello from Mo#initialize" end puts "Finished defining initialize in Mo" end puts "Finishing creation of #{method} for #{self.name}" end end end end class Foo include Mo def initialize puts "Hello from Foo#initialize" end end foo = Foo.new
Il risultato è il seguente output:
Starting creation of initialize for Foo
Starting creation of original_initialize for Foo
Finishing creation of original_initialize for Foo
About to define initialize in Mo
Finished defining initialize in Mo
Finishing creation of initialize for Foo
Hello from Foo#initialize
Sembra a me come initialize
dalla classe Foo è ancora sovrascrive la definizione dal modulo. Immagino che questo sia perché la definizione è ancora aperta, suggerendo che non è una questione di quale blocco è stato avviato per ultimo, che è finito per ultimo che "vince".
Se qualcuno là fuori sa davvero come farlo e farlo funzionare, per favore illuminami.
FWIW, sì, penso di avere una buona ragione per voler farlo.
Ho scoperto "antepone" poco dopo aver fatto la domanda. Mi piace! Ancora curioso di sapere se c'è un modo per farlo in 1.9. * – Huliax
C'è qualcosa di ovvio che mi manca nell'usare 'klass.send: prepend' invece di semplicemente' klass.prepend'? – NobodysNightmare