summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Hammel <jhammel@mozilla.com>2010-11-16 19:37:07 -0800
committerJeff Hammel <jhammel@mozilla.com>2010-11-16 19:37:07 -0800
commitc12afe463f63249f70cace60fa2d8869cb452171 (patch)
treeb91f6509946da72de2e70b08cfdfd254130313af
parentde7296dae489bb1005dea700b7913b52998c2e2a (diff)
downloadtempita-c12afe463f63249f70cace60fa2d8869cb452171.tar.gz
[mq]: delimeters
-rw-r--r--tempita/__init__.py51
-rw-r--r--tests/test_template.txt7
2 files changed, 44 insertions, 14 deletions
diff --git a/tempita/__init__.py b/tempita/__init__.py
index 2af2147..83528b3 100644
--- a/tempita/__init__.py
+++ b/tempita/__init__.py
@@ -42,7 +42,6 @@ from tempita.compat3 import bytes, basestring_, next, is_unicode, coerce_text
__all__ = ['TemplateError', 'Template', 'sub', 'HTMLTemplate',
'sub_html', 'html', 'bunch']
-token_re = re.compile(r'\{\{|\}\}')
in_re = re.compile(r'\s+in\s+')
var_re = re.compile(r'^[a-z_][a-z0-9_]*$', re.I)
@@ -93,8 +92,22 @@ class Template(object):
default_inherit = None
def __init__(self, content, name=None, namespace=None, stacklevel=None,
- get_template=None, default_inherit=None, line_offset=0):
+ get_template=None, default_inherit=None, line_offset=0,
+ delimeters=None):
self.content = content
+
+ # set delimeters
+ if delimeters is None:
+ delimeters = (self.default_namespace['start_braces'],
+ self.default_namespace['end_braces'])
+ else:
+ assert len(delimeters) == 2 and all([isinstance(delimeter, basestring)
+ for delimeter in delimeters])
+ self.default_namespace = self.__class__.default_namespace.copy()
+ self.default_namespace['start_braces'] = delimeters[0]
+ self.default_namespace['end_braces'] = delimeters[1]
+ self.delimeters = delimeters
+
self._unicode = is_unicode(content)
if name is None and stacklevel is not None:
try:
@@ -115,7 +128,7 @@ class Template(object):
if lineno:
name += ':%s' % lineno
self.name = name
- self._parsed = parse(content, name=name, line_offset=line_offset)
+ self._parsed = parse(content, name=name, line_offset=line_offset, delimeters=self.delimeters)
if namespace is None:
namespace = {}
self.namespace = namespace
@@ -358,9 +371,9 @@ class Template(object):
return msg
-def sub(content, **kw):
+def sub(content, delimeters=None, **kw):
name = kw.get('__name')
- tmpl = Template(content, name=name)
+ tmpl = Template(content, name=name, delimeters=delimeters)
return tmpl.substitute(kw)
@@ -618,7 +631,7 @@ del _Empty
############################################################
-def lex(s, name=None, trim_whitespace=True, line_offset=0):
+def lex(s, name=None, trim_whitespace=True, line_offset=0, delimeters=None):
"""
Lex a string into chunks:
@@ -640,20 +653,27 @@ def lex(s, name=None, trim_whitespace=True, line_offset=0):
TemplateError: {{ inside expression at line 1 column 10
"""
+ if delimeters is None:
+ delimeters = ( Template.default_namespace['start_braces'],
+ Template.default_namespace['end_braces'] )
in_expr = False
chunks = []
last = 0
last_pos = (1, 1)
+ token_re = re.compile(r'%s|%s' % (re.escape(delimeters[0]),
+ re.escape(delimeters[1])))
for match in token_re.finditer(s):
expr = match.group(0)
pos = find_position(s, match.end(), line_offset)
- if expr == '{{' and in_expr:
- raise TemplateError('{{ inside expression', position=pos,
+ if expr == delimeters[0] and in_expr:
+ raise TemplateError('%s inside expression' % delimeters[0],
+ position=pos,
name=name)
- elif expr == '}}' and not in_expr:
- raise TemplateError('}} outside expression', position=pos,
+ elif expr == delimeters[1] and not in_expr:
+ raise TemplateError('%s outside expression' % delimeters[1],
+ position=pos,
name=name)
- if expr == '{{':
+ if expr == delimeters[0]:
part = s[last:match.start()]
if part:
chunks.append(part)
@@ -664,7 +684,7 @@ def lex(s, name=None, trim_whitespace=True, line_offset=0):
last = match.end()
last_pos = pos
if in_expr:
- raise TemplateError('No }} to finish last expression',
+ raise TemplateError('No %s to finish last expression' % delimeters[1],
name=name, position=last_pos)
part = s[last:]
if part:
@@ -744,7 +764,7 @@ def find_position(string, index, line_offset):
return (len(leading) + line_offset, len(leading[-1]) + 1)
-def parse(s, name=None, line_offset=0):
+def parse(s, name=None, line_offset=0, delimeters=None):
r"""
Parses a string into a kind of AST
@@ -794,7 +814,10 @@ def parse(s, name=None, line_offset=0):
...
TemplateError: Multi-line py blocks must start with a newline at line 1 column 3
"""
- tokens = lex(s, name=name, line_offset=line_offset)
+ if delimeters is None:
+ delimeters = ( Template.default_namespace['start_braces'],
+ Template.default_namespace['end_braces'] )
+ tokens = lex(s, name=name, line_offset=line_offset, delimeters=delimeters)
result = []
while tokens:
next_chunk, tokens = parse_expr(tokens, name)
diff --git a/tests/test_template.txt b/tests/test_template.txt
index 7c66a7f..232bd8e 100644
--- a/tests/test_template.txt
+++ b/tests/test_template.txt
@@ -14,6 +14,13 @@ example::
...
TypeError: cannot concatenate 'str' and 'int' objects at line 1 column 6
+You can also specifiy delimeters::
+
+ >>> sub('Hi ${name}', name='Ian', delimeters=('${', '}'))
+ 'Hi Ian'
+ >>> Template('Hi $[[repr(name)]]', delimeters=('$[[', ']]')).substitute(name='Ian')
+ "Hi 'Ian'"
+
It also has Django-style piping::
>>> sub('Hi {{name|repr}}', name='Ian')