From: Robert Klemme Date: 2010-02-13T17:10:45+09:00 Subject: Re: Is there a way to get a method to always run at the end of any descendent's initialize method? On 02/12/2010 11:41 PM, Xeno Campanoli wrote: > Ryan Davis wrote: >> On Feb 12, 2010, at 13:50 , Xeno Campanoli wrote: >> >>> I have an initialize method I want to run at the end of any daughter or granddaughter 'initialize' to make sure the state has been created properly, and I would rather specify the execution from the base class itself than count on those descendents to do it. >> The most correct way to do it is to have all subclasses properly use super at the end of their initialize bodies: >> >> class Subclass < Superclass >> def initialize >> # ... stuff >> super >> end >> end >> >> There are "fancier" ways (read: overly clever), but doing it this way is cleaner, faster, and easier to debug / maintain. >> >> >> > > The problem with that is you may want some things from super available before > you do other things in initialize. I figured out another way, which is to > define initialize subroutines as pure virtual in the base class, called from > initialize, then I put the thing at the end of initialize, and all the daughters > only modify the called initializers, and all use the base class initialize > method. There is nothing to force daughters not to make their own initialize, > but at least this is nice and formal. Template method pattern. Here's another approach, only mildly more sophisticated: irb(main):001:0> class Base irb(main):002:1> def self.new(*a, &b) irb(main):003:2> x = allocate irb(main):004:2> x.send(:initialize, *a, &b) irb(main):005:2> x.after_init irb(main):006:2> x irb(main):007:2> end irb(main):008:1> def after_init; puts "hook run for #{self.class}"; end irb(main):009:1> end => nil irb(main):010:0> class Derived < Base irb(main):011:1> def initialize; puts "work for #{self.class}"; end irb(main):012:1> end => nil irb(main):013:0> d = Derived.new work for Derived hook run for Derived => # irb(main):014:0> class Derived2 < Derived irb(main):015:1> def initialize;super;puts "in #{self.class}"; end irb(main):016:1> end => nil irb(main):017:0> e = Derived2.new work for Derived2 in Derived2 hook run for Derived2 => # irb(main):018:0> The basic trick is to redefine the base class's #new method. Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/