[Zope3-checkins] SVN: Zope3/branches/roger-contentprovider/src/zope/viewlet/ Fixed the API and tests to the new content provider API.

Stephan Richter srichter at cosmos.phy.tufts.edu
Tue Oct 25 00:01:56 EDT 2005


Log message for revision 39607:
  Fixed the API and tests to the new content provider API.
  

Changed:
  U   Zope3/branches/roger-contentprovider/src/zope/viewlet/README.txt
  U   Zope3/branches/roger-contentprovider/src/zope/viewlet/directives.txt
  U   Zope3/branches/roger-contentprovider/src/zope/viewlet/interfaces.py
  U   Zope3/branches/roger-contentprovider/src/zope/viewlet/manager.py
  U   Zope3/branches/roger-contentprovider/src/zope/viewlet/metaconfigure.py
  U   Zope3/branches/roger-contentprovider/src/zope/viewlet/metadirectives.py
  U   Zope3/branches/roger-contentprovider/src/zope/viewlet/viewlet.py

-=-
Modified: Zope3/branches/roger-contentprovider/src/zope/viewlet/README.txt
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/viewlet/README.txt	2005-10-25 02:59:26 UTC (rev 39606)
+++ Zope3/branches/roger-contentprovider/src/zope/viewlet/README.txt	2005-10-25 04:01:56 UTC (rev 39607)
@@ -17,13 +17,13 @@
 frequently want to define a region in our page and allow specialized content
 providers to be inserted based on configuration. Those specialized content
 providers are known viewlets and are only available inside viewlet managers,
-which are just a more complex example of a content provider.
+which are just a more complex example of content providers.
 
 Unfortunately, the Java world does not implement this layer separately. The
 viewlet manager is most similar to a Java "channel", but we decided against
 using this name, since it is very generic and not very meaningful. The viewlet
 has no Java counterpart, since Java does not implement content providers using
-a component archicture and thus does not register content providers
+a component architecture and thus does not register content providers
 specifically for viewlet managers, which I believe makes the Java
 implementation less usefull as a generic concept. In fact, the main design
 goal in the Java world is the implementation of reusable and sharable
@@ -67,7 +67,8 @@
 
 So initially nothing gets rendered:
 
-  >>> leftColumn()
+  >>> leftColumn.update()
+  >>> leftColumn.render()
   u''
 
 But now we register some viewlets for the manager
@@ -79,14 +80,17 @@
   ...     zope.interface.implements(interfaces.IViewlet)
   ...
   ...     def __init__(self, context, request, view, manager):
+  ...         self.__parent__ = view
+  ...
+  ...     def update(self):
   ...         pass
   ...
-  ...     def __call__(self):
+  ...     def render(self):
   ...         return u'<div class="box">It is sunny today!</div>'
 
   # Create a security checker for viewlets.
   >>> from zope.security.checker import NamesChecker, defineChecker
-  >>> viewletChecker = NamesChecker(('__call__', 'weight'))
+  >>> viewletChecker = NamesChecker(('update', 'render'))
   >>> defineChecker(WeatherBox, viewletChecker)
 
   >>> zope.component.provideAdapter(
@@ -99,9 +103,12 @@
   ...     zope.interface.implements(interfaces.IViewlet)
   ...
   ...     def __init__(self, context, request, view, manager):
+  ...         self.__parent__ = view
+  ...
+  ...     def update(self):
   ...         pass
   ...
-  ...     def __call__(self):
+  ...     def render(self):
   ...         return u'<div class="box">Patriots (23) : Steelers (7)</div>'
 
   >>> defineChecker(SportBox, viewletChecker)
@@ -114,7 +121,8 @@
 
 and thus the left column is filled:
 
-  >>> print leftColumn()
+  >>> leftColumn.update()
+  >>> print leftColumn.render()
   <div class="box">Patriots (23) : Steelers (7)</div>
   <div class="box">It is sunny today!</div>
 
@@ -129,7 +137,7 @@
   >>> open(leftColTemplate, 'w').write('''
   ... <div class="left-column">
   ...   <tal:block repeat="viewlet options/viewlets"
-  ...              replace="structure viewlet" />
+  ...              replace="structure viewlet/render" />
   ... </div>
   ... ''')
 
@@ -142,7 +150,8 @@
 variable that is an iterable of all the avialable viewlets in the correct
 order:
 
-  >>> print leftColumn().strip()
+  >>> leftColumn.update()
+  >>> print leftColumn.render().strip()
   <div class="left-column">
     <div class="box">Patriots (23) : Steelers (7)</div>
     <div class="box">It is sunny today!</div>
@@ -200,7 +209,8 @@
 
 So we get the weather box first and the sport box second:
 
-  >>> print leftColumn().strip()
+  >>> leftColumn.update()
+  >>> print leftColumn.render().strip()
   <div class="left-column">
     <div class="box">It is sunny today!</div>
     <div class="box">Patriots (23) : Steelers (7)</div>
@@ -212,7 +222,8 @@
 
 and the order should switch as well:
 
-  >>> print leftColumn().strip()
+  >>> leftColumn.update()
+  >>> print leftColumn.render().strip()
   <div class="left-column">
     <div class="box">Patriots (23) : Steelers (7)</div>
     <div class="box">It is sunny today!</div>
@@ -221,7 +232,8 @@
 Of course, we also can remove a shown viewlet:
 
   >>> weather = shown.pop()
-  >>> print leftColumn().strip()
+  >>> leftColumn.update()
+  >>> print leftColumn.render().strip()
   <div class="left-column">
     <div class="box">Patriots (23) : Steelers (7)</div>
   </div>
@@ -242,17 +254,17 @@
   'context'
   >>> base.request
   'request'
-  >>> base.view
+  >>> base.__parent__
   'view'
   >>> base.manager
   'manager'
 
-But a default `__call__()` method implementation is not provided:
+But a default ``render()`` method implementation is not provided:
 
-  >>> base()
+  >>> base.render()
   Traceback (most recent call last):
   ...
-  NotImplementedError: `__call__` method must be implemented by subclass.
+  NotImplementedError: `render` method must be implemented by subclass.
 
 If you have already an existing class that produces the HTML content in some
 method, then the ``SimpleAttributeViewlet`` might be for you, since it can be
@@ -270,22 +282,22 @@
   >>> foo = FooViewlet('context', 'request', 'view', 'manager')
   >>> foo.foo()
   'output'
-  >>> foo()
+  >>> foo.render()
   'output'
 
-If you specify `__call__` as the attribute an error is raised to prevent
+If you specify `render` as the attribute an error is raised to prevent
 infinite recursion:
 
-  >>> foo.__page_attribute__ = '__call__'
-  >>> foo()
+  >>> foo.__page_attribute__ = 'render'
+  >>> foo.render()
   Traceback (most recent call last):
   ...
-  AttributeError: __call__
+  AttributeError: render
 
 The same is true if the specified attribute does not exist:
 
   >>> foo.__page_attribute__ = 'bar'
-  >>> foo()
+  >>> foo.render()
   Traceback (most recent call last):
   ...
   AttributeError: 'FooViewlet' object has no attribute 'bar'
@@ -300,7 +312,7 @@
   >>> open(template, 'w').write('''<div>contents</div>''')
 
   >>> Demo = viewlet.SimpleViewletClass(template)
-  >>> print Demo(content, request, view, manager)()
+  >>> print Demo(content, request, view, manager).render()
   <div>contents</div>
 
 Now let's additionally specify a class that can provide additional features:
@@ -353,7 +365,7 @@
   >>> ztapi.browserResource('resource.js', JSResource)
 
   >>> JSViewlet = viewlet.JavaScriptViewlet('resource.js')
-  >>> print JSViewlet(content, request, view, manager)().strip()
+  >>> print JSViewlet(content, request, view, manager).render().strip()
   <script type="text/javascript" src="/@@/resource.js">
   </script>
 
@@ -369,14 +381,14 @@
   >>> ztapi.browserResource('resource.css', CSSResource)
 
   >>> CSSViewlet = viewlet.CSSViewlet('resource.css')
-  >>> print CSSViewlet(content, request, view, manager)().strip()
+  >>> print CSSViewlet(content, request, view, manager).render().strip()
   <link type="text/css" rel="stylesheet"
         href="/@@/resource.css" media="all" />
 
 You can also change the media type and the rel attribute:
 
   >>> CSSViewlet = viewlet.CSSViewlet('resource.css', media='print', rel='css')
-  >>> print CSSViewlet(content, request, view, manager)().strip()
+  >>> print CSSViewlet(content, request, view, manager).render().strip()
   <link type="text/css" rel="css" href="/@@/resource.css"
         media="print" />
 
@@ -470,19 +482,20 @@
   ...     def __init__(self, context, request, view):
   ...         self.context = context
   ...         self.request = request
-  ...         self.view = view
+  ...         self.__parent__ = view
   ...
-  ...     def rows(self):
+  ...     def update(self):
   ...         rows = []
   ...         for name, value in self.context.items():
   ...             rows.append(
   ...                 [zope.component.getMultiAdapter(
-  ...                     (value, self.request, self.view, self),
+  ...                     (value, self.request, self.__parent__, self),
   ...                     interfaces.IViewlet, name=colname)
   ...                  for colname in shownColumns])
-  ...         return rows
+  ...             [entry.update() for entry in rows[-1]]
+  ...         self.rows = rows
   ...
-  ...     def __call__(self, *args, **kw):
+  ...     def render(self, *args, **kw):
   ...         return self.index(*args, **kw)
 
 Now we need a template to produce the contents table:
@@ -492,7 +505,7 @@
   ... <table>
   ...   <tr tal:repeat="row view/rows">
   ...     <td tal:repeat="column row">
-  ...       <tal:block replace="structure column" />
+  ...       <tal:block replace="structure column/render" />
   ...     </td>
   ...   </tr>
   ... </table>
@@ -541,9 +554,13 @@
   >>> class NameViewlet(object):
   ...
   ...     def __init__(self, context, request, view, manager):
+  ...         self.__parent__ = view
   ...         self.context = context
   ...
-  ...     def __call__(self):
+  ...     def update(self):
+  ...         pass
+  ...
+  ...     def render(self):
   ...         return self.context.__name__
 
 and register it:
@@ -611,9 +628,13 @@
   >>> class SizeViewlet(object):
   ...
   ...     def __init__(self, context, request, view, manager):
+  ...         self.__parent__ = view
   ...         self.context = context
   ...
-  ...     def __call__(self):
+  ...     def update(self):
+  ...         pass
+  ...
+  ...     def render(self):
   ...         return size.interfaces.ISized(self.context).sizeForDisplay()
 
   >>> zope.component.provideAdapter(
@@ -750,9 +771,9 @@
   ...     def __init__(self, context, request, view):
   ...         self.context = context
   ...         self.request = request
-  ...         self.view = view
+  ...         self.__parent__ = view
   ...
-  ...     def rows(self):
+  ...     def update(self):
   ...         values = self.context.values()
   ...
   ...         if sortByColumn:
@@ -764,12 +785,13 @@
   ...         for value in values:
   ...             rows.append(
   ...                 [zope.component.getMultiAdapter(
-  ...                     (value, self.request, self.view, self),
+  ...                     (value, self.request, self.__parent__, self),
   ...                     interfaces.IViewlet, name=colname)
   ...                  for colname in shownColumns])
-  ...         return rows
+  ...             [entry.update() for entry in rows[-1]]
+  ...         self.rows = rows
   ...
-  ...     def __call__(self, *args, **kw):
+  ...     def render(self, *args, **kw):
   ...         return self.index(*args, **kw)
 
 As you can see, the concern of sorting is cleanly separated from generating

Modified: Zope3/branches/roger-contentprovider/src/zope/viewlet/directives.txt
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/viewlet/directives.txt	2005-10-25 02:59:26 UTC (rev 39606)
+++ Zope3/branches/roger-contentprovider/src/zope/viewlet/directives.txt	2005-10-25 04:01:56 UTC (rev 39607)
@@ -54,7 +54,8 @@
   True
   >>> manager.template is None
   True
-  >>> manager()
+  >>> manager.update()
+  >>> manager.render()
   u''
 
 However, this registration is not very useful, since we did specify a specific
@@ -88,7 +89,8 @@
   True
   >>> manager.template is None
   True
-  >>> manager()
+  >>> manager.update()
+  >>> manager.render()
   u''
 
 Next let's see what happens, if we specify a template for the viewlet manager:
@@ -125,7 +127,8 @@
   True
   >>> manager.template
   <BoundPageTemplateFile of ...<ViewletManager providing ILeftColumn>  ...>>
-  >>> print manager().strip()
+  >>> manager.update()
+  >>> print manager.render().strip()
   <div class="column">
   </div>
 
@@ -163,7 +166,8 @@
   True
   >>> manager.template
   <BoundPageTemplateFile of ...<ViewletManager providing ILeftColumn>  ...>>
-  >>> print manager().strip()
+  >>> manager.update()
+  >>> print manager.render().strip()
   <div class="column">
   </div>
 
@@ -214,12 +218,13 @@
   >>> viewlet = zope.component.getMultiAdapter(
   ...     (content, request, view, manager), interfaces.IViewlet,
   ...     name='weather')
-  >>> viewlet().strip()
+  >>> viewlet.render().strip()
   u'<div>sunny</div>'
 
 The manager now also gives us the output of the one and only viewlet:
 
-  >>> print manager().strip()
+  >>> manager.update()
+  >>> print manager.render().strip()
   <div class="column">
     <div class="entry">
       <div>sunny</div>
@@ -299,7 +304,7 @@
   >>> viewlet = zope.component.getMultiAdapter(
   ...     (content, request, view, manager), interfaces.IViewlet,
   ...     name='stock')
-  >>> viewlet()
+  >>> viewlet.render()
   u'SRC $5.19'
 
 A final feature the ``viewlet`` directive supports is the additional

Modified: Zope3/branches/roger-contentprovider/src/zope/viewlet/interfaces.py
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/viewlet/interfaces.py	2005-10-25 02:59:26 UTC (rev 39606)
+++ Zope3/branches/roger-contentprovider/src/zope/viewlet/interfaces.py	2005-10-25 04:01:56 UTC (rev 39607)
@@ -19,7 +19,7 @@
 
 import zope.interface
 import zope.schema
-from zope.app.i18n import ZopeMessageFactory as _
+from zope.app.i18n import ZopeMessageIDFactory as _
 
 from zope.contentprovider.interfaces import IContentProvider
 from zope.interface.common.mapping import IReadMapping

Modified: Zope3/branches/roger-contentprovider/src/zope/viewlet/manager.py
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/viewlet/manager.py	2005-10-25 02:59:26 UTC (rev 39606)
+++ Zope3/branches/roger-contentprovider/src/zope/viewlet/manager.py	2005-10-25 04:01:56 UTC (rev 39607)
@@ -33,17 +33,18 @@
     zope.interface.implements(interfaces.IViewletManager)
 
     def __init__(self, context, request, view):
+        self.__updated = False
+        self.__parent__ = view
         self.context = context
         self.request = request
-        self.view = view
 
 
     def __getitem__(self, name):
         """See zope.interface.common.mapping.IReadMapping"""
         # Find the viewlet
         viewlet = zope.component.queryMultiAdapter(
-            (self.context, self.request, self.view, self), interfaces.IViewlet,
-            name=name)
+            (self.context, self.request, self.__parent__, self),
+            interfaces.IViewlet, name=name)
 
         # If the viewlet was not found, then raise a lookup error
         if viewlet is None:
@@ -52,15 +53,14 @@
 
         # If the viewlet cannot be accessed, then raise an
         # unauthorized error
-        if not zope.security.canAccess(viewlet, '__call__'):
+        if not zope.security.canAccess(viewlet, 'render'):
             raise zope.security.interfaces.Unauthorized(
                 'You are not authorized to access the provider '
                 'called `%s`.' %name)
 
-        # Return the rendered viewlet.
+        # Return the viewlet.
         return viewlet
 
-
     def get(self, name, default=None):
         """See zope.interface.common.mapping.IReadMapping"""
         try:
@@ -76,7 +76,7 @@
         """
         # Only return viewlets accessible to the principal
         return [(name, viewlet) for name, viewlet in viewlets
-                if zope.security.canAccess(viewlet, '__call__')]
+                if zope.security.canAccess(viewlet, 'render')]
 
     def sort(self, viewlets):
         """Sort the viewlets.
@@ -86,24 +86,31 @@
         # By default, use the standard Python way of doing sorting.
         return sorted(viewlets, lambda x, y: cmp(x[1], y[1]))
 
-    def __call__(self, *args, **kw):
+    def update(self):
         """See zope.contentprovider.interfaces.IContentProvider"""
+        self.__updated = True
 
         # Find all content providers for the region
         viewlets = zope.component.getAdapters(
-            (self.context, self.request, self.view, self), interfaces.IViewlet)
+            (self.context, self.request, self.__parent__, self),
+            interfaces.IViewlet)
 
         viewlets = self.filter(viewlets)
         viewlets = self.sort(viewlets)
 
         # Just use the viewlets from now on
-        viewlets = [viewlet for name, viewlet in viewlets]
+        self.viewlets = [viewlet for name, viewlet in viewlets]
 
+        # Update all viewlets
+        [viewlet.update() for viewlet in self.viewlets]
+
+    def render(self):
+        """See zope.contentprovider.interfaces.IContentProvider"""
         # Now render the view
         if self.template:
-            return self.template(viewlets=viewlets)
+            return self.template(viewlets=self.viewlets)
         else:
-            return u'\n'.join([viewlet() for viewlet in viewlets])
+            return u'\n'.join([viewlet.render() for viewlet in self.viewlets])
 
 
 def ViewletManager(interface, template=None, bases=()):

Modified: Zope3/branches/roger-contentprovider/src/zope/viewlet/metaconfigure.py
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/viewlet/metaconfigure.py	2005-10-25 02:59:26 UTC (rev 39606)
+++ Zope3/branches/roger-contentprovider/src/zope/viewlet/metaconfigure.py	2005-10-25 04:01:56 UTC (rev 39607)
@@ -64,7 +64,7 @@
         new_class = manager.ViewletManager(provides, bases=(class_, ))
 
     # Register some generic attributes with the security dictionary
-    for attr_name in ('browserDefault', '__call__', 'publishTraverse'):
+    for attr_name in ('browserDefault', 'update', 'render', 'publishTraverse'):
         required[attr_name] = permission
 
     # Register the ``provides`` interface and register fields in the security
@@ -100,7 +100,7 @@
     _context, name, permission,
     for_=Interface, layer=IDefaultBrowserLayer, view=IBrowserView,
     manager=interfaces.IViewletManager, class_=None, template=None,
-    attribute='__call__', allowed_interface=None, allowed_attributes=None,
+    attribute='render', allowed_interface=None, allowed_attributes=None,
     **kwargs):
 
     # Security map dictionary
@@ -114,7 +114,7 @@
         raise ConfigurationError("Must specify a class or template")
 
     # Make sure that all the non-default attribute specifications are correct.
-    if attribute != '__call__':
+    if attribute != 'render':
         if template:
             raise ConfigurationError(
                 "Attribute and template cannot be used together.")
@@ -134,7 +134,7 @@
 
     # Make sure the has the right form, if specified.
     if class_:
-        if attribute != '__call__':
+        if attribute != 'render':
             if not hasattr(class_, attribute):
                 raise ConfigurationError(
                     "The provided class doesn't have the specified attribute "
@@ -172,7 +172,7 @@
         _context, kwargs.keys(), permission, required)
     viewmeta._handle_allowed_attributes(
         _context,
-        (attribute, 'browserDefault', '__call__', 'publishTraverse'),
+        (attribute, 'browserDefault', 'update', 'render', 'publishTraverse'),
         permission, required)
 
     # Register the interfaces.

Modified: Zope3/branches/roger-contentprovider/src/zope/viewlet/metadirectives.py
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/viewlet/metadirectives.py	2005-10-25 02:59:26 UTC (rev 39606)
+++ Zope3/branches/roger-contentprovider/src/zope/viewlet/metadirectives.py	2005-10-25 04:01:56 UTC (rev 39607)
@@ -20,7 +20,7 @@
 import zope.configuration.fields
 import zope.schema
 
-from zope.app.i18n import ZopeMessageFactory as _
+from zope.app.i18n import ZopeMessageIDFactory as _
 from zope.app.publisher.browser import metadirectives
 from zope.app.publisher.interfaces import browser
 

Modified: Zope3/branches/roger-contentprovider/src/zope/viewlet/viewlet.py
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/viewlet/viewlet.py	2005-10-25 02:59:26 UTC (rev 39606)
+++ Zope3/branches/roger-contentprovider/src/zope/viewlet/viewlet.py	2005-10-25 04:01:56 UTC (rev 39607)
@@ -21,7 +21,7 @@
 import sys
 import zope.interface
 
-from zope.app.pagetemplate.simpleviewclass import simple
+from zope.app.pagetemplate import simpleviewclass
 from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
 from zope.app.publisher.browser import BrowserView
 from zope.app.traversing import api
@@ -36,34 +36,40 @@
 
     def __init__(self, context, request, view, manager):
         super(ViewletBase, self).__init__(context, request)
-        # TODO: We need to evaluate whether we really want to expose all those
-        # objects in the object. Theoretically, we only want `request` and
-        # `manager`.
+        self.__parent__ = view
         self.context = context
         self.request = request
-        self.view = view
         self.manager = manager
 
-    def __call__(self):
+    def update(self):
+        pass
+
+    def render(self):
         raise NotImplementedError(
-            '`__call__` method must be implemented by subclass.')
+            '`render` method must be implemented by subclass.')
 
 
 class SimpleAttributeViewlet(ViewletBase):
     """A viewlet that uses a specified method to produce its content."""
 
-    def __call__(self, *args, **kw):
+    def render(self, *args, **kw):
         # If a class doesn't provide it's own call, then get the attribute
         # given by the browser default.
 
         attr = self.__page_attribute__
-        if attr == '__call__':
-            raise AttributeError("__call__")
+        if attr == 'render':
+            raise AttributeError("render")
 
         meth = getattr(self, attr)
         return meth(*args, **kw)
 
 
+class simple(simpleviewclass.simple):
+    """Simple viewlet class supporting the ``render()`` method."""
+
+    render = simpleviewclass.simple.__call__
+
+
 def SimpleViewletClass(template, offering=None, bases=(), attributes=None,
                        name=u''):
     """A function that can be used to generate a viewlet from a set of
@@ -99,7 +105,7 @@
                                 request=self.request)
         return resource()
 
-    def __call__(self, *args, **kw):
+    def render(self, *args, **kw):
         return self.index(*args, **kw)
 
 



More information about the Zope3-Checkins mailing list