Module s.l.component

Part of stoqlib.lib

Component infrastructure for Stoqlib

Stoqlib uses the adapter pattern http://en.wikipedia.org/wiki/Adapter_pattern to solve a specific set of problems, most noticeable roles for Persons.

First we need an object that we can adapt into something else. It needs to be a subclass of AdaptableORMObject:

>>> from stoqlib.lib.component import Adaptable
>>> class Bike(Adaptable):
...     pass

We have no facets, yet so getFacetTypes() will return an empty list:

>>> Bike.getFacetTypes()
[]

Let's define an interface for something we can adapt

>>> from zope.interface.interface import Interface
>>> class ISuspension(Interface):
...    def lockout():
...        pass
...    def is_locked():
...        pass

To be able to adapt our object into the interface we need to create an adapter which needs to be a subclass of Adapter

>>> from stoqlib.lib.component import Adapter
>>> class BikeAdaptToSuspension(Adapter):
...     def __init__(self, original):
...         Adapter.__init__(self, original)
...         self.locked = False
...     def lockout(self):
...         self.locked = True
...     def is_locked(self):
...         return self.locked

We need to register the adapter, to attach the adapter to the adaptable object, which will return the

>>> Bike.registerFacet(BikeAdaptToSuspension, ISuspension)

If we try to register the same facet twice we'll receive an exception:

>>> Bike.registerFacet(BikeAdaptToSuspension, ISuspension)
Traceback (most recent call last):
    ...
TypeError: Bike does already have a facet for interface ISuspension

Now, if you want to listen the adapter types for a specific interface you can call getFacetTypes():

>>> Bike.getFacetTypes() # doctest:+ELLIPSIS
[<class '...BikeAdaptToSuspension'>]
>>> bike = Bike()
>>> ISuspension(bike) # doctest:+ELLIPSIS
Traceback (most recent call last):
    ...
TypeError: ('Could not adapt', ...)

TypeError should never be caught in user code, so if we want to check if a certain object implements an adapter or not we should pass in a default object as the second argument to the interface "casting":

>>> ISuspension(bike, False)
False

To attach an adapter to an object, we use addFacet, which will return the adapted object, which will return the adapter.

>>> bike.addFacet(ISuspension) # doctest:+ELLIPSIS
<...BikeAdaptToSuspension object at ...>

Call addFacet with the same interface again raises a

>>> bike.addFacet(ISuspension)
Traceback (most recent call last):
    ...
AdapterError: Bike already has a facet for interface ISuspension

We can now adapt the object:

>>> suspension = ISuspension(bike)
>>> suspension # doctest:+ELLIPSIS
<...BikeAdaptToSuspension object at ...>

And we can call methods on the object, which are part of the interface:

>>> suspension.is_locked()
False
>>> suspension.lockout()
>>> suspension.is_locked()
True

To fetch the adaptable/adapted object call get_adapted():

>>> suspension.get_adapted() # doctest:+ELLIPSIS
<...Bike object at ...>
Class Adapter Adapter base class, all adapters must subclass this.
Class Adaptable Adapter base class, everything you want to adapt must subclass this.
Function _adapter_hook Undocumented
def _adapter_hook(iface, obj):
Undocumented
API Documentation for Stoqlib, generated by pydoctor at 2009-07-14 16:00:32.