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