summaryrefslogtreecommitdiff
path: root/pystache/template.py
blob: 7bde5352d84c13f2990904bbb78cf3f75c24496e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import re
import cgi

SECTION_RE = re.compile(r"{{\#([^\}]*)}}\s*(.+?)\s*{{/\1}}", re.M | re.S)
TAG_RE = re.compile(r"{{(#|=|!|<|>|\{)?(.+?)\1?}}+")

class Template(object):
    tag_types = {
        None: 'tag',
        '!': 'comment',
        '{': 'unescaped'
    }

    def __init__(self, template, context=None):
        self.template = template
        self.context = context or {}

    def render(self, template=None, context=None):
        """Turns a Mustache template into something wonderful."""
        template = template or self.template
        context = context or self.context

        template = self.render_sections(template, context)
        return self.render_tags(template, context)

    def render_sections(self, template, context):
        """Expands sections."""
        while 1:
            match = SECTION_RE.search(template)
            if match is None:
                break

            section, section_name, inner = match.group(0, 1, 2)

            it = context.get(section_name, None)
            replacer = ''
            if it and not hasattr(it, '__iter__'):
                replacer = inner
            elif it:
                insides = []
                for item in it:
                    insides.append(self.render(inner, item))
                replacer = ''.join(insides)

            template = template.replace(section, replacer)

        return template

    def render_tags(self, template, context):
        """Renders all the tags in a template for a context."""
        while 1:
            match = TAG_RE.search(template)
            if match is None:
                break

            tag, tag_type, tag_name = match.group(0, 1, 2)
            func = 'render_' + self.tag_types[tag_type]

            if hasattr(self, func):
                replacement = getattr(self, func)(tag_name, context)
                template = template.replace(tag, replacement)

        return template

    def render_tag(self, tag_name, context):
        """Given a tag name and context, finds and renders the tag."""
        return cgi.escape(context.get(tag_name, ''))

    def render_comment(self, tag_name=None, context=None):
        """Rendering a comment always returns nothing."""
        return ''

    def render_unescaped(self, tag_name=None, context=None):
        """Render a tag without escaping it."""
        return context.get(tag_name, '')