I apologize if this a stupid question - but I'd be very grateful for
any hints!
Short Problem
···
-------------
Is there a way of _forcing_ methods to be
overwritten when including a module?
Background
----------
I'm implementing some algorithm, let's call it M, as a class. Now M
needs to be customised - e.g. different bits need to be
instatiated. If there was just one such bit, I'd create subclasses
that inherit from M.
However, there are several such bits -- and my idea was to realise
this by writing, for each such customisation point, different Modules
which all offer the same "plugin" method. As an example, look at the
code below.
class M
def customize(param)
if param == "useA" then
extend(ModuleA)
elsif param == "useB" then
extend(ModuleB)
else
raise someException
end
end
def runAlgorithm
pluginMethod()
end
end
module A
def pluginMethod
puts "module A"
end
end
module B
def pluginMethod
puts "module B"
end
end
But what happens if I customize the class several times?
m_obj = new M()
m_obj.runAlgorithm() -> fails; that it fine
First I run it extended with A...
m_obj.customize("useA")
m_obj.runAlgorithm() -> prints "module A"
Then extended with B...
m_obj.customize("useB")
m_obj.runAlgorithm() -> prints "module B"
But if I want to switch back to A, it goes wrong:
m_obj.customize("useA")
m_obj.runAlgorithm() -> prints "module B"
Somewhere in the documentation of Module I found that
Module.append_features only appends its features if they have not been
added already - I suspect that this is the underlying reason.
So, is there any way to "force" the methods to be overwritten, even if
it appears to be superfluous? Or am I using an unsuitable approach to
begin with? Any
I apologize if this a stupid question - but I'd be very grateful for
any hints!
Short Problem
-------------
Is there a way of _forcing_ methods to be
overwritten when including a module?
Background
----------
I'm implementing some algorithm, let's call it M, as a class. Now M
needs to be customised - e.g. different bits need to be
instatiated. If there was just one such bit, I'd create subclasses
that inherit from M.
However, there are several such bits -- and my idea was to realise
this by writing, for each such customisation point, different Modules
which all offer the same "plugin" method. As an example, look at the
code below.
<snip/>
So, is there any way to "force" the methods to be overwritten, even if
it appears to be superfluous? Or am I using an unsuitable approach to
begin with? Any
In your case no effort is necessary since you just extend with one of your
modules and Ruby will complain as soon as the needed methods are invoked.
If you want to check in customize, you can use ModuleA.instance_methods to
check whether all methods are there.
An additional caveat: if you invoke customize multiple times you might run
into trouble if you need to extend the same instance with different
modules over time. An approach that uses delegation (see state pattern,
strategy pattern and related patterns) might be better in that case.
So, is there any way to "force" the methods to be overwritten, even if
it appears to be superfluous? Or am I using an unsuitable approach to
begin with?
You might want to consider the Strategy Pattern ... create an object that
implements your plugin method and then delegate to that object whenever
the plugin is called. By using a separate object, it becomes much easier
to switch strategies at runtime.
class StrategyA
def pluginMethod
puts "A"
end
end
class StrategyB
... similar to above
end
class M
def customize(param)
if param == "useA" then @strategy = StrategyA.new
elsif param == "useB" then @strategy = StrategyB.new
else
raise someException
end
end
def runAlgorithm
pluginMethod
end
def pluginMethod @strategy.pluginMethod
end
end
The strategy object is a bit less intimate with your original object than
the extend module approach ... this could good or bad, depending on what
you need.
···
--
-- Jim Weirich jim@weirichhouse.org http://onestepback.org
-----------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
Is there a way of _forcing_ methods to be
overwritten when including a module?
Here's a somewhat wild suggestion that I have found useful when running
up against the limitations of ruby's modules: use a proc instead. That is,
instead of:
module ModuleA
def pluginMethod
puts "module A"
end
end
use
ModuleA = proc do
def pluginMethod
puts "module A"
end
end
and then instance_eval the blocks instead of extending:
...
if param == "useA" then
instance_eval(ModuleA)
If there's just one method that changes, you might be better off using
define_method... but this way will handle more than one method. You
will get a warning about method redefinition if you enable warnings.... I think
undef'ing the method first will disable it.
This also works around the problem of not being able to redefine an already
existing method of a class in a module that gets included in that class. It is a fairly
low-level approach, so use with caution