From: Daniel Schierbeck Date: 2005-11-23T22:12:25+09:00 Subject: Re: pattern: auto-running module init code Phil Tomson wrote: > Maybe you've run into this problem: you have a module and you want to make > sure that certain intialization code is run in that module. Of course a module can > have an initialize method like so: > > module Foo > def initialize(a,b) > @a=a > @b=b > end > end > > > and then when you include the Foo module in your class later on that becomes > the initialize for your class: > > class Bar > include Foo > end > > Now Bar's new takes two arguments a and b. > > However, what if you either want to define initialize in your class (to do > some class-specific things) or > what if you have a module that sets up some sort of connection, > perhaps a Rinda tuplespace, for example: > > module Broadcaster > PROTOCOL = "druby" > HOST = "localhost" > PORT = 9999 > def setup_connection > @uri = "#{@protocol||PROTOCOL}://#{@host||HOST}:#{@port||PORT}" > #set up the shared tuplespace: > DRb.start_service(@uri,Rinda::TupleSpace.new) > puts "#{$0}: setting up broadcaster..." > #now set up broadcaster: > @ts = Rinda::TupleSpaceProxy.new(DRbObject.new(nil,@uri)) > end > > #other related methods that access the tuplespace > end > > Now if you want your class to also be a Broadcaster you could do the > following: > > class Thing > include Broadcaster > def initialize(*args) > #... > setup_connection > end > end > > However, what if the user forgets to include the call to 'setup_connection' in > their constructor? The connection won't be setup and 'Thing' won't really be > doing any broadcasting. > > How can we get setup_connection to be called automatically when 'Thing' is > extended with Broadcaster? > > Add the following methods to the Broadcaster module: > > module Broadcaster > def self.extended(obj) > obj.setup_connection > end > > def self.included(mod) > warn "Be sure to run #{self}.setup_connection somewhere in #{mod}'s\ > initialize method!" > warn "OR: instead of 'include #{self}', use 'extend #{self}' in \ > #{mod}'s initialize method and it will be called automatically." > end > end #module > > Then instead of 'include Broadcaster' use 'extend' like so: > > class Thing > def initialize(*args) > #... > extend Broadcaster # setup_connection called automagically > end > end > > > What are the pros & cons of this approach? Is there really any advantage to > doing things this way? > > (I can think of one con: if setup_connection took arguments this approach > would not work) > > It does seem advantagous to call the setup code automatically this way, but it > comes at the cost of using extend instead of include (and include tends to be > used a lot more than extend ). > > Phil Ideally, there would be a method hook that was called when a class including the module was instantiated. module Fooable def self.initialized(obj, *args, &block) puts "A class including Fooable has been instantiated!" obj.do_something(*args) # whatever end end Cheers, Daniel