A real world example of Adaption¶
Imagine that you are about to give a presentation at a meeting. You’ve brought your laptop, and the room has a projector and a cable to plug your laptop into the projector. However, the cable you brought won’t plug into the projector because your cable only interfaces with a DVI port, and the projector only interfaces with a VGA port.
So you ask of the room, “does anyone have a DVI to VGA adapter?”
An adapter? Let’s state the problem of the projector and the laptop in Grok. Of course it’s impossible to implement a hardware problem in software (duh!) so for this example we won’t have any implementation details:
import grok
from zope.interface import Interface
class IVGAPort(Interface):
"Video connection using VGA"
def connectToVGA(cable):
"Connect to a VGA video cable"
class IDVIPort(Interface):
"Video connection using DVI"
def connectToDVI(cable):
"Connect to a DVI video cable"
class DVIToVGAAdapter(grok.Adapter):
"Use your DVI laptop with a VGA projector"
grok.adapts(IDVIPort)
grok.provides(IVGAPort)
def connectToVGA(cable):
# self.context will be a reference to the laptop object
def plugLaptopIntoProjector(laptop, projector):
"Display your presentation on the wall"
vga_capable = IVGAPort(laptop, None)
if vga_capable is None:
print "Uh oh, looks like you forget to bring an adapter."
else:
vga_capable.connectToVGA(projector)
A common idiom for asking the Zope 3 component architecture to perform adaptation is to instantiate a new Interface with the object that you wish to adapt as an argument. We did this in the ‘plugLaptopIntoProjecter’ function with the line:
vga_capable = IVGAPort(laptop, None)
The vga_capable variable is now an object that provides the IVGAPort. If the
laptop already implements IVGAPort, then this will be the laptop object itself.
If the laptop provides IDVIPort, then the DVIToVGAAdapter will be used to
extend IDVIPort to provide IVGAPort. The second optional argument (None
)
will be returned if the laptop doesn’t provide an IVGAPort and no suitable
adapter can be found. If adaptation was successful, you shouldn’t care if you
have a Laptop object or a DVIToVGAAdapter object returned - your only concern
is that you have an object that provides the requested IVGAPort interface that
provides the necessary connectToVGA(projector)
method.
The DVI to VGA Adapter¶
Let’s review the DVIToVGAAdapter class that we created.
class DVIToVGAAdapter(grok.Adapter):
"Use your DVI laptop with a VGA projector"
grok.adapts(IDVIPort)
grok.provides(IVGAPort)
def connectToVGA(cable):
# self.context will be a reference to the laptop object
When you inhert from grok.Adapter, Grok will do two things. One is to register
your Adapter with the Zope 3 Component Architecture so that it can look-up the
right adapter for the requested interface. The second is to reference the
object that is being adapted to an attribute named context
. In Grok, the
Adapter base class that you inherit from is very simple and looks like this:
class Adapter(object):
def __init__(self, context):
self.context = context
This is just a convention used to save some typing. If you wish, you may supply your own constructor to call the object being adapted something specific to your adapter. For example, in the above example, we could add the following constructor to our DVIToVGAAdapter Class:
def __init__(self, laptop):
self.laptop = laptop
Adaptation is about requiring an object which provides one interface, and
extending it so that you get a new interface. We declare that we require an
object that provides an IDVIPort interface - this is declared with the
directive grok.adapts(IDVIPort)
. We are extending the IDVIPort interface
to provide a new interface, IVGAPort - this is declared with the directive
grok.provides(IVGAPort)
. Finally, the adapter is responsible for fulfilling
the interface that it declares it implements. This implementation will
typically use self.context
attribute - which is the object that is being
adapted.
It is possible to use either grok.provides(IVGAPort)
or
grok.implements(IVGAPort)
directives for the DVIToVGAAdapter. In a more
complex example it’s possible that an adapter provides multiple interfaces, but
only one interface is meant to be used for the purposes of adaptation. The
grok.provides
directive explicitly declares the interface to be used for
adaptation, however if an Adapter only declares that it implements a single