Edgewall Software

Ticket #47: texttmpl.diff

File texttmpl.diff, 2.8 KB (added by cmlenz, 9 years ago)

Template subclass that does basic text-based templating

  • markup/template.py

     
    753753            self.filepath = None
    754754
    755755        self.filters = []
    756         self.parse()
     756        self.stream = self.parse()
    757757
    758758    def __repr__(self):
    759759        return '<%s "%s">' % (self.__class__.__name__, self.filename)
     
    851851            else:
    852852                stream.append((kind, data, pos))
    853853
    854         self.stream = stream
     854        return stream
    855855
    856856    _FULL_EXPR_RE = re.compile(r'(?<!\$)\$\{(.+?)\}', re.DOTALL)
    857857    _SHORT_EXPR_RE = re.compile(r'(?<!\$)\$([a-zA-Z][a-zA-Z0-9_\.]*)')
     
    10491049                yield kind, data, pos
    10501050
    10511051
     1052class TextTemplate(Template):
     1053    """
     1054    >>> tmpl = TextTemplate('''Dear $name,
     1055    ...
     1056    ... We have the following items for you:
     1057    ... #for item in items
     1058    ...  * $item
     1059    ... #endfor
     1060    ...
     1061    ... All the best,
     1062    ... Foobar
     1063    ... #endif''')
     1064    >>> print tmpl.generate(name='Joe', items=[1, 2, 3]).render('text')
     1065    Dear Joe,
     1066    <BLANKLINE>
     1067    We have the following items for you:
     1068     * 1
     1069     * 2
     1070     * 3
     1071    <BLANKLINE>
     1072    All the best,
     1073    Foobar
     1074    <BLANKLINE>
     1075    """
     1076
     1077    _DIRECTIVE_RE = re.compile('^#(\w+.*)\n?', re.MULTILINE)
     1078
     1079    def parse(self):
     1080        stream = [] # list of events of the "compiled" template
     1081        dirmap = {} # temporary mapping of directives to elements
     1082        depth = 0
     1083
     1084        source = self.source.read()
     1085        for idx, part in enumerate(self._DIRECTIVE_RE.split(source)):
     1086
     1087            if idx % 2:
     1088                directive = part.split(None, 1)
     1089                if len(directive) > 1:
     1090                    command, value = directive
     1091                else:
     1092                    command, value = directive[0], None
     1093
     1094                if not command.startswith('end'):
     1095                    cls = self._dir_by_name.get(command)
     1096                    if cls is None:
     1097                        raise BadDirectiveError(command)
     1098                    directive = cls(value, None, -1, -1)
     1099                    dirmap[depth] = (directive, len(stream))
     1100                    depth += 1
     1101                else:
     1102                    depth -= 1
     1103                    command = command[3:]
     1104                    if depth in dirmap:
     1105                        directive, start_offset = dirmap.pop(depth)
     1106                        substream = stream[start_offset:]
     1107                        stream[start_offset:] = [(SUB, ([directive], substream),
     1108                                                  (None, -1, -1))]
     1109
     1110            else:
     1111                for kind, data, pos in self._interpolate(part):
     1112                    stream.append((kind, data, (None, -1, -1)))
     1113
     1114        return stream
     1115
     1116
    10521117EXPR = Template.EXPR
    10531118SUB = Template.SUB
    10541119