[Zope3-checkins]
SVN: Zope3/branches/roger-contentprovider/src/zope/viewlet/
Finally finished testing the viewlet package.
Stephan Richter
srichter at cosmos.phy.tufts.edu
Sat Oct 15 06:45:14 EDT 2005
Log message for revision 39461:
Finally finished testing the viewlet package.
Changed:
U Zope3/branches/roger-contentprovider/src/zope/viewlet/README.txt
U Zope3/branches/roger-contentprovider/src/zope/viewlet/css_viewlet.pt
U Zope3/branches/roger-contentprovider/src/zope/viewlet/javascript_viewlet.pt
U Zope3/branches/roger-contentprovider/src/zope/viewlet/tests.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-15 05:03:48 UTC (rev 39460)
+++ Zope3/branches/roger-contentprovider/src/zope/viewlet/README.txt 2005-10-15 10:45:13 UTC (rev 39461)
@@ -209,8 +209,157 @@
Viewlet Base Classes
--------------------
+To make the creation of viewlets simpler, a set of useful base classes and
+helper functions are provided:
+ >>> from zope.viewlet import viewlet
+The first class is a base class that simply defines the constructor:
+
+ >>> base = viewlet.ViewletBase('context', 'request', 'view', 'manager')
+ >>> base.context
+ 'context'
+ >>> base.request
+ 'request'
+ >>> base.view
+ 'view'
+ >>> base.manager
+ 'manager'
+
+But a default `__call__()` method implementation is not provided:
+
+ >>> base()
+ Traceback (most recent call last):
+ ...
+ NotImplementedError: `__call__` 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
+used to convert any class quickly into a viewlet:
+
+ >>> class FooViewlet(viewlet.SimpleAttributeViewlet):
+ ... __page_attribute__ = 'foo'
+ ...
+ ... def foo(self):
+ ... return 'output'
+
+The `__page_attribute__` attribute provides the name of the function to call for
+rendering.
+
+ >>> foo = FooViewlet('context', 'request', 'view', 'manager')
+ >>> foo.foo()
+ 'output'
+ >>> foo()
+ 'output'
+
+If you specify `__call__` as the attribute an error is raised to prevent
+infinite recursion:
+
+ >>> foo.__page_attribute__ = '__call__'
+ >>> foo()
+ Traceback (most recent call last):
+ ...
+ AttributeError: __call__
+
+The same is true if the specified attribute does not exist:
+
+ >>> foo.__page_attribute__ = 'bar'
+ >>> foo()
+ Traceback (most recent call last):
+ ...
+ AttributeError: 'FooViewlet' object has no attribute 'bar'
+
+To create simple template-based viewlets you can use the
+``SimpleViewletClass()`` function. This function is very similar to its view
+equivalent and is used by the ZCML directives to create viewlets. The result
+of this function call will be a fully functional viewlet class. Let's start by
+simply specifying a template only:
+
+ >>> template = os.path.join(temp_dir, 'demoTemplate.pt')
+ >>> open(template, 'w').write('''<div>contents</div>''')
+
+ >>> Demo = viewlet.SimpleViewletClass(template)
+ >>> print Demo(content, request, view, manager)()
+ <div>contents</div>
+
+Now let's additionally specify a class that can provide additional features:
+
+ >>> class MyViewlet(object):
+ ... myAttribute = 8
+
+ >>> Demo = viewlet.SimpleViewletClass(template, bases=(MyViewlet,))
+ >>> MyViewlet in Demo.__bases__
+ True
+ >>> Demo(content, request, view, manager).myAttribute
+ 8
+
+The final important feature is the ability to pass in further attributes to
+the class:
+
+ >>> Demo = viewlet.SimpleViewletClass(
+ ... template, attributes={'here': 'now', 'lucky': 3})
+ >>> demo = Demo(content, request, view, manager)
+ >>> demo.here
+ 'now'
+ >>> demo.lucky
+ 3
+
+As for all views, they must provide a name that can also be passed to the
+function:
+
+ >>> Demo = viewlet.SimpleViewletClass(template, name='demoViewlet')
+ >>> demo = Demo(content, request, view, manager)
+ >>> demo.__name__
+ 'demoViewlet'
+
+In addition to the the generic viewlet code above, the package comes with two
+viewlet base classes and helper functions for inserting CSS and Javascript
+links into HTML headers, since those two are so very common. I am only going
+to demonstrate the helper functions here, since those demonstrations will
+fully demonstrate the functionality of the base classes as well.
+
+The viewlet will look up the resource it was given and tries to produce the
+absolute URL for it:
+
+ >>> class JSResource(object):
+ ... def __init__(self, request):
+ ... self.request = request
+ ...
+ ... def __call__(self):
+ ... return '/@@/resource.js'
+
+ >>> from zope.app.testing import ztapi
+ >>> ztapi.browserResource('resource.js', JSResource)
+
+ >>> JSViewlet = viewlet.JavaScriptViewlet('resource.js')
+ >>> print JSViewlet(content, request, view, manager)().strip()
+ <script type="text/javascript" src="/@@/resource.js">
+ </script>
+
+The same works for the CSS resource viewlet:
+
+ >>> class CSSResource(object):
+ ... def __init__(self, request):
+ ... self.request = request
+ ...
+ ... def __call__(self):
+ ... return '/@@/resource.css'
+
+ >>> ztapi.browserResource('resource.css', CSSResource)
+
+ >>> CSSViewlet = viewlet.CSSViewlet('resource.css')
+ >>> print CSSViewlet(content, request, view, manager)().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()
+ <link type="text/css" rel="css" href="/@@/resource.css"
+ media="print" />
+
+
A Complex Example
-----------------
Modified: Zope3/branches/roger-contentprovider/src/zope/viewlet/css_viewlet.pt
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/viewlet/css_viewlet.pt 2005-10-15 05:03:48 UTC (rev 39460)
+++ Zope3/branches/roger-contentprovider/src/zope/viewlet/css_viewlet.pt 2005-10-15 10:45:13 UTC (rev 39461)
@@ -1,4 +1,4 @@
<link type="text/css" rel="stylesheet" href="somestyle.css" media="all"
- tal:attributes="rel viewlet/getRel;
- href viewlet/getURL;
- media viewlet/getMedia" />
+ tal:attributes="rel view/getRel;
+ href view/getURL;
+ media view/getMedia" />
Modified: Zope3/branches/roger-contentprovider/src/zope/viewlet/javascript_viewlet.pt
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/viewlet/javascript_viewlet.pt 2005-10-15 05:03:48 UTC (rev 39460)
+++ Zope3/branches/roger-contentprovider/src/zope/viewlet/javascript_viewlet.pt 2005-10-15 10:45:13 UTC (rev 39461)
@@ -1,3 +1,3 @@
<script type="text/javascript" src="some-library.js"
- tal:attributes="src viewlet/getURL">
+ tal:attributes="src view/getURL">
</script>
Modified: Zope3/branches/roger-contentprovider/src/zope/viewlet/tests.py
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/viewlet/tests.py 2005-10-15 05:03:48 UTC (rev 39460)
+++ Zope3/branches/roger-contentprovider/src/zope/viewlet/tests.py 2005-10-15 10:45:13 UTC (rev 39461)
@@ -22,7 +22,7 @@
import zope.security
from zope.testing import doctest
from zope.testing.doctestunit import DocTestSuite, DocFileSuite
-from zope.app.testing import setup
+from zope.app.testing import setup, ztapi
class TestParticipation(object):
principal = 'foobar'
@@ -31,6 +31,12 @@
def setUp(test):
setup.placefulSetUp()
+ # resource namespace setup
+ from zope.app.traversing.interfaces import ITraversable
+ from zope.app.traversing.namespace import resource
+ ztapi.provideAdapter(None, ITraversable, resource, name="resource")
+ ztapi.provideView(None, None, ITraversable, "resource", resource)
+
from zope.app.pagetemplate import metaconfigure
from zope.contentprovider import tales
metaconfigure.registerType('provider', tales.TALESProviderExpression)
Modified: Zope3/branches/roger-contentprovider/src/zope/viewlet/viewlet.py
===================================================================
--- Zope3/branches/roger-contentprovider/src/zope/viewlet/viewlet.py 2005-10-15 05:03:48 UTC (rev 39460)
+++ Zope3/branches/roger-contentprovider/src/zope/viewlet/viewlet.py 2005-10-15 10:45:13 UTC (rev 39461)
@@ -29,30 +29,28 @@
from zope.viewlet import interfaces
-class ViewletPageTemplateFile(ViewPageTemplateFile):
-
- def pt_getContext(self, instance, request, **_kw):
- namespace = super(ViewletPageTemplateFile, self).pt_getContext(
- instance, request, **_kw)
- namespace['view'] = instance.view
- namespace['viewlet'] = instance
- return namespace
-
-
-class SimpleViewlet(BrowserView):
+class ViewletBase(BrowserView):
"""Viewlet adapter class used in meta directive as a mixin class."""
zope.interface.implements(interfaces.IViewlet)
- def __init__(self, context, request, view, providerType):
- super(SimpleViewlet, self).__init__(context, request)
+ 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.context = context
+ self.request = request
self.view = view
+ self.manager = manager
+ def __call__(self):
+ raise NotImplementedError(
+ '`__call__` method must be implemented by subclass.')
-class SimpleAttributeViewlet(SimpleViewlet):
- def publishTraverse(self, request, name):
- raise NotFound(self, name, request)
+class SimpleAttributeViewlet(ViewletBase):
+ """A viewlet that uses a specified method to produce its content."""
def __call__(self, *args, **kw):
# If a class doesn't provide it's own call, then get the attribute
@@ -68,14 +66,17 @@
def SimpleViewletClass(template, offering=None, bases=(), attributes=None,
name=u''):
+ """A function that can be used to generate a viewlet from a set of
+ information.
+ """
# Get the current frame
if offering is None:
offering = sys._getframe(1).f_globals
# Create the base class hierarchy
- bases += (SimpleViewlet, simple)
+ bases += (simple, ViewletBase)
- attrs = {'index' : ViewletPageTemplateFile(template, offering),
+ attrs = {'index' : ViewPageTemplateFile(template, offering),
'__name__' : name}
if attributes:
attrs.update(attributes)
@@ -87,7 +88,10 @@
class ResourceViewletBase(object):
+ """A simple viewlet for inserting references to resources.
+ This is an abstract class that is expected to be used as a base only.
+ """
_path = None
def getURL(self):
@@ -104,8 +108,8 @@
src = os.path.join(os.path.dirname(__file__), 'javascript_viewlet.pt')
klass = type('JavaScriptViewlet',
- (ResourceViewletBase, SimpleViewlet),
- {'index': ViewletPageTemplateFile(src),
+ (ResourceViewletBase, ViewletBase),
+ {'index': ViewPageTemplateFile(src),
'_path': path})
return klass
@@ -128,8 +132,8 @@
src = os.path.join(os.path.dirname(__file__), 'css_viewlet.pt')
klass = type('CSSViewlet',
- (CSSResourceViewletBase, SimpleViewlet),
- {'index': ViewletPageTemplateFile(src),
+ (CSSResourceViewletBase, ViewletBase),
+ {'index': ViewPageTemplateFile(src),
'_path': path,
'_media':media,
'_rel':rel})
More information about the Zope3-Checkins
mailing list