# HG changeset patch # User Dirkjan Ochtman # Date 1239023394 -7200 # Node ID e61cb2813d2a882b807926e6e0aa5b03b3a44908 # Parent d895158fe8af5122b7346aeaa391a2551afff895 templater: separate template management and actual string processing diff -r d895158fe8af -r e61cb2813d2a mercurial/templater.py --- a/mercurial/templater.py Mon Apr 27 11:35:18 2009 +0200 +++ b/mercurial/templater.py Mon Apr 06 15:09:54 2009 +0200 @@ -21,7 +21,7 @@ return s.decode('string_escape') -class templater(object): +class engine(object): '''template expansion engine. template expansion works like this. a map file contains key=value @@ -44,6 +44,68 @@ template_re = re.compile(r"(?:(?:#(?=[\w\|%]+#))|(?:{(?=[\w\|%]+})))" r"(\w+)(?:(?:%(\w+))|((?:\|\w+)*))[#}]") + def __init__(self, loader, filters={}, defaults={}): + self.loader = loader + self.filters = filters + self.defaults = defaults + + def process(self, t, map): + '''Perform expansion. t is name of map element to expand. map contains + added elements for use during expansion. Is a generator.''' + tmpl = self.loader(t) + iters = [self._process(tmpl, map)] + while iters: + try: + item = iters[0].next() + except StopIteration: + iters.pop(0) + continue + if isinstance(item, str): + yield item + elif item is None: + yield '' + elif hasattr(item, '__iter__'): + iters.insert(0, iter(item)) + else: + yield str(item) + + def _process(self, tmpl, map): + '''Render a template. Returns a generator.''' + while tmpl: + m = self.template_re.search(tmpl) + if not m: + yield tmpl + break + + start, end = m.span(0) + key, format, fl = m.groups() + + if start: + yield tmpl[:start] + tmpl = tmpl[end:] + + if key in map: + v = map[key] + else: + v = self.defaults.get(key, "") + if callable(v): + v = v(**map) + if format: + if not hasattr(v, '__iter__'): + raise SyntaxError(_("Error expanding '%s%%%s'") + % (key, format)) + lm = map.copy() + for i in v: + lm.update(i) + yield self.process(format, lm) + else: + if fl: + for f in fl.split("|")[1:]: + v = self.filters[f](v) + yield v + +class templater(object): + def __init__(self, mapfile, filters={}, defaults={}, cache={}, minchunk=1024, maxchunk=65536): '''set up template engine. @@ -79,7 +141,7 @@ def __contains__(self, key): return key in self.cache or key in self.map - def _template(self, t): + def load(self, t): '''Get the template for the given template name. Use a local cache.''' if not t in self.cache: try: @@ -89,69 +151,14 @@ (self.map[t], inst.args[1])) return self.cache[t] - def _process(self, tmpl, map): - '''Render a template. Returns a generator.''' - while tmpl: - m = self.template_re.search(tmpl) - if not m: - yield tmpl - break - - start, end = m.span(0) - key, format, fl = m.groups() - - if start: - yield tmpl[:start] - tmpl = tmpl[end:] - - if key in map: - v = map[key] - else: - v = self.defaults.get(key, "") - if callable(v): - v = v(**map) - if format: - if not hasattr(v, '__iter__'): - raise SyntaxError(_("Error expanding '%s%%%s'") - % (key, format)) - lm = map.copy() - for i in v: - lm.update(i) - t = self._template(format) - yield self._process(t, lm) - else: - if fl: - for f in fl.split("|")[1:]: - v = self.filters[f](v) - yield v - def __call__(self, t, **map): - stream = self.expand(t, **map) + proc = engine(self.load, self.filters, self.defaults) + stream = proc.process(t, map) if self.minchunk: stream = util.increasingchunks(stream, min=self.minchunk, max=self.maxchunk) return stream - def expand(self, t, **map): - '''Perform expansion. t is name of map element to expand. map contains - added elements for use during expansion. Is a generator.''' - tmpl = self._template(t) - iters = [self._process(tmpl, map)] - while iters: - try: - item = iters[0].next() - except StopIteration: - iters.pop(0) - continue - if isinstance(item, str): - yield item - elif item is None: - yield '' - elif hasattr(item, '__iter__'): - iters.insert(0, iter(item)) - else: - yield str(item) - def templatepath(name=None): '''return location of template file or directory (if no name). returns None if not found.'''