Some more refinements:
* [include] now uses the current template's directory as a base for including other templates. Thus, you can [include "header.ezt"] to refer to a header.ezt template in the same directory. * _cmd_print() now looks for a "read" attribute on the value, to determine whether it is a stream (rather than a simple string). It can now copy a stream to the output. * added a simple catch for unclosed blocks. It doesn't say *what* is unclosed, but it will at least give you an error about it, rather than quiet failure. * [for] loops now iterate until the end of a list (determined internally by the interpreter when an IndexError occurs), rather than using len(list). This allows for lists of an indeterminate length to be used. git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@392 8cb11bc2-c004-0410-86c3-e597b4017df7remotes/tags/V0_9
parent
a2b579b5ac
commit
62f37986d5
44
lib/ezt.py
44
lib/ezt.py
|
@ -147,6 +147,7 @@ Directives
|
|||
import string
|
||||
import re
|
||||
from types import StringType, IntType, FloatType
|
||||
import os
|
||||
|
||||
#
|
||||
# This regular expression matches three alternatives:
|
||||
|
@ -205,9 +206,10 @@ class Template:
|
|||
self._execute(self.program, fp, ctx)
|
||||
|
||||
def _parse_file(self, fname, for_names=None):
|
||||
return self._parse(open(fname, "rt").read(), for_names)
|
||||
return self._parse(open(fname, "rt").read(), for_names,
|
||||
os.path.dirname(fname))
|
||||
|
||||
def _parse(self, text, for_names=None):
|
||||
def _parse(self, text, for_names=None, base=None):
|
||||
"""text -> string object containing the HTML template.
|
||||
|
||||
This is a private helper function doing the real work for method parse.
|
||||
|
@ -277,15 +279,22 @@ class Template:
|
|||
raise ArgCountSyntaxError()
|
||||
if args[1][0] == '"':
|
||||
include_filename = args[1][1:-1]
|
||||
if base:
|
||||
include_filename = os.path.join(base, include_filename)
|
||||
program.extend(self._parse_file(include_filename, for_names))
|
||||
else:
|
||||
program.append((self._cmd_include, _prepare_ref(args[1], for_names)))
|
||||
program.append((self._cmd_include,
|
||||
(_prepare_ref(args[1], for_names),
|
||||
base)))
|
||||
else:
|
||||
# implied PRINT command
|
||||
if len(args) > 1:
|
||||
raise ArgCountSyntaxError()
|
||||
program.append((self._cmd_print, _prepare_ref(args[0], for_names)))
|
||||
|
||||
if stack:
|
||||
### would be nice to say which blocks...
|
||||
raise UnclosedBlocksError()
|
||||
return program
|
||||
|
||||
def _execute(self, program, fp, ctx):
|
||||
|
@ -300,11 +309,23 @@ class Template:
|
|||
step[0](step[1], fp, ctx)
|
||||
|
||||
def _cmd_print(self, valref, fp, ctx):
|
||||
### type check the value
|
||||
fp.write(_get_value(valref, ctx))
|
||||
value = _get_value(valref, ctx)
|
||||
|
||||
def _cmd_include(self, valref, fp, ctx):
|
||||
self._execute(self._parse_file(_get_value(valref, ctx)), fp, ctx)
|
||||
# if the value has a 'read' attribute, then it is a stream: copy it
|
||||
if hasattr(value, 'read'):
|
||||
while 1:
|
||||
chunk = value.read(16384)
|
||||
if not chunk:
|
||||
break
|
||||
fp.write(chunk)
|
||||
else:
|
||||
fp.write(value)
|
||||
|
||||
def _cmd_include(self, (valref, base), fp, ctx):
|
||||
fname = _get_value(valref, ctx)
|
||||
if base:
|
||||
fname = os.path.join(base, fname)
|
||||
self._execute(self._parse_file(fname), fp, ctx)
|
||||
|
||||
def _cmd_if_any(self, args, fp, ctx):
|
||||
"If the value is a non-empty string or non-empty list, then T else F."
|
||||
|
@ -350,10 +371,10 @@ class Template:
|
|||
if isinstance(list, StringType):
|
||||
raise NeedSequenceError()
|
||||
refname = valref[0]
|
||||
ctx.for_index[refname] = [ list, 0 ]
|
||||
for i in range(len(list)):
|
||||
ctx.for_index[refname][1] = i
|
||||
ctx.for_index[refname] = idx = [ list, 0 ]
|
||||
for item in list:
|
||||
self._execute(section, fp, ctx)
|
||||
idx[1] = idx[1] + 1
|
||||
del ctx.for_index[refname]
|
||||
|
||||
|
||||
|
@ -427,6 +448,9 @@ class UnknownReference(Exception):
|
|||
class NeedSequenceError(Exception):
|
||||
pass
|
||||
|
||||
class UnclosedBlocksError(Exception):
|
||||
pass
|
||||
|
||||
# --- standard test environment ---
|
||||
def test_parse():
|
||||
assert _re_parse.split('[a]') == ['', '[a]', None, '']
|
||||
|
|
Loading…
Reference in New Issue