Skip to content

Commit

Permalink
Layer specialization is now observed such that template overrides are…
Browse files Browse the repository at this point in the history
… looked up in order of specialization.
  • Loading branch information
malthe committed Jul 15, 2008
1 parent 92aa210 commit 53325de
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 47 deletions.
10 changes: 6 additions & 4 deletions z3c/jbot/Five.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ Register override for HTTP-request layer.
>>> from zope.publisher.interfaces.browser import IHTTPRequest
>>> factory = z3c.jbot.manager.TemplateManagerFactory()
>>> component.provideAdapter(
... factory, (IHTTPRequest,), z3c.jbot.interfaces.ITemplateManager)
... factory, (IHTTPRequest,),
... z3c.jbot.interfaces.ITemplateManager, name='http')

>>> manager = factory.manager
>>> manager.registerDirectory(directory)
Expand All @@ -74,9 +75,10 @@ Examine the request.
>>> import z3c.jbot.utility
>>> z3c.jbot.utility.getRequest()
<zope.publisher.browser.TestRequest ...>

>>> z3c.jbot.utility.getManager() is manager
True

>>> managers = tuple(z3c.jbot.utility.getManagers())
>>> len(managers)
2

Verify that template attributes are set per request layer.

Expand Down
37 changes: 25 additions & 12 deletions z3c/jbot/README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ Register template manager factory. We'll register it for
>>> import z3c.jbot.interfaces
>>> factory = z3c.jbot.manager.TemplateManagerFactory()
>>> component.provideAdapter(
... factory, (interface.Interface,), z3c.jbot.interfaces.ITemplateManager)
... factory, (interface.Interface,),
... z3c.jbot.interfaces.ITemplateManager)

Register overrides directory.

Expand Down Expand Up @@ -79,7 +80,8 @@ override template factory for the HTTP-request layer.
>>> from zope.publisher.interfaces.browser import IHTTPRequest
>>> factory = z3c.jbot.manager.TemplateManagerFactory()
>>> component.provideAdapter(
... factory, (IHTTPRequest,), z3c.jbot.interfaces.ITemplateManager)
... factory, (IHTTPRequest,),
... z3c.jbot.interfaces.ITemplateManager, name='http')

Register overrides directory.

Expand Down Expand Up @@ -122,21 +124,22 @@ Going back to a basic request.
Let's verify that we only cook once per template source.

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

>>> interface.alsoProvides(request, IHTTPRequest)
>>> z3c.jbot.utility.getManager().registerTemplate(template)
>>> output = template()
>>> template._v_last_read and template._v_cooked
1

>>> template()
u'This template will override the example template.\n'

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

>>> interface.noLongerProvides(request, IHTTPRequest)
>>> z3c.jbot.utility.getManager().unregisterDirectory("%s/templates" % directory)

Configuring template override directories in ZCML
-------------------------------------------------
Expand All @@ -161,8 +164,21 @@ Once again, the override will be in effect.
>>> template()
u'This template will override the example template.\n'

>>> z3c.jbot.utility.getManager().unregisterDirectory("%s/templates" % directory)
Providing the HTTP-request layer does not change this.

>>> interface.alsoProvides(request, IHTTPRequest)

>>> template()
u'This template will override the example template.\n'

Unregister overrides.

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

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

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

>>> xmlconfig.xmlconfig(StringIO("""
Expand All @@ -173,11 +189,8 @@ Let's register overrides for the HTTP-request layer.
... </configure>
... """ % directory))

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

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

>>> interface.alsoProvides(request, IHTTPRequest)

>>> template()
u'This template will override the example template.\n'

25 changes: 17 additions & 8 deletions z3c/jbot/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
from zope.pagetemplate.pagetemplatefile import PageTemplateFile

import manager
import utility
import logging

logger = logging.getLogger('jbot')

PT_CLASSES = [PageTemplateFile]

if utility.ZOPE_2:
try:
import Products.PageTemplates.PageTemplateFile
PT_CLASSES.append(Products.PageTemplates.PageTemplateFile.PageTemplateFile)
except:
pass

class LayerProperty(property):
"""Layer-specific property class.
Expand Down Expand Up @@ -54,18 +58,23 @@ def _set(self, template, value):
# registration hook to template manager
def jbot(func):
def patch(self, *args, **kwargs):
manager = utility.getManager()
if manager is not None:
manager.registerTemplate(self)

for manager in utility.getManagers():
# register template; this call returns ``True`` if
# template was invalidated
if manager.registerTemplate(self):
break

return func(self, *args, **kwargs)
return patch

logger.info("Patching page template classes...")

# patch ``_cook_check``-method to insert jbot-logic
for pt_class in PT_CLASSES:
# patch ``_cook_check``-method to insert jbot-logic
pt_class._cook_check = jbot(pt_class._cook_check)

# munge per-layer attribute descriptors on class
# munge per-layer attribute descriptors on class
for pt_class in PT_CLASSES:
for name in ('_v_macros', '_v_program', '_v_cooked', '_v_errors',
'_v_last_read', '_v_warning', '_text_',
'filename', 'content_type', 'is_html'):
Expand Down
10 changes: 7 additions & 3 deletions z3c/jbot/manager.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from zope import interface

import os
import sys
import os.path

import utility
import interfaces

IGNORE = object()
Expand Down Expand Up @@ -70,8 +71,9 @@ def unregisterDirectory(self, directory):
del self.paths[filename]

for template in templates:
template._v_last_read = False

self.registerTemplate(template)
del self.templates[template]

def registerTemplate(self, template):
# only register templates that have a filename attribute
if not hasattr(template, 'filename'):
Expand Down Expand Up @@ -116,3 +118,5 @@ def registerTemplate(self, template):

# force cook
template._v_last_read = False

return True
22 changes: 17 additions & 5 deletions z3c/jbot/metaconfigure.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,26 @@ def handler(directory, layer):
gsm = component.getGlobalSiteManager()

# check if a template manager already exists
factory = gsm.adapters.lookup((layer,), interfaces.ITemplateManager)
factories = set(factory for name, factory in gsm.adapters.lookupAll(
(layer,), interfaces.ITemplateManager))

if factory is None:
factory = manager.TemplateManagerFactory()
component.provideAdapter(factory, (layer,), interfaces.ITemplateManager)
# if factory is available on the interface bases of the layer we
# discard it and register a new manager specialized to the layer
if layer is interface.Interface:
base_factories = set()
else:
base_factories = set(factory for name, factory in gsm.adapters.lookupAll(
(interface.implementedBy(layer.__bases__),), interfaces.ITemplateManager))

factory.manager.registerDirectory(directory)
try:
factory = factories.difference(base_factories).pop()
except KeyError:
factory = manager.TemplateManagerFactory()
component.provideAdapter(
factory, (layer,), interfaces.ITemplateManager, name=directory)

factory(layer).registerDirectory(directory)

def templateOverridesDirective(_context, directory, layer=interface.Interface):
_context.action(
discriminator = ('override', directory, layer),
Expand Down
30 changes: 15 additions & 15 deletions z3c/jbot/utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,27 @@
import interfaces

try:
import Products.PageTemplates
import Acquisition
ZOPE_2 = True
except ImportError:
except:
ZOPE_2 = False

def getRequest():
try:
i = zope.security.management.getInteraction()
for p in i.participations:
if IRequest.providedBy(p):
return p
except zope.security.interfaces.NoInteraction:
pass

if ZOPE_2:
# get request by acquisition
site = getSite()
if site is not None:
return site.REQUEST


try:
i = zope.security.management.getInteraction()
except zope.security.interfaces.NoInteraction:
return

for p in i.participations:
if IRequest.providedBy(p):
return p

def getLayer():
request = getRequest()

Expand All @@ -38,10 +39,9 @@ def getLayer():

return interface.Interface

def getManager():
def getManagers():
layer = getLayer()
gsm = component.getGlobalSiteManager()

factory = gsm.adapters.lookup((layer,), interfaces.ITemplateManager)
if factory is not None:
return factory.manager
for name, factory in gsm.adapters.lookupAll((layer,), interfaces.ITemplateManager):
yield factory(layer)

0 comments on commit 53325de

Please sign in to comment.