Skip to content

Commit

Permalink
Fixed issue with multiple layers; refactor, added tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
malthe committed Sep 26, 2009
1 parent f56634b commit 92e3a98
Show file tree
Hide file tree
Showing 13 changed files with 202 additions and 135 deletions.
20 changes: 20 additions & 0 deletions CHANGES.txt
@@ -0,0 +1,20 @@
Changes
=======

In next release...

- Improved test coverage.

- Refactored code, improving performance.

- Fixed issue with multiple layers.

0.2 (2008-07-14)
----------------

- Added layer support.

0.1 (2007-11-27)
----------------

- Initial public release.
13 changes: 4 additions & 9 deletions README.txt
@@ -1,5 +1,5 @@
Overview
--------
========

The z3c.jbot (or "Just a bunch of templates") package allows drop-in
page template overrides.
Expand All @@ -11,7 +11,6 @@ filename.

Overrides may be registered for a specific layer or any layer.


Canonical filename
------------------

Expand All @@ -24,28 +23,24 @@ Example:
Suppose you want to override: /plone/app/layout/viewlets/logo.pt
You would use the filename: plone.app.layout.viewlets.logo.pt


Registering a on overrides directory
------------------------------------

A Zope component configuration directive is available to configure
overrides.
overrides::

<include package="z3c.jbot" file="meta.zcml" />

<browser:templateOverrides
directory="<directory>"
layer="<layer>" />


Performance considerations
--------------------------

The use of jbot adds to the general page load time. On a site with
many templates this may be as much as 20 ms per request (a 7% increase
on my machine).
many templates this may be as much as 10 ms per request.


Author
------

Expand Down
4 changes: 2 additions & 2 deletions setup.py
@@ -1,12 +1,12 @@
from setuptools import setup, find_packages
import sys, os

version = '0.2dev'
version = '0.3dev'

setup(name='z3c.jbot',
version=version,
description="Drop-in template overrides.",
long_description=open("README.txt").read(),
long_description=open("README.txt").read() + open("CHANGES.txt").read(),
classifiers=[
"Framework :: Zope2",
"Framework :: Zope3",
Expand Down
167 changes: 94 additions & 73 deletions z3c/jbot/README.txt
Expand Up @@ -11,7 +11,7 @@ Let's instantiate a page template

>>> from zope.pagetemplate.pagetemplatefile import PageTemplateFile
>>> template = PageTemplateFile("tests/templates/example.pt")

A call to the template will render it.

>>> template()
Expand All @@ -30,41 +30,23 @@ of the original filename.
>>> import z3c.jbot.tests
>>> directory = z3c.jbot.tests.__path__[0]

Register template manager factory. We'll register it for
``zope.interface.Interface`` which makes it available on all layers.

>>> import z3c.jbot.manager
>>> import z3c.jbot.interfaces
>>> factory = z3c.jbot.manager.TemplateManagerFactory()
>>> component.provideAdapter(
... factory, (interface.Interface,),
... z3c.jbot.interfaces.ITemplateManager)

Register overrides directory.

>>> manager = factory.manager
>>> manager.registerDirectory("%s/templates" % directory)

Verify that we've registered the contents of the directory:

>>> manager.paths
{'z3c.jbot.tests.templates.example.pt': '.../z3c.jbot.tests.templates.example.pt',
'example.pt': '.../example.pt'}

Notice that the file "z3c.jbot.tests.templates.example.pt" is the
dotted name for the original example page template file.
Register overrides directory (by default for any request); we confirm
that it's registered for the same template manager.

>>> from z3c.jbot.metaconfigure import handler
>>> manager = handler("%s/overrides/interface" % directory, interface.Interface)

We should now see that the new filename will be used for rendering:

>>> template()
u'This template will override the example template.\n'
u'Override from ./interface.\n'

Before we proceed we'll clean up.

>>> manager.unregisterDirectory("%s/templates" % directory)
>>> manager.unregisterAllDirectories()

The template does indeed render the original template.

>>> template()
u'This is an example page template.\n'

Expand All @@ -74,73 +56,112 @@ template filename to the original.
>>> template.filename
'.../z3c.jbot/z3c/jbot/tests/templates/example.pt'

Overrides can be registered for a specific layer. Let's re-register an
override template factory for the HTTP-request layer.
Overrides can be registered for a specific layer. Let's register three
more overrides, one for the general-purpose ``IRequest`` layer, one
for the ``IHTTPRequest`` layer and one for a made-up ``IHTTPSRequest``
layer.

>>> from zope.publisher.interfaces.browser import IHTTPRequest
>>> factory = z3c.jbot.manager.TemplateManagerFactory()
>>> component.provideAdapter(
... factory, (IHTTPRequest,),
... z3c.jbot.interfaces.ITemplateManager, name='http')
>>> from zope.publisher.interfaces import IRequest
>>> from zope.publisher.interfaces.http import IHTTPRequest
>>> class IHTTPSRequest(IRequest):
... """An HTTPS request."""

Register overrides directory.

>>> manager = factory.manager
>>> manager.registerDirectory("%s/templates" % directory)
Next we register an overrides directory for the ``IRequest`` layer.

Let's set up an interaction with a base request.
>>> general = handler("%s/overrides/request" % directory, IRequest)

Let's set up an interaction with a trivial participation.

>>> class Participation:
... interaction = None

>>> participation = Participation()
>>> import zope.security.management
>>> import zope.publisher.base
>>> request = zope.publisher.base.BaseRequest("", {})
>>> IHTTPRequest.providedBy(request)
>>> zope.security.management.newInteraction(participation)

This participation does not provide even the basic request interface.

>>> IRequest.providedBy(participation)
False
>>> zope.security.management.newInteraction(request)

Since this request is not an HTTP-request, we don't expect the
override to be enabled.
We don't expect the template to be overriden for this interaction.

>>> template()
u'This is an example page template.\n'

Let's now engage in an interaction with an HTTP-request.

>>> interface.alsoProvides(request, IHTTPRequest)
Let's upgrade it.

>>> request = participation
>>> interface.alsoProvides(request, IRequest)

>>> template()
u'This template will override the example template.\n'
u'Override from ./request.\n'

>>> template._v_cooked
1

Going back to a basic request.

>>> interface.noLongerProvides(request, IHTTPRequest)
>>> IHTTPRequest.providedBy(request)
False

>>> interface.noLongerProvides(request, IRequest)
>>> template()
u'This is an example page template.\n'

Let's verify that we only cook once per template source.

>>> import z3c.jbot.utility
>>> output = template()
>>> template._v_last_read and template._v_cooked
1

>>> interface.alsoProvides(request, IHTTPRequest)
>>> interface.alsoProvides(request, IRequest)
>>> output = template()
>>> template._v_last_read and template._v_cooked
1

>>> template()
u'This template will override the example template.\n'
u'Override from ./request.\n'

Now, if we switch to the HTTP-layer.

>>> interface.noLongerProvides(request, IRequest)
>>> interface.alsoProvides(request, IHTTPRequest)

>>> template()
u'Override from ./request.\n'

>>> general.unregisterAllDirectories()

>>> template()
u'This is an example page template.\n'

>>> http = handler("%s/overrides/http" % directory, IHTTPRequest)
>>> https = handler("%s/overrides/https" % directory, IHTTPSRequest)

>>> template()
u'Override from ./http.\n'

Switching to HTTPS.

>>> for manager in z3c.jbot.utility.getManagers():
... manager.unregisterDirectory("%s/templates" % directory)

>>> interface.noLongerProvides(request, IHTTPRequest)

>>> interface.alsoProvides(request, IHTTPSRequest)

>>> template()
u'Override from ./https.\n'

>>> interface.noLongerProvides(request, IHTTPSRequest)

Unregister all directories (cleanup).

>>> for manager, layer in ((http, IHTTPRequest), (https, IHTTPSRequest)):
... interface.alsoProvides(request, layer)
... _ = template()
... manager.unregisterAllDirectories()
... interface.noLongerProvides(request, layer)

The override is no longer in effect.

>>> template()
u'This is an example page template.\n'

Configuring template override directories in ZCML
-------------------------------------------------

Expand All @@ -155,42 +176,42 @@ Let's try registering the directory again.

>>> xmlconfig.xmlconfig(StringIO("""
... <configure xmlns="http://namespaces.zope.org/browser">
... <templateOverrides directory="%s/templates" />
... <templateOverrides directory="%s/overrides/interface" />
... </configure>
... """ % directory))

Once again, the override will be in effect.

>>> template()
u'This template will override the example template.\n'
u'Override from ./interface.\n'

Providing the HTTP-request layer does not change this.

>>> interface.alsoProvides(request, IHTTPRequest)

>>> template()
u'This template will override the example template.\n'
u'Override from ./interface.\n'

Unregister overrides.
>>> manager = tuple(z3c.jbot.utility.getManagers())[0]
>>> manager.unregisterDirectory("%s/templates" % directory)

>>> for manager in z3c.jbot.utility.getManagers():
... manager.unregisterAllDirectories()

>>> template()
u'This is an example page template.\n'

Let's register overrides for the HTTP-request layer.

>>> xmlconfig.xmlconfig(StringIO("""
... <configure xmlns="http://namespaces.zope.org/browser">
... <templateOverrides
... directory="%s/templates"
... directory="%s/overrides/http"
... layer="zope.publisher.interfaces.browser.IHTTPRequest" />
... </configure>
... """ % directory))

If we now provide the HTTP-request layer, the override becomes active.
Since we now provide the HTTP-request layer, the override is used.

>>> template()
u'This template will override the example template.\n'
u'Override from ./http.\n'

0 comments on commit 92e3a98

Please sign in to comment.