extend question

S

Sebastian Padó

Hello everybody,

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
 
D

David A. Black

--8323328-195993639-1126701134=:28844
Content-Type: MULTIPART/MIXED; BOUNDARY="8323328-195993639-1126701134=:28844"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

--8323328-195993639-1126701134=:28844
Content-Type: TEXT/PLAIN; charset=X-UNKNOWN; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE

Hi --

Hello everybody,

I apologize if this a stupid question - but I'd be very grateful for
any hints!

Short Problem

You can dup the module:

module A
def x
puts "A"
end
end

module B
def x
puts "B"
end
end

obj =3D Object.new
obj.extend(A).x # A
obj.extend(B).x # B
obj.extend(A).x # B
obj.extend(A.dup).x # A

I'm not sure whether there are hidden pitfalls to this, perhaps
involving constants.


David

--=20
David A. Black
(e-mail address removed)
--8323328-195993639-1126701134=:28844--
--8323328-195993639-1126701134=:28844--
 
R

Robert Klemme

Sebastian said:
Hello everybody,

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.

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.

Kind regards

robert
 
J

Jim Weirich

Sebastian Pad=F3 said:
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 =3D=3D "useA" then
@strategy =3D StrategyA.new
elsif param =3D=3D "useB" then
@strategy =3D 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.

--=20
-- Jim Weirich (e-mail address removed) http://onestepback.org
 
C

Caleb Clausen

Sebastian said:
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 =3D proc do
def pluginMethod
puts "module A"
end
end

and then instance_eval the blocks instead of extending:

...
if param =3D=3D "useA" then
instance_eval(ModuleA)

If there's just one method that changes, you might be better off using=20
define_method... but this way will handle more than one method. You
will get a warning about method redefinition if you enable warnings.... I t=
hink=20
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top