[Checkins] SVN: zope.browserzcml2/trunk/src/zope/browserzcml2/ Implement basic directive schemas and the directive handlers for browser2:page

Philipp von Weitershausen philikon at philikon.de
Fri Apr 21 13:23:08 EDT 2006


Log message for revision 67232:
  Implement basic directive schemas and the directive handlers for browser2:page
  and browser2:pageTemplate.
  

Changed:
  A   zope.browserzcml2/trunk/src/zope/browserzcml2/README.txt
  A   zope.browserzcml2/trunk/src/zope/browserzcml2/browserzcml2-meta.zcml
  A   zope.browserzcml2/trunk/src/zope/browserzcml2/interfaces.py
  A   zope.browserzcml2/trunk/src/zope/browserzcml2/meta.zcml
  A   zope.browserzcml2/trunk/src/zope/browserzcml2/test.pt
  A   zope.browserzcml2/trunk/src/zope/browserzcml2/tests.py
  A   zope.browserzcml2/trunk/src/zope/browserzcml2/zcml.py

-=-
Added: zope.browserzcml2/trunk/src/zope/browserzcml2/README.txt
===================================================================
--- zope.browserzcml2/trunk/src/zope/browserzcml2/README.txt	2006-04-21 16:43:55 UTC (rev 67231)
+++ zope.browserzcml2/trunk/src/zope/browserzcml2/README.txt	2006-04-21 17:23:03 UTC (rev 67232)
@@ -0,0 +1,192 @@
+zope.browserzcml2
+=================
+
+This package provides a few ZCML directives to register a browser
+pages in a much less magical way.  The rationale behind this is that
+pages implemented in Python should themselves be fully operational, in
+other words, publishable as registered adapters.  These directives are
+all part of the ``http://namespaces.zope.org/browser2`` namespace.
+
+In the following we will discuss three major use cases involving
+browser pages for which this package provides three ZCML directives:
+
+  * ``browser2:page``
+
+  * ``browser2:pageTemplate``
+
+  * ``browser2:pagesFromClass``
+
+
+Pages
+-----
+
+A browser page is nothing but a (browser) view that is *publishable*.
+Publishable means that it is basically the last piece in the traversal
+chain and the object that is responsible for the request.  It will be
+published.  Hence, it has to be publishable.  Publishability is
+determined by the ``IBrowerPublisher`` interface.  All pages should
+provide it.
+
+Simple page
+~~~~~~~~~~~
+
+Let's create a simple page.  For convenience, we can inherit from
+``zope.formlib.Page`` which will give us ``IBrowserPublisher``
+conformance:
+
+  >>> import zope.formlib
+  >>> class MacGyverPage(zope.formlib.Page):
+  ...     def __call__(self):
+  ...         return u"I've got a Swiss Army knife"
+
+Now we register the page.  This works almost like registering an
+adapter:
+
+  >>> run_config("""
+  ... <browser2:page
+  ...     for="*"
+  ...     name="simplepage.html"
+  ...     factory="zope.browserzcml2.README.MacGyverPage"
+  ...     permission="zope.Public"
+  ...     />
+  ... """)
+
+Then we can look up the page as an adapter.  We'll use a test request
+and a stub object.
+
+  >>> import zope.component
+  >>> from zope.publisher.browser import TestRequest
+  >>> request = TestRequest()
+  >>> page = zope.component.getMultiAdapter((object(), request),
+  ...                                       name=u'simplepage.html')
+
+We see that the adapter is an instance of our page class above and
+that we get the expected result upon calling it.
+
+  >>> page #doctest: +ELLIPSIS
+  <zope.browserzcml2.README.MacGyverPage object at ...>
+  >>> page()
+  u"I've got a Swiss Army knife"
+
+Other factories
+~~~~~~~~~~~~~~~
+
+Note that we require the page factory to implement
+``IBrowserPublisher``.  Something else won't work, e.g.:
+
+  >>> from zope.app.publisher.browser import BrowserView
+  >>> class MacGyverView(BrowserView):
+  ...     def __call__(self):
+  ...         return u"I drive a Jeep"
+
+  >>> run_config("""
+  ... <browser2:page
+  ...     for="*"
+  ...     name="justaview.html"
+  ...     factory="zope.browserzcml2.README.MacGyverView"
+  ...     permission="zope.Public"
+  ...     />
+  ... """) # doctest: +NORMALIZE_WHITESPACE
+  Traceback (most recent call last):
+    ...
+  ZopeXMLConfigurationError: File "<string>", line 6.0-11.6
+      ConfigurationError: The browser page factory needs to provide
+      IBrowserPublisher. A convenient base class is zope.formlib.Page.
+
+It is, however, absolutely possible that the supplied factory isn't in
+fact a class.  As long as it implements ``IBrowserPublisher``, it's
+ok:
+
+  >>> import zope.interface
+  >>> from zope.publisher.interfaces.browser import IBrowserPublisher
+  >>> @zope.interface.implementer(IBrowserPublisher)
+  ... def makeAMacGyverPage(context, request):
+  ...     return MacGyverPage(context, request)
+
+  >>> run_config("""
+  ... <browser2:page
+  ...     for="*"
+  ...     name="functionfactory.html"
+  ...     factory="zope.browserzcml2.README.makeAMacGyverPage"
+  ...     permission="zope.Public"
+  ...     />
+  ... """)
+
+  >>> page = zope.component.getMultiAdapter((object(), request),
+  ...                                       name=u'functionfactory.html')
+  >>> page #doctest: +ELLIPSIS
+  <zope.browserzcml2.README.MacGyverPage object at ...>
+  >>> page()
+  u"I've got a Swiss Army knife"
+
+Page with page template
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Rendering HTML from Python is tedious.  We therefore often turn this
+work over to Page Templates.  Referring to a Page Template in a page
+is easy:
+
+  >>> from zope.app.pagetemplate import ViewPageTemplateFile
+  >>> class MacGyverTemplatePage(zope.formlib.Page):
+  ...     __call__ = ViewPageTemplateFile('test.pt')
+
+The rest works just like with a pure-Python browser page:
+
+  >>> run_config("""
+  ... <browser2:page
+  ...     for="*"
+  ...     name="templatepage.html"
+  ...     factory="zope.browserzcml2.README.MacGyverTemplatePage"
+  ...     permission="zope.Public"
+  ...     />
+  ... """)
+
+  >>> page = zope.component.getMultiAdapter((object(), request),
+  ...                                       name=u'templatepage.html')
+  >>> page #doctest: +ELLIPSIS
+  <zope.browserzcml2.README.MacGyverTemplatePage object at ...>
+  >>> page()
+  u"Hi, the name's MacGyver.\n"
+
+
+Pages from Page Templates
+-------------------------
+
+We've just seen how to create pages that use Page Templates for
+rendering.  If that's all a page does, we can use a shortcut provided
+by the ``browser2:pageTemplate`` directive.  It works almost like the
+``browser2:page`` directive, except that it takes a ``template``
+parameter, not a ``factory`` parameter:
+
+  >>> run_config("""
+  ... <browser2:pageTemplate
+  ...     for="*"
+  ...     name="pagetemplate.html"
+  ...     template="test.pt"
+  ...     permission="zope.Public"
+  ...     />
+  ... """)
+
+We can look up the page like the others before, except now it won't be
+an instance of a class that we've implemented.  It'll be a dynamically
+generated class.  Either way, we are still able to call it like any
+other browser page:
+
+  >>> page = zope.component.getMultiAdapter((object(), request),
+  ...                                       name=u'pagetemplate.html')
+  >>> page #doctest: +ELLIPSIS
+  <zope.browserzcml2.zcml.TemplatePage object at ...>
+  >>> page()
+  u"Hi, the name's MacGyver.\n"
+
+
+Pages from classes
+------------------
+
+XXX
+
+
+Conflicts
+---------
+
+XXX


Property changes on: zope.browserzcml2/trunk/src/zope/browserzcml2/README.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: zope.browserzcml2/trunk/src/zope/browserzcml2/browserzcml2-meta.zcml
===================================================================
--- zope.browserzcml2/trunk/src/zope/browserzcml2/browserzcml2-meta.zcml	2006-04-21 16:43:55 UTC (rev 67231)
+++ zope.browserzcml2/trunk/src/zope/browserzcml2/browserzcml2-meta.zcml	2006-04-21 17:23:03 UTC (rev 67232)
@@ -0,0 +1 @@
+<include package="zope.browserzcml2" file="meta.zcml" />
\ No newline at end of file


Property changes on: zope.browserzcml2/trunk/src/zope/browserzcml2/browserzcml2-meta.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: zope.browserzcml2/trunk/src/zope/browserzcml2/interfaces.py
===================================================================
--- zope.browserzcml2/trunk/src/zope/browserzcml2/interfaces.py	2006-04-21 16:43:55 UTC (rev 67231)
+++ zope.browserzcml2/trunk/src/zope/browserzcml2/interfaces.py	2006-04-21 17:23:03 UTC (rev 67232)
@@ -0,0 +1,70 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Common parameters for browser directives
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+import zope.interface
+import zope.configuration.fields
+import zope.schema
+import zope.i18nmessageid
+_ = zope.i18nmessageid.MessageFactory('zope')
+
+from zope.app.publisher.browser.fields import MenuField
+from zope.app.security.fields import Permission
+
+class IViewCharacteristics(zope.interface.Interface):
+
+    for_ = zope.configuration.fields.GlobalObject(
+        title=_(u'Registered for'),
+        description=_(u"The interface or class this view is for."),
+        required=False
+        )
+
+    layer = zope.configuration.fields.GlobalInterface(
+        title=_('Layer'),
+        description=_("""Layer that the view is registered for.
+        This defaults to IDefaultBrowserLayer."""),
+        required=False,
+        )
+
+    name = zope.schema.TextLine(
+        title=_(u'Name'),
+        description=_(u"""The name of a view, which will show up e.g. in
+        URLs and other paths."""),
+        required=True
+        )
+
+    permission = Permission(
+        title=_(u'Permission'),
+        description=_(u"The permission needed to use the view."),
+        required=True
+        )
+
+class IRegisterInMenu(zope.interface.Interface):
+
+    menu = MenuField(
+        title=_(u'Menu'),
+        description=_(u"A browser menu to include the page in."),
+        required=False
+        )
+
+    title = zope.configuration.fields.MessageID(
+        title=_(u'Menu label'),
+        description=_(u"""The browser menu label for the page. Must be
+        supplied when the 'menu' attribute is supplied."""),
+        required=False
+        )


Property changes on: zope.browserzcml2/trunk/src/zope/browserzcml2/interfaces.py
___________________________________________________________________
Name: svn:eol-style
   + native

Added: zope.browserzcml2/trunk/src/zope/browserzcml2/meta.zcml
===================================================================
--- zope.browserzcml2/trunk/src/zope/browserzcml2/meta.zcml	2006-04-21 16:43:55 UTC (rev 67231)
+++ zope.browserzcml2/trunk/src/zope/browserzcml2/meta.zcml	2006-04-21 17:23:03 UTC (rev 67232)
@@ -0,0 +1,21 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:meta="http://namespaces.zope.org/meta">
+
+  <meta:directives namespace="http://namespaces.zope.org/browser2">
+
+    <meta:directive
+        name="pageTemplate"
+        schema=".zcml.IPageTemplateDirective"
+        handler=".zcml.pageTemplate"
+        />
+
+    <meta:directive
+        name="page"
+        schema=".zcml.IPageDirective"
+        handler=".zcml.page"
+        />
+
+  </meta:directives>
+
+</configure>


Property changes on: zope.browserzcml2/trunk/src/zope/browserzcml2/meta.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: zope.browserzcml2/trunk/src/zope/browserzcml2/test.pt
===================================================================
--- zope.browserzcml2/trunk/src/zope/browserzcml2/test.pt	2006-04-21 16:43:55 UTC (rev 67231)
+++ zope.browserzcml2/trunk/src/zope/browserzcml2/test.pt	2006-04-21 17:23:03 UTC (rev 67232)
@@ -0,0 +1 @@
+Hi, the name's MacGyver.
\ No newline at end of file


Property changes on: zope.browserzcml2/trunk/src/zope/browserzcml2/test.pt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: zope.browserzcml2/trunk/src/zope/browserzcml2/tests.py
===================================================================
--- zope.browserzcml2/trunk/src/zope/browserzcml2/tests.py	2006-04-21 16:43:55 UTC (rev 67231)
+++ zope.browserzcml2/trunk/src/zope/browserzcml2/tests.py	2006-04-21 17:23:03 UTC (rev 67232)
@@ -0,0 +1,59 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Tests
+
+$Id$
+"""
+import unittest
+from StringIO import StringIO
+
+import zope.browserzcml2
+import zope.component.testing
+from zope.testing import doctest, module
+from zope.configuration import xmlconfig
+
+__docformat__ = "reStructuredText"
+
+def run_config(snippet):
+    global _context
+    template = """\
+    <configure
+        xmlns="http://namespaces.zope.org/zope"
+        xmlns:browser2="http://namespaces.zope.org/browser2"
+        >
+        %s
+    </configure>"""
+    xmlconfig.string(template % snippet, _context)
+
+_context = None
+def setUp(test):
+    global _context
+    _context = xmlconfig.file('meta.zcml', zope.browserzcml2)
+    test.globs['run_config'] = run_config
+    module.setUp(test, 'zope.browserzcml2.README')
+    zope.component.testing.setUp(test)
+
+def tearDown(test):
+    global _context
+    _context = None
+    module.tearDown(test)
+    zope.component.testing.tearDown(test)
+
+def test_suite():
+    return unittest.TestSuite([
+        doctest.DocFileSuite('README.txt', setUp=setUp, tearDown=tearDown)
+        ])
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')


Property changes on: zope.browserzcml2/trunk/src/zope/browserzcml2/tests.py
___________________________________________________________________
Name: svn:eol-style
   + native

Added: zope.browserzcml2/trunk/src/zope/browserzcml2/zcml.py
===================================================================
--- zope.browserzcml2/trunk/src/zope/browserzcml2/zcml.py	2006-04-21 16:43:55 UTC (rev 67231)
+++ zope.browserzcml2/trunk/src/zope/browserzcml2/zcml.py	2006-04-21 17:23:03 UTC (rev 67232)
@@ -0,0 +1,105 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""ZCML directives and their handlers
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+import zope.configuration.fields
+import zope.configuration.exceptions
+import zope.formlib
+import zope.i18nmessageid
+_ = zope.i18nmessageid.MessageFactory('zope')
+
+from zope.publisher.interfaces.browser import IBrowserPublisher
+from zope.publisher.interfaces.browser import IDefaultBrowserLayer
+from zope.browserzcml2.interfaces import IViewCharacteristics
+from zope.browserzcml2.interfaces import IRegisterInMenu
+
+from zope.app.publisher.browser.viewmeta import _handle_menu
+from zope.app.pagetemplate import ViewPageTemplateFile
+from zope.app.component.metaconfigure import adapter
+
+class IPageTemplateDirective(IViewCharacteristics, IRegisterInMenu):
+
+    template = zope.configuration.fields.Path(
+        title=_(u"Template"),
+        description=_(u"""
+        Refers to a file containing a page template (should end in
+        extension '.pt' or '.html')."""),
+        required=True
+        )
+
+def pageTemplate(
+    _context, template,                                 # IPageTemplateDirective
+    for_, name, permission, layer=IDefaultBrowserLayer, # IViewCharacteristics
+    menu=None, title=None):                             # IRegisterInMenu
+
+    class TemplatePage(zope.formlib.Page):
+        __call__ = ViewPageTemplateFile(template)
+
+    page(_context, TemplatePage,
+         for_, name, permission, layer,
+         menu, title)
+
+class IPageDirective(IViewCharacteristics, IRegisterInMenu):
+    """Define multiple pages without repeating all of the parameters.
+
+    The pages directive allows multiple page views to be defined
+    without repeating the 'for', 'permission', 'class', 'layer',
+    'allowed_attributes', and 'allowed_interface' attributes.
+    """
+
+    factory = zope.configuration.fields.GlobalObject(
+        title=_(u"Factory"),
+        description=_(u"Adapter factory that returns the browser page. "
+                      "It should implement IBrowserPublisher."),
+        required=True,
+        )
+
+def page(
+    _context, factory,                                  # IPageDirective
+    for_, name, permission, layer=IDefaultBrowserLayer, # IViewCharacteristics
+    menu=None, title=None):                             # IRegisterInMenu
+    if not IBrowserPublisher.implementedBy(factory):
+        raise zope.configuration.exceptions.ConfigurationError(
+            "The browser page factory needs to provide IBrowserPublisher. "
+            "A convenient base class is zope.formlib.Page."
+            )
+    adapter(_context,
+            factory=(factory,),
+            for_=(for_, layer),
+            provides=IBrowserPublisher,
+            permission=permission,
+            name=name)
+
+    _handle_menu(_context, menu, title, (for_,), name, permission, layer)
+
+class IPagesFromClassDirective(IViewCharacteristics):
+    """Define multiple pages without repeating all of the parameters.
+
+    The pages directive allows multiple page views to be defined
+    without repeating the 'for', 'permission', 'class', 'layer',
+    'allowed_attributes', and 'allowed_interface' attributes.
+    """
+
+    class_ = zope.configuration.fields.GlobalObject(
+        title=_(u"Class"),
+        description=_(u"A class from which one or more browser pages will "
+                      "be dynamically created and registered"),
+        required=False,
+        )
+
+# XXX PagesFromClass


Property changes on: zope.browserzcml2/trunk/src/zope/browserzcml2/zcml.py
___________________________________________________________________
Name: svn:eol-style
   + native



More information about the Checkins mailing list