Commit f9db8744 authored by Evan Simpson's avatar Evan Simpson

Eliminate path modifiers, fix up 'exists:', and make tests conform.

parent f3d2bed3
...@@ -89,7 +89,7 @@ Page Template-specific implementation of TALES, with handlers ...@@ -89,7 +89,7 @@ Page Template-specific implementation of TALES, with handlers
for Python expressions, Python string literals, and paths. for Python expressions, Python string literals, and paths.
""" """
__version__='$Revision: 1.12 $'[11:-2] __version__='$Revision: 1.13 $'[11:-2]
import re, sys import re, sys
from TALES import Engine, CompilerError, _valid_name, NAME_RE, \ from TALES import Engine, CompilerError, _valid_name, NAME_RE, \
...@@ -108,7 +108,7 @@ def getEngine(): ...@@ -108,7 +108,7 @@ def getEngine():
def installHandlers(engine): def installHandlers(engine):
reg = engine.registerType reg = engine.registerType
pe = PathExpr pe = PathExpr
for pt in ('standard', 'path'): for pt in ('standard', 'path', 'exists'):
reg(pt, pe) reg(pt, pe)
reg('string', StringExpr) reg('string', StringExpr)
reg('python', PythonExpr) reg('python', PythonExpr)
...@@ -161,11 +161,7 @@ def render(ob, ns): ...@@ -161,11 +161,7 @@ def render(ob, ns):
raise raise
return ob return ob
path_modifiers = {'if': 0, 'exists': 0, 'nocall':0}
class PathExpr: class PathExpr:
_call_name = ''
def __init__(self, name, expr, engine): def __init__(self, name, expr, engine):
self._s = expr self._s = expr
self._name = name self._name = name
...@@ -173,22 +169,9 @@ class PathExpr: ...@@ -173,22 +169,9 @@ class PathExpr:
def _prepPath(self, path): def _prepPath(self, path):
path = split(strip(path), '/') path = split(strip(path), '/')
front = path.pop(0) base = path.pop(0)
fronts = split(replace(replace(front, '(', '( '), ')', ' ) '))
base = fronts.pop()
if not _valid_name(base): if not _valid_name(base):
raise CompilerError, 'Invalid variable name "%s"' % base raise CompilerError, 'Invalid variable name "%s"' % base
# Parse path modifiers
modifiers = path_modifiers.copy()
if fronts:
if len(fronts) < 2 or (fronts.pop(0) != '(' or
fronts.pop() != ')'):
raise CompilerError, 'Invalid path base "%s"' % front
for modifier in fronts:
if not modifiers.has_key(modifier):
raise CompilerError, ('Unknown path modifier "%s"'
% modifier)
modifiers[modifier] = 1
# Parse path # Parse path
dp = [] dp = []
for i in range(len(path)): for i in range(len(path)):
...@@ -196,7 +179,7 @@ class PathExpr: ...@@ -196,7 +179,7 @@ class PathExpr:
if e[:1] == '?' and _valid_name(e[1:]): if e[:1] == '?' and _valid_name(e[1:]):
dp.append((i, e[1:])) dp.append((i, e[1:]))
dp.reverse() dp.reverse()
return (base, path, dp), modifiers return base, path, dp
def _eval(self, (base, path, dp), econtext): def _eval(self, (base, path, dp), econtext):
path = list(path) # Copy! path = list(path) # Copy!
...@@ -225,30 +208,18 @@ class PathExpr: ...@@ -225,30 +208,18 @@ class PathExpr:
return Undefined(self._s, sys.exc_info()) return Undefined(self._s, sys.exc_info())
def __call__(self, econtext): def __call__(self, econtext):
for pathinfo, modifiers in self._paths: for pathinfo in self._paths:
ob = self._eval(pathinfo, econtext) ob = self._eval(pathinfo, econtext)
mod = modifiers.get exists = not isinstance(ob, Undefined)
if isinstance(ob, Undefined): if exists:
# This path is Undefined, so skip to the next. # We're done
if mod('exists'): break
if mod('if'): if self._name == 'exists':
return Default # All we wanted to know is whether one of the paths exist.
else: return exists
return 0 # Return the rendered object
continue return render(ob, econtext.contexts)
if mod('exists') and not mod('if'):
# This path is defined, and that's all we wanted to know.
return 1
if not mod('nocall'):
# Render the object, unless explicitly prevented.
ob = render(ob, econtext.contexts)
if mod('if') and not mod('exists') and not ob:
# Skip the object if it is false.
continue
return ob
# We ran out of paths to test, so return the last value.
return ob
def __str__(self): def __str__(self):
return '%s expression "%s"' % (self._name, self._s) return '%s expression "%s"' % (self._name, self._s)
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<div tal:define="x string:X;nil string:"> <div tal:define="x string:X;nil string:">
<p tal:content="x">1</p> <p tal:content="x">1</p>
<p tal:content="x | nil">2</p> <p tal:content="x | nil">2</p>
<p tal:content="(if) nil | x">3</p> <p tal:content="python:nil or x">3</p>
<p tal:content="y/z | x">4</p> <p tal:content="y/z | x">4</p>
<p tal:content="y/z | x | nil">5</p> <p tal:content="y/z | x | nil">5</p>
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<p tal:attributes="name y/z | nil">Z</p> <p tal:attributes="name y/z | nil">Z</p>
<p tal:attributes="name y/z | nothing">Z</p> <p tal:attributes="name y/z | nothing">Z</p>
<p tal:on-error="error/value" tal:content="a/b | (if) nil | c/d">Z</p> <p tal:on-error="python:str(error.value)" tal:content="a/b | c/d">Z</p>
</div> </div>
</body> </body>
</html> </html>
...@@ -10,12 +10,6 @@ class ExpressionTests(unittest.TestCase): ...@@ -10,12 +10,6 @@ class ExpressionTests(unittest.TestCase):
e = Expressions.getEngine() e = Expressions.getEngine()
for p in ('x', 'x/y', 'x/y/z'): for p in ('x', 'x/y', 'x/y/z'):
e.compile(p) e.compile(p)
for m in range(2 ** 3):
mods = ''
if m & 1: mods = 'if'
if m & 2: mods = mods + ' exists'
if m & 4: mods = mods + ' nocall'
e.compile('(%s) %s' % (mods, p))
e.compile('path:a|b|c/d/e') e.compile('path:a|b|c/d/e')
e.compile('string:Fred') e.compile('string:Fred')
e.compile('string:A$B') e.compile('string:A$B')
......
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