[Checkins] SVN: z3c.pt/trunk/ Implemented tuple-unpack in
tal:define statement.
Malthe Borch
mborch at gmail.com
Mon Dec 3 12:35:51 EST 2007
Log message for revision 82102:
Implemented tuple-unpack in tal:define statement.
Changed:
U z3c.pt/trunk/README.txt
U z3c.pt/trunk/setup.py
U z3c.pt/trunk/z3c/pt/BENCHMARKS.txt
U z3c.pt/trunk/z3c/pt/pagetemplate.py
U z3c.pt/trunk/z3c/pt/tal.py
U z3c.pt/trunk/z3c/pt/tal.txt
-=-
Modified: z3c.pt/trunk/README.txt
===================================================================
--- z3c.pt/trunk/README.txt 2007-12-03 17:09:37 UTC (rev 82101)
+++ z3c.pt/trunk/README.txt 2007-12-03 17:35:50 UTC (rev 82102)
@@ -7,7 +7,29 @@
In a nutshell:
- Templates are JIT-compiled
- - Only python-expressions are supported
+ - Only Python-expressions are supported
- Depends only on lxml
The METAL macro language is not supported; i18n is on the to-do.
+
+Template language
+-----------------
+
+The template language is based loosely on the TAL 1.4 specification
+found here:
+
+ * http://wiki.zope.org/ZPT/TALSpecification14
+
+1. Only Python-expressions are allowed. Expressions can have
+ try-except fallbacks using the vertical bar syntax:
+
+ tal:content="<expression> | <first fallback> | <second fallback> | ..."
+
+2. Tuples are allowed in the tal:define statement:
+
+ tal:define="(a, b, c) [1, 2, 3]"
+
+3. Generators are allowed in tal:repeat statements. Note that the
+ repeat variable is not available in this case.
+
+ tal:repeat="i <some generator>"
Modified: z3c.pt/trunk/setup.py
===================================================================
--- z3c.pt/trunk/setup.py 2007-12-03 17:09:37 UTC (rev 82101)
+++ z3c.pt/trunk/setup.py 2007-12-03 17:35:50 UTC (rev 82102)
@@ -1,7 +1,7 @@
from setuptools import setup, find_packages
import sys, os
-version = '0.1'
+version = '0.2'
setup(name='z3c.pt',
version=version,
Modified: z3c.pt/trunk/z3c/pt/BENCHMARKS.txt
===================================================================
--- z3c.pt/trunk/z3c/pt/BENCHMARKS.txt 2007-12-03 17:09:37 UTC (rev 82101)
+++ z3c.pt/trunk/z3c/pt/BENCHMARKS.txt 2007-12-03 17:35:50 UTC (rev 82102)
@@ -3,7 +3,7 @@
zope.pagetemplate z3c.pt
Hello World 4.482 1
-1000 x 10 table 4.540 1
+1000 x 10 table 4.513 1
Source
------
@@ -42,7 +42,7 @@
... </tr>
... </table>""")
- >>> # for i in range(20): a = template(table=table)
+ >>> for i in range(20): a = template(table=table)
>>> template = z3PageTemplate()
>>> template.pt_edit("""\
Modified: z3c.pt/trunk/z3c/pt/pagetemplate.py
===================================================================
--- z3c.pt/trunk/z3c/pt/pagetemplate.py 2007-12-03 17:09:37 UTC (rev 82101)
+++ z3c.pt/trunk/z3c/pt/pagetemplate.py 2007-12-03 17:35:50 UTC (rev 82102)
@@ -33,6 +33,8 @@
stream.write("def render(**_kwargs):")
stream.indent()
+
+ # globalize imports and set up process variables
stream.write("global _StringIO, _repeatdict, _escape")
stream.write("repeat = _repeatdict()")
stream.write("_attrs = {}")
Modified: z3c.pt/trunk/z3c/pt/tal.py
===================================================================
--- z3c.pt/trunk/z3c/pt/tal.py 2007-12-03 17:09:37 UTC (rev 82101)
+++ z3c.pt/trunk/z3c/pt/tal.py 2007-12-03 17:35:50 UTC (rev 82102)
@@ -1,6 +1,7 @@
import parser
import cgi
import xml.sax.saxutils
+import itertools
def expression(string):
"""
@@ -42,6 +43,18 @@
return expression
+def variable(string):
+ for var in string.split(', '):
+ var = var.strip()
+
+ if var in ('repeat',):
+ raise ValueError, "Invalid variable name '%s' (reserved)." % variable
+
+ if var.startswith('_'):
+ raise ValueError, \
+ "Invalid variable name '%s' (starts with an underscore)." % variable
+ yield var
+
def definition(string):
"""
TAL define-expression:
@@ -62,19 +75,19 @@
while string[i] == ' ':
i += 1
- # get variable name
- j = string.find(' ', i + 1)
- if j == -1:
- raise ValueError, "Invalid define clause (%s)." % string
+ # get variable definition
+ if string[i] == '(':
+ j = string.find(')', i+1)
+ if j == -1:
+ raise ValueError, "Invalid variable tuple definition (%s)." % string
+ var = variable(string[i+1:j])
+ j += 1
+ else:
+ j = string.find(' ', i + 1)
+ if j == -1:
+ raise ValueError, "Invalid define clause (%s)." % string
+ var = variable(string[i:j])
- variable = string[i:j]
-
- if variable in ('repeat',):
- raise ValueError, "Invalid variable name '%s' (reserved)." % variable
-
- if variable.startswith('_'):
- raise ValueError, \
- "Invalid variable name '%s' (starts with an underscore)." % variable
# get expression
i = j
while j < len(string):
@@ -90,7 +103,7 @@
else:
raise e
- defines.append((variable, expr))
+ defines.append((list(var), expr))
i = j + 1
@@ -164,28 +177,34 @@
class Define(object):
def __init__(self, value):
self.defines = [(v, Assign(e)) for v, e in definition(value)]
+ self.variables = list(itertools.chain(*[v for (v, e) in self.defines]))
+ if '' in self.variables:
+ import pdb; pdb.set_trace()
+
def update(self, node):
return node
def begin(self, stream):
- variables = [v for (v, e) in self.defines]
-
# save local variables already in scope
save = stream.save()
stream.write("%s = {}" % save)
- for var in variables:
+
+ for var in self.variables:
stream.write("if '%s' in _scope: %s['%s'] = %s" % (var, save, var, var))
stream.write("else: _scope.append('%s')" % var)
- for variable, assign in self.defines:
- assign.begin(stream, variable)
+ for variables, assign in self.defines:
+ if len(variables) == 1:
+ assign.begin(stream, variables[0])
+ else:
+ assign.begin(stream, u"(%s,)" % ", ".join(variables))
assign.end(stream)
def end(self, stream):
restore = stream.restore()
- for variable, expression in reversed(self.defines):
+ for variable in reversed(self.variables):
# restore local variables previously in scope
stream.write("if '%s' in %s:" % (variable, restore))
stream.indent()
@@ -258,21 +277,22 @@
class Attribute(object):
def __init__(self, value):
- self.attributes = definition(value)
+ self.attributes = [(v, Assign(e)) for v, e in definition(value)]
def update(self, node):
- for variable, expression in self.attributes:
- if variable in node.attrib:
- del node.attrib[variable]
+ for variables, expression in self.attributes:
+ for variable in variables:
+ if variable in node.attrib:
+ del node.attrib[variable]
return node
def begin(self, stream):
stream.write("_attrs = {}")
- for variable, expression in self.attributes:
- assign = Assign(expression)
- assign.begin(stream, "_attrs['%s']" % variable)
- assign.end(stream)
+ for variables, assign in self.attributes:
+ for variable in variables:
+ assign.begin(stream, "_attrs['%s']" % variable)
+ assign.end(stream)
def end(self, stream):
pass
Modified: z3c.pt/trunk/z3c/pt/tal.txt
===================================================================
--- z3c.pt/trunk/z3c/pt/tal.txt 2007-12-03 17:09:37 UTC (rev 82101)
+++ z3c.pt/trunk/z3c/pt/tal.txt 2007-12-03 17:35:50 UTC (rev 82102)
@@ -77,6 +77,23 @@
>>> b is not None and d is not None
True
+Tuple assignments:
+
+ >>> define = tal.Define("(e, f) [1, 2]")
+ >>> define.begin(stream)
+ >>> exec stream.getvalue()
+ >>> e == 1 and f == 2
+ True
+ >>> define.end(stream)
+
+Verify scope is preserved on tuple assignment:
+
+ >>> e = None; f = None
+ >>> _scope.append('e'); _scope.append('f')
+ >>> exec stream.getvalue()
+ >>> e is None and f is None
+ True
+
Using semicolons in expressions within a define:
>>> define = tal.Define("a ';'")
More information about the Checkins
mailing list