# HG changeset patch # User cmlenz # Date 1163201544 0 # Node ID 0cc031745884f5c6cd2a05c7ef1f57d4602827ae # Parent 96882a19168617f1d30781eaae7c969dc5c3dfa5 The `py:content`, `py:replace`, and `py:strip=""` directives are now expanded when the template is loaded (as opposed to when it's rendered). diff --git a/genshi/template/core.py b/genshi/template/core.py --- a/genshi/template/core.py +++ b/genshi/template/core.py @@ -177,6 +177,15 @@ expr = ' "%s"' % self.expr.source return '<%s%s>' % (self.__class__.__name__, expr) + def prepare(self, directives, stream): + """Called after the template stream has been completely parsed. + + The part of the template stream associated with the directive will be + replaced by what this function returns. This allows the directive to + optimize the template or validate the way the directive is used. + """ + return stream + def tagname(self): """Return the local tag name of the directive as it is used in templates. @@ -230,7 +239,7 @@ self.filters = [self._flatten, self._eval] - self.stream = self._parse(encoding) + self.stream = list(self._prepare(self._parse(encoding))) def __repr__(self): return '<%s "%s">' % (self.__class__.__name__, self.filename) @@ -288,6 +297,25 @@ return _interpolate(text, [cls._FULL_EXPR_RE, cls._SHORT_EXPR_RE]) _interpolate = classmethod(_interpolate) + def _prepare(self, stream): + """Call the `prepare` method of every directive instance in the + template so that various optimization and validation tasks can be + performed. + """ + for kind, data, pos in stream: + if kind is SUB: + directives, substream = data + for directive in directives[:]: + substream = directive.prepare(directives, substream) + substream = self._prepare(substream) + if directives: + yield kind, (directives, list(substream)), pos + else: + for event in substream: + yield event + else: + yield kind, data, pos + def generate(self, *args, **kwargs): """Apply the template to the given context data. diff --git a/genshi/template/directives.py b/genshi/template/directives.py --- a/genshi/template/directives.py +++ b/genshi/template/directives.py @@ -114,16 +114,9 @@ """ __slots__ = [] - def __call__(self, stream, ctxt, directives): - def _generate(): - yield stream.next() - yield EXPR, self.expr, (None, -1, -1) - event = stream.next() - for next in stream: - event = next - yield event - - return _apply_directives(_generate(), ctxt, directives) + def prepare(self, directives, stream): + directives.remove(self) + return [stream[0], (EXPR, self.expr, (None, -1, --1)), stream[-1]] class DefDirective(Directive): @@ -367,8 +360,9 @@ """ __slots__ = [] - def __call__(self, stream, ctxt, directives): - yield EXPR, self.expr, (None, -1, -1) + def prepare(self, directives, stream): + directives.remove(self) + return [(EXPR, self.expr, (None, -1, -1))] class StripDirective(Directive): @@ -406,11 +400,7 @@ def __call__(self, stream, ctxt, directives): def _generate(): - if self.expr: - strip = self.expr.evaluate(ctxt) - else: - strip = True - if strip: + if self.expr.evaluate(ctxt): stream.next() # skip start tag previous = stream.next() for event in stream: @@ -419,8 +409,13 @@ else: for event in stream: yield event + return _apply_directives(_generate(), ctxt, directives) - return _apply_directives(_generate(), ctxt, directives) + def prepare(self, directives, stream): + if not self.expr: + directives.remove(self) + return stream[1:-1] + return stream class ChooseDirective(Directive):