Commit 49b01517 authored by Evan Simpson's avatar Evan Simpson

Extend String expressions to allow paths, and complain about ambiguous $s.

parent b2f7b8bb
...@@ -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.1 $'[11:-2] __version__='$Revision: 1.2 $'[11:-2]
import re, sys import re, sys
from TALES import Engine, TALESError, _valid_name, NAME_RE from TALES import Engine, TALESError, _valid_name, NAME_RE
...@@ -116,6 +116,7 @@ def installHandlers(engine): ...@@ -116,6 +116,7 @@ def installHandlers(engine):
class PathExpr: class PathExpr:
def __init__(self, name, expr): def __init__(self, name, expr):
self._s = expr
self._name = name self._name = name
self._path = path = split(expr, '/') self._path = path = split(expr, '/')
self._base = base = path.pop(0) self._base = base = path.pop(0)
...@@ -163,31 +164,44 @@ class PathExpr: ...@@ -163,31 +164,44 @@ class PathExpr:
return mm['_ob'] return mm['_ob']
def __str__(self): def __str__(self):
return '%s expression "%s"' % (self._name, join(self._path, '/')) return '%s expression "%s"' % (self._name, self._s)
def __repr__(self): def __repr__(self):
return '<PathExpr %s:%s>' % (self._name, join(self._path, '/')) return '<PathExpr %s:%s>' % (self._name, self._s)
_interp1 = re.compile(r'\$(%s)' % NAME_RE) _interp = re.compile(r'\$(%(n)s)|\${(%(n)s(?:/%(n)s)*)}' % {'n': NAME_RE})
_interp2 = re.compile(r'\${(%s)}' % NAME_RE)
class StringExpr: class StringExpr:
def __init__(self, name, expr): def __init__(self, name, expr):
self._s = expr self._s = expr
if '%' in expr:
expr = replace(expr, '%', '%%')
self._vars = vars = []
if '$' in expr: if '$' in expr:
exprs = split(expr, '$$') parts = []
for i in range(len(exprs)): for exp in split(expr, '$$'):
expr = exprs[i] if parts: parts.append('$')
if '$' in expr: m = _interp.search(exp)
expr = _interp1.sub(r'%(\1)s', expr) if m is not None:
expr = _interp2.sub(r'%(\1)s', expr) parts.append(exp[:m.start()])
exprs[i] = expr parts.append('%s')
expr = join(exprs, '$') vars.append(PathExpr('path', m.group(1) or m.group(2)))
exp = exp[m.end():]
m = _interp.search(exp)
if '$' in exp:
raise TALESError, ('$ must be doubled or '
'followed by a variable name '
'in string expression "%s"' % expr)
parts.append(exp)
expr = join(parts, '')
self._expr = expr self._expr = expr
def __call__(self, econtext): def __call__(self, econtext):
return self._expr % econtext.contexts['var'] vvals = []
for var in self._vars:
vvals.append(var(econtext))
return self._expr % tuple(vvals)
def __str__(self): def __str__(self):
return 'string expression %s' % `self._s` return 'string expression %s' % `self._s`
......
...@@ -12,6 +12,8 @@ class ExpressionTests(unittest.TestCase): ...@@ -12,6 +12,8 @@ class ExpressionTests(unittest.TestCase):
e.compile('path:x') e.compile('path:x')
e.compile('x/y') e.compile('x/y')
e.compile('string:Fred') e.compile('string:Fred')
e.compile('string:A$B')
e.compile('string:a${x/y}b')
e.compile('python: 2 + 2') e.compile('python: 2 + 2')
def test_suite(): def test_suite():
......
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