[Zope3-dev] A generic Decorator class

Steve Alexander steve@cat-box.net
Sat, 16 Feb 2002 19:17:25 +0000


Hi Folks,

This email is moderately long. It explains the generic Decorator class 
I've written. I'd like to check Decorator.py into Zope3 somewhere, and 
I'm seeking opinions on this.



Continuing in my quest to write a real application using Zope 3, I've 
been extending the Contact example.

On thing I wanted to do was to make ContactInfoView show both the 
IContactInfo and the IPostalInfo information when viewed.

To do this, I added two more table rows to info.pt:

      <tr>
       <td>City:</td>
          <td tal:content="here/city">City</td>
      </tr>
      <tr>
       <td>State:</td>
          <td tal:content="here/state">State</td>
      </tr>


Then, I needed a way of combining the Contact object with the 
ContactCityState object (or whatever IPostalInfo is returned by the 
utility).

Here's what I've done:


----
from Zope.Publisher.Browser.AttributePublisher import AttributePublisher
from Zope.PageTemplate import PageTemplateFile
from IContactInfo import IContactInfo
from Zope.ComponentArchitecture import getAdapter
from IPostal import IPostalInfo

class ContactInfoView(AttributePublisher):
     """Provide an interface for viewing a contact
     """

     # Boiler plate
     def __init__(self, context):
         info = getAdapter(context, IPostalInfo, None)
         self._context=Decorator(context, info)

     def getContext(self):
         return self._context

     # Assert that we can only be applied to IContactInfo
     __used_for__=IContactInfo

     # Input form
     index = PageTemplateFile('info.pt', globals())

from Interface.Util import objectImplements
from types import ListType, TupleType

class Decorator(object):

     def __init__(self, context, decorations,
                  ArrayTypes=(ListType, TupleType)):
         """
         context is the object to be decorated. All
         attribute access falls through to this object.

         decorations is a sequence of objects.
         When an attribute is accessed, we see if it is a method
         of an interface of one of the decorations. If so,
         the decoration gets the message.
         """
         self._context=context
         if not isinstance(decorations, ArrayTypes):
             decorations=[decorations]
         self._decorations=decorations

     def __getattribute__(self, attr_name):
         for d in object.__getattribute__(self, '_decorations'):
             for i in objectImplements(d):
                 if attr_name in i.names():
                     return getattr(d, attr_name)

         return getattr(object.__getattribute__(self, '_context'),
                        attr_name)

----

Is there anything like this Decorator class in Zope3 at present?

It looks like it will be very useful when presenting a view combined 
from a content objects and one or more adapters.

Can I check this in? Is there a better way to achieve my aims?

Thanks.

--
Steve Alexander