Commit 3cd71660 authored by Christian Heimes's avatar Christian Heimes

Merged branches/tiran-zpt-pydefer r29702:30399 into trunk (including manual...

Merged branches/tiran-zpt-pydefer r29702:30399 into trunk (including manual merge because I renamed the original branch)
parents 361d2553 4c575f4a
......@@ -27,6 +27,9 @@ Zope Changes
Features added
- Added lazy: TAL expression and fixed defer: expression for python
expression
Bugs fixed
- Collector #1754: Fixed import of 'transaction' in
......
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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
#
##############################################################################
"""Defer and Lazy expression handler
defer expressions can be usesd for a design pattern called deferred evaluation.
Example:
<div tal:define="xis defer:string:x is $x">
<p tal:repeat="x python:range(3)"
tal:content="xis"></p>
</div>
Output:
<div>
<p>x is 0</p>
<p>x is 1</p>
<p>x is 2</p>
</div>
A lazy expressions is implemented in a similar way but has a different result. While
a defer expression is evaluated every time it is used according to its context a lazy
expression is evaluted only the first time it is used. Lazy expression are known
under the name lazy initialization of variables, too.
A common use case for a lazy expression is a lazy binding of a costly expression.
While one could call an expression only when it's required it makes sense to define
it only one time when it could be used multiple times.
Example
<div tal:define="lazyvar lazy:here/suckMyCPU">
<div tal:condition="foo" tal:content="lazyvar" />
<div tal:condition="bar" tal:content="lazyvar" />
<div tal:condition"python: not (foo or bar)">...</div>
</div>
"""
_marker = object()
# defer expression
class DeferWrapper:
"""Wrapper for defer: expression
"""
def __init__(self, expr, econtext):
self._expr = expr
self._econtext = econtext
def __str__(self):
return str(self())
def __call__(self):
return self._expr(self._econtext)
class DeferExpr:
"""defer: expression handler for deferred evaluation of the context
"""
def __init__(self, name, expr, compiler):
self._s = expr = expr.lstrip()
self._c = compiler.compile(expr)
def __call__(self, econtext):
return DeferWrapper(self._c, econtext)
def __repr__(self):
return 'defer:%s' % `self._s`
# lazy expression
class LazyWrapper(DeferWrapper):
"""Wrapper for lazy: expression
"""
def __init__(self, expr, econtext):
DeferWrapper.__init__(self, expr, econtext)
self._result = _marker
def __call__(self):
r = self._result
if r is _marker:
self._result = r = self._expr(self._econtext)
return r
class LazyExpr(DeferExpr):
"""lazy: expression handler for lazy initialization of expressions
"""
def __call__(self, econtext):
return LazyWrapper(self._c, econtext)
def __repr__(self):
return 'lazy:%s' % `self._s`
......@@ -20,10 +20,18 @@ for Python expressions, string literals, and paths.
__version__='$Revision: 1.45 $'[11:-2]
import re, sys
from TALES import Engine, CompilerError, _valid_name, NAME_RE, \
Undefined, Default, _parse_expr
from TALES import Engine
from TALES import CompilerError
from TALES import _valid_name
from TALES import NAME_RE
from TALES import Undefined
from TALES import Default
from TALES import _parse_expr
from Acquisition import aq_base, aq_inner, aq_parent
from DeferExpr import LazyWrapper
from DeferExpr import LazyExpr
from DeferExpr import DeferWrapper
from DeferExpr import DeferExpr
_engine = None
def getEngine():
......@@ -43,6 +51,7 @@ def installHandlers(engine):
reg('python', PythonExpr)
reg('not', NotExpr)
reg('defer', DeferExpr)
reg('lazy', LazyExpr)
import AccessControl
import AccessControl.cAccessControl
......@@ -50,7 +59,9 @@ acquisition_security_filter = AccessControl.cAccessControl.aq_validate
from AccessControl import getSecurityManager
from AccessControl.ZopeGuards import guarded_getattr
from AccessControl import Unauthorized
from ZRPythonExpr import PythonExpr, _SecureModuleImporter, call_with_ns
from ZRPythonExpr import PythonExpr
from ZRPythonExpr import _SecureModuleImporter
from ZRPythonExpr import call_with_ns
SecureModuleImporter = _SecureModuleImporter()
......@@ -235,29 +246,6 @@ class NotExpr:
def __repr__(self):
return 'not:%s' % `self._s`
class DeferWrapper:
def __init__(self, expr, econtext):
self._expr = expr
self._econtext = econtext
def __str__(self):
return str(self())
def __call__(self):
return self._expr(self._econtext)
class DeferExpr:
def __init__(self, name, expr, compiler):
self._s = expr = expr.lstrip()
self._c = compiler.compile(expr)
def __call__(self, econtext):
return DeferWrapper(self._c, econtext)
def __repr__(self):
return 'defer:%s' % `self._s`
def restrictedTraverse(object, path, securityManager,
get=getattr, has=hasattr, N=None, M=[],
TupleType=type(()) ):
......
......@@ -18,6 +18,7 @@ __version__='$Revision: 1.13 $'[11:-2]
from TALES import CompilerError
from sys import exc_info
from DeferExpr import DeferWrapper
class getSecurityManager:
'''Null security manager'''
......@@ -57,6 +58,9 @@ class PythonExpr:
names[vname] = val
else:
names[vname] = val
for key, val in names.items():
if isinstance(val, DeferWrapper):
names[key] = val()
return names
def __call__(self, econtext):
......
import os, sys, unittest
from Products.PageTemplates import Expressions
from Products.PageTemplates.DeferExpr import LazyWrapper
from Products.PageTemplates.DeferExpr import DeferWrapper
class ExpressionTests(unittest.TestCase):
......@@ -51,6 +53,15 @@ class ExpressionTests(unittest.TestCase):
assert ec.evaluate('x | string:x') == 'x'
assert ec.evaluate('x | string:$one') == '1'
assert ec.evaluate('x | not:exists:x')
def testWrappers(self):
"""Test if defer and lazy are returning their wrappers
"""
ec = self.ec
defer = ec.evaluate('defer: b')
lazy = ec.evaluate('lazy: b')
self.failUnless(isinstance(defer, DeferWrapper))
self.failUnless(isinstance(lazy, LazyWrapper))
def test_suite():
return unittest.makeSuite(ExpressionTests)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment