Skip to content

Instantly share code, notes, and snippets.

@sma
Created July 5, 2009 09:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sma/140888 to your computer and use it in GitHub Desktop.
Save sma/140888 to your computer and use it in GitHub Desktop.
import re
__all__ = ['Template', 'tag', 'filter', 'escape']
def Template(source):
tokens = r'\{%(?:"[^"]*"|[^"]+?)*?%\}\s*|\{\{(?:"[^"]*"|[^"]+?)*?\}\}|[^{]+|\{'
return Block(None, iter(re.findall(tokens, source)))
tags, filters = {}, {}
def tag(cls):
tags[cls.__name__.lower()] = cls; return cls
def filter(fun):
filters[fun.__name__] = Filter(fun); return fun
class Tag(object):
def __init__(self, parts, tokens):
pass
def render_body(context, body):
return u"".join(b.render(context) for b in body)
class Block(Tag):
def __init__(self, parts, tokens):
self.body, self.orelse = [], []; body = self.body
for token in tokens:
if token.startswith(u"{{"):
body.append(Variable(token[2:-2].strip()))
elif token.startswith(u"{%"):
token = token.rstrip()[2:-2].strip()
if token == "end":
break
if token == "else":
body = self.orelse
continue
parts = re.findall(r'"[^"]*"|\S+', token)
body.append(tags[parts[0]](parts, tokens))
else:
body.append(Static(token))
def render(self, context):
return render_body(context, self.body)
def eval_var(source, context):
return eval(source, filters, context)
@tag
class If(Block):
def __init__(self, parts, tokens):
self.source = parts[1]
Block.__init__(self, parts, tokens)
def render(self, context):
return render_body(context, self.body if eval_var(self.source, context) else self.orelse)
def merge(dct1, dct2): dct1.update(dct2); return dct1
@tag
class For(Block):
def __init__(self, parts, tokens):
self.name = parts[1]
assert 'in' == parts[2]
self.source = parts[3]
Block.__init__(self, parts, tokens)
def render(self, context):
items = eval_var(self.source, context)
if items:
return u"".join(render_body(merge(dict(context), {self.name: item}), self.body) for item in items)
else:
return render_body(context, self.orelse)
class Filter(object):
def __init__(self, f): self.f = f
def __ror__(self, other): return self.f(other)
@filter
def odd(v): return v % 2
def escape(s): return unicode(s).replace(u"&", u"&amp;").replace(u"<", u"&lt;")
class Variable(object):
def __init__(self, source):
self.source = source
def render(self, context):
return escape(unicode(eval(self.source, context)))
class Static(object):
def __init__(self, text):
self.text = text
def render(self, context):
return self.text
if __name__ == '__main__':
s = u"""
Beispiel:
{% if len(items) %}
{% for i in items %}
{% if i|odd %}{{ i }}{% else %}-{% end %}
{% end %}
{% end %}"""
print Template(s).render({'items': range(10)})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment