From 69c44762bbfbdbcf5c85e534af691f03150a82c7 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Thu, 3 May 2012 13:46:46 -0700 Subject: Moved the partial-loading code from the parser module to the renderengine module. --- pystache/parser.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 4e05f3b..5a56f4c 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -9,7 +9,6 @@ This module is only meant for internal use by the renderengine module. import re -from pystache.common import TemplateNotFoundError from pystache.parsed import ParsedTemplate @@ -216,15 +215,9 @@ class Parser(object): elif tag_type == '>': - try: - # TODO: make engine.load() and test it separately. - template = engine.load_partial(tag_key) - except TemplateNotFoundError: - template = u'' - + template = engine.read_partial(tag_key) # Indent before rendering. template = re.sub(NON_BLANK_RE, leading_whitespace + ur'\1', template) - func = engine._make_get_partial(template) else: -- cgit v1.2.1 From 049a76c11318b3e389863f2f4a2e39fe73f7597a Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Thu, 3 May 2012 16:14:16 -0700 Subject: Added RenderEngine.resolve_context(). --- pystache/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 5a56f4c..4851303 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -215,7 +215,7 @@ class Parser(object): elif tag_type == '>': - template = engine.read_partial(tag_key) + template = engine.resolve_partial(tag_key) # Indent before rendering. template = re.sub(NON_BLANK_RE, leading_whitespace + ur'\1', template) func = engine._make_get_partial(template) -- cgit v1.2.1 From ef3ef4bf927dce83341b05ef61a251c3d450920c Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Fri, 4 May 2012 14:54:19 -0700 Subject: Refactored some of the parsing logic: delayed template slicing. --- pystache/parser.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 4851303..b2af35c 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -177,10 +177,10 @@ class Parser(object): including any trailing newlines). """ - parsed_section, content_end_index, end_index = \ + parsed_section, section_end_index, end_index = \ self.parse(template=template, start_index=start_index, section_key=section_key) - return parsed_section, template[start_index:content_end_index], end_index + return parsed_section, section_end_index, end_index def _handle_tag_type(self, template, parse_tree, tag_type, tag_key, leading_whitespace, end_index): @@ -205,12 +205,14 @@ class Parser(object): elif tag_type == '#': - parsed_section, section_contents, end_index = self._parse_section(template, end_index, tag_key) - func = engine._make_get_section(tag_key, parsed_section, section_contents, self._delimiters) + section_start_index = end_index + parsed_section, section_end_index, end_index = self._parse_section(template, end_index, tag_key) + func = engine._make_get_section(tag_key, parsed_section, self._delimiters, + template, section_start_index, section_end_index) elif tag_type == '^': - parsed_section, section_contents, end_index = self._parse_section(template, end_index, tag_key) + parsed_section, section_end_index, end_index = self._parse_section(template, end_index, tag_key) func = engine._make_get_inverse(tag_key, parsed_section) elif tag_type == '>': -- cgit v1.2.1 From 159849714fe362556e64d1923ff00789f0df47d9 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Fri, 4 May 2012 18:42:46 -0700 Subject: Moved more code (partial-related code) from parser to renderengine. --- pystache/parser.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index b2af35c..83b1c7e 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -14,7 +14,6 @@ from pystache.parsed import ParsedTemplate DEFAULT_DELIMITERS = (u'{{', u'}}') END_OF_LINE_CHARACTERS = [u'\r', u'\n'] -NON_BLANK_RE = re.compile(ur'^(.)', re.M) def _compile_template_re(delimiters=None): @@ -205,6 +204,7 @@ class Parser(object): elif tag_type == '#': + # TODO: move this code into RenderEngine. section_start_index = end_index parsed_section, section_end_index, end_index = self._parse_section(template, end_index, tag_key) func = engine._make_get_section(tag_key, parsed_section, self._delimiters, @@ -212,15 +212,13 @@ class Parser(object): elif tag_type == '^': + # TODO: move this code into RenderEngine. parsed_section, section_end_index, end_index = self._parse_section(template, end_index, tag_key) func = engine._make_get_inverse(tag_key, parsed_section) elif tag_type == '>': - template = engine.resolve_partial(tag_key) - # Indent before rendering. - template = re.sub(NON_BLANK_RE, leading_whitespace + ur'\1', template) - func = engine._make_get_partial(template) + func = engine._make_get_partial(tag_key, leading_whitespace) else: -- cgit v1.2.1 From f5b62fdccbf56c37e99dfca0ccfe1328a1d55713 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 05:04:53 -0700 Subject: Continued refactoring the parsing code: simplified _handle_tag_type(). --- pystache/parser.py | 61 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 29 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 83b1c7e..87bd577 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -144,87 +144,90 @@ class Parser(object): if tag_key != section_key: raise ParsingError("Section end tag mismatch: %s != %s" % (tag_key, section_key)) - return ParsedTemplate(parse_tree), match_index, end_index + return end_index, ParsedTemplate(parse_tree), match_index - index = self._handle_tag_type(template, parse_tree, tag_type, tag_key, leading_whitespace, end_index) + index, parsed_section, content_end_index = \ + self._parse_section(tag_type, tag_key, template, end_index) + # Variable index is now the next character to process. + + self._handle_tag_type(template, parse_tree, tag_type, tag_key, leading_whitespace, + end_index, content_end_index, parsed_section) # Save the rest of the template. parse_tree.append(template[index:]) return ParsedTemplate(parse_tree) - def _parse_section(self, template, start_index, section_key): + def _parse_section(self, tag_type, section_key, template, start_index): """ Parse the contents of a template section. Arguments: + tag_type: the tag symbol. + + section_key: the tag key of the section. + template: a unicode template string. start_index: the string index at which the section contents begin. - section_key: the tag key of the section. - Returns: a 3-tuple: + end_index: the string index after the closing section tag (and + including any trailing newlines), or the same index if there + is no section. + parsed_section: the section contents parsed as a ParsedTemplate instance. content_end_index: the string index after the section contents. - end_index: the string index after the closing section tag (and - including any trailing newlines). - """ - parsed_section, section_end_index, end_index = \ - self.parse(template=template, start_index=start_index, section_key=section_key) + if not tag_type in ('#', '^'): + return start_index, None, None - return parsed_section, section_end_index, end_index + # Returns: + # + # end_index, parsed_section, section_end_index + # + return self.parse(template=template, start_index=start_index, section_key=section_key) - def _handle_tag_type(self, template, parse_tree, tag_type, tag_key, leading_whitespace, end_index): + def _handle_tag_type(self, template, parse_tree, tag_type, tag_key, leading_whitespace, + section_start_index, section_end_index, parsed_section): # TODO: switch to using a dictionary instead of a bunch of ifs and elifs. if tag_type == '!': - return end_index + return if tag_type == '=': delimiters = tag_key.split() self._change_delimiters(delimiters) - return end_index - - engine = self.engine + return if tag_type == '': - func = engine._make_get_escaped(tag_key) + func = self.engine._make_get_escaped(tag_key) elif tag_type == '&': - func = engine._make_get_literal(tag_key) + func = self.engine._make_get_literal(tag_key) elif tag_type == '#': - # TODO: move this code into RenderEngine. - section_start_index = end_index - parsed_section, section_end_index, end_index = self._parse_section(template, end_index, tag_key) - func = engine._make_get_section(tag_key, parsed_section, self._delimiters, + func = self.engine._make_get_section(tag_key, parsed_section, self._delimiters, template, section_start_index, section_end_index) elif tag_type == '^': - # TODO: move this code into RenderEngine. - parsed_section, section_end_index, end_index = self._parse_section(template, end_index, tag_key) - func = engine._make_get_inverse(tag_key, parsed_section) + func = self.engine._make_get_inverse(tag_key, parsed_section) elif tag_type == '>': - func = engine._make_get_partial(tag_key, leading_whitespace) + func = self.engine._make_get_partial(tag_key, leading_whitespace) else: raise Exception("Unrecognized tag type: %s" % repr(tag_type)) parse_tree.append(func) - - return end_index - -- cgit v1.2.1 From e167059a23e4a3ed1b6942e1df916950828a57e0 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 05:19:58 -0700 Subject: More parser refactoring: eliminated _parse_section(). --- pystache/parser.py | 45 +++++++-------------------------------------- 1 file changed, 7 insertions(+), 38 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 87bd577..bd6706d 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -99,6 +99,8 @@ class Parser(object): parse_tree = [] index = start_index + content_end_index, parsed_section = None, None + while True: match = self._template_re.search(template, index) @@ -146,8 +148,10 @@ class Parser(object): return end_index, ParsedTemplate(parse_tree), match_index - index, parsed_section, content_end_index = \ - self._parse_section(tag_type, tag_key, template, end_index) + if tag_type in ('#', '^'): + index, parsed_section, content_end_index = self.parse(template, end_index, tag_key) + else: + index = end_index # Variable index is now the next character to process. self._handle_tag_type(template, parse_tree, tag_type, tag_key, leading_whitespace, @@ -158,41 +162,6 @@ class Parser(object): return ParsedTemplate(parse_tree) - def _parse_section(self, tag_type, section_key, template, start_index): - """ - Parse the contents of a template section. - - Arguments: - - tag_type: the tag symbol. - - section_key: the tag key of the section. - - template: a unicode template string. - - start_index: the string index at which the section contents begin. - - Returns: a 3-tuple: - - end_index: the string index after the closing section tag (and - including any trailing newlines), or the same index if there - is no section. - - parsed_section: the section contents parsed as a ParsedTemplate - instance. - - content_end_index: the string index after the section contents. - - """ - if not tag_type in ('#', '^'): - return start_index, None, None - - # Returns: - # - # end_index, parsed_section, section_end_index - # - return self.parse(template=template, start_index=start_index, section_key=section_key) - def _handle_tag_type(self, template, parse_tree, tag_type, tag_key, leading_whitespace, section_start_index, section_end_index, parsed_section): @@ -216,7 +185,7 @@ class Parser(object): elif tag_type == '#': func = self.engine._make_get_section(tag_key, parsed_section, self._delimiters, - template, section_start_index, section_end_index) + template, section_start_index, section_end_index) elif tag_type == '^': -- cgit v1.2.1 From ce1b81b1a5951c0ea34c4f8251ada3573af9c691 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 05:29:51 -0700 Subject: More parser refactoring: further simplified _handle_tag_type(). --- pystache/parser.py | 49 ++++++++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 27 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index bd6706d..9066c54 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -146,57 +146,52 @@ class Parser(object): if tag_key != section_key: raise ParsingError("Section end tag mismatch: %s != %s" % (tag_key, section_key)) - return end_index, ParsedTemplate(parse_tree), match_index + return end_index, match_index, ParsedTemplate(parse_tree) if tag_type in ('#', '^'): - index, parsed_section, content_end_index = self.parse(template, end_index, tag_key) + index, content_end_index, parsed_section = self.parse(template, end_index, tag_key) else: index = end_index # Variable index is now the next character to process. - self._handle_tag_type(template, parse_tree, tag_type, tag_key, leading_whitespace, - end_index, content_end_index, parsed_section) + node = self._make_node(template, tag_type, tag_key, leading_whitespace, + end_index, content_end_index, parsed_section) + parse_tree.append(node) # Save the rest of the template. parse_tree.append(template[index:]) return ParsedTemplate(parse_tree) - def _handle_tag_type(self, template, parse_tree, tag_type, tag_key, leading_whitespace, - section_start_index, section_end_index, parsed_section): + def _make_node(self, template, tag_type, tag_key, leading_whitespace, + section_start_index, section_end_index, parsed_section): + """ + Create and return a node of the parse tree. + """ # TODO: switch to using a dictionary instead of a bunch of ifs and elifs. if tag_type == '!': - return + return u'' if tag_type == '=': delimiters = tag_key.split() self._change_delimiters(delimiters) - return + return u'' if tag_type == '': + return self.engine._make_get_escaped(tag_key) - func = self.engine._make_get_escaped(tag_key) - - elif tag_type == '&': - - func = self.engine._make_get_literal(tag_key) - - elif tag_type == '#': + if tag_type == '&': + return self.engine._make_get_literal(tag_key) - func = self.engine._make_get_section(tag_key, parsed_section, self._delimiters, + if tag_type == '#': + return self.engine._make_get_section(tag_key, parsed_section, self._delimiters, template, section_start_index, section_end_index) - elif tag_type == '^': - - func = self.engine._make_get_inverse(tag_key, parsed_section) - - elif tag_type == '>': - - func = self.engine._make_get_partial(tag_key, leading_whitespace) - - else: + if tag_type == '^': + return self.engine._make_get_inverse(tag_key, parsed_section) - raise Exception("Unrecognized tag type: %s" % repr(tag_type)) + if tag_type == '>': + return self.engine._make_get_partial(tag_key, leading_whitespace) - parse_tree.append(func) + raise Exception("Unrecognized tag type: %s" % repr(tag_type)) -- cgit v1.2.1 From 2de83f87b16edad7fa028e56adf08548fa41a777 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 06:53:52 -0700 Subject: Refactoring parser: removed a local variable (index) from parse(). --- pystache/parser.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 9066c54..b573138 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -97,12 +97,11 @@ class Parser(object): """ parse_tree = [] - index = start_index content_end_index, parsed_section = None, None while True: - match = self._template_re.search(template, index) + match = self._template_re.search(template, start_index) if match is None: break @@ -110,7 +109,7 @@ class Parser(object): match_index = match.start() end_index = match.end() - before_tag = template[index : match_index] + before_tag = template[start_index : match_index] parse_tree.append(before_tag) @@ -149,9 +148,9 @@ class Parser(object): return end_index, match_index, ParsedTemplate(parse_tree) if tag_type in ('#', '^'): - index, content_end_index, parsed_section = self.parse(template, end_index, tag_key) + start_index, content_end_index, parsed_section = self.parse(template, end_index, tag_key) else: - index = end_index + start_index = end_index # Variable index is now the next character to process. node = self._make_node(template, tag_type, tag_key, leading_whitespace, @@ -159,7 +158,7 @@ class Parser(object): parse_tree.append(node) # Save the rest of the template. - parse_tree.append(template[index:]) + parse_tree.append(template[start_index:]) return ParsedTemplate(parse_tree) -- cgit v1.2.1 From 06e290786eec127290be976dcfce08081b01c08d Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 07:01:28 -0700 Subject: Work with ParsedTemplate instance instead of parse_tree list. --- pystache/parser.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index b573138..1202c66 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -96,7 +96,7 @@ class Parser(object): a ParsedTemplate instance. """ - parse_tree = [] + parsed_template = ParsedTemplate() content_end_index, parsed_section = None, None @@ -111,7 +111,7 @@ class Parser(object): before_tag = template[start_index : match_index] - parse_tree.append(before_tag) + parsed_template.add(before_tag) matches = match.groupdict() @@ -137,7 +137,7 @@ class Parser(object): if end_index < len(template): end_index += template[end_index] == '\n' and 1 or 0 elif leading_whitespace: - parse_tree.append(leading_whitespace) + parsed_template.add(leading_whitespace) match_index += len(leading_whitespace) leading_whitespace = '' @@ -145,7 +145,7 @@ class Parser(object): if tag_key != section_key: raise ParsingError("Section end tag mismatch: %s != %s" % (tag_key, section_key)) - return end_index, match_index, ParsedTemplate(parse_tree) + return end_index, match_index, parsed_template if tag_type in ('#', '^'): start_index, content_end_index, parsed_section = self.parse(template, end_index, tag_key) @@ -155,12 +155,12 @@ class Parser(object): node = self._make_node(template, tag_type, tag_key, leading_whitespace, end_index, content_end_index, parsed_section) - parse_tree.append(node) + parsed_template.add(node) # Save the rest of the template. - parse_tree.append(template[start_index:]) + parsed_template.add(template[start_index:]) - return ParsedTemplate(parse_tree) + return parsed_template def _make_node(self, template, tag_type, tag_key, leading_whitespace, section_start_index, section_end_index, parsed_section): -- cgit v1.2.1 From 906a0961e303859f23d67fa2b5e03e0913dc55c4 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 07:05:50 -0700 Subject: Reordered if block. --- pystache/parser.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 1202c66..806dac9 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -141,14 +141,15 @@ class Parser(object): match_index += len(leading_whitespace) leading_whitespace = '' - if tag_type == '/': + if tag_type in ('#', '^'): + start_index, content_end_index, parsed_section = self.parse(template, end_index, tag_key) + + elif tag_type == '/': if tag_key != section_key: raise ParsingError("Section end tag mismatch: %s != %s" % (tag_key, section_key)) return end_index, match_index, parsed_template - if tag_type in ('#', '^'): - start_index, content_end_index, parsed_section = self.parse(template, end_index, tag_key) else: start_index = end_index # Variable index is now the next character to process. -- cgit v1.2.1 From a6105f89965b61a8ae70b5953059d1f986d42abb Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 07:54:27 -0700 Subject: Reduced use of recursion in Parser.parse(). --- pystache/parser.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 806dac9..12e887e 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -97,9 +97,10 @@ class Parser(object): """ parsed_template = ParsedTemplate() - content_end_index, parsed_section = None, None + states = [] + while True: match = self._template_re.search(template, start_index) @@ -142,17 +143,28 @@ class Parser(object): leading_whitespace = '' if tag_type in ('#', '^'): - start_index, content_end_index, parsed_section = self.parse(template, end_index, tag_key) + # Cache current state. + state = (tag_type, tag_key, leading_whitespace, end_index, section_key, parsed_template) + states.append(state) + + # Initialize new state + start_index, section_key = end_index, tag_key + parsed_template = ParsedTemplate() + content_end_index, parsed_section = None, None - elif tag_type == '/': + continue + + if tag_type == '/': if tag_key != section_key: raise ParsingError("Section end tag mismatch: %s != %s" % (tag_key, section_key)) - return end_index, match_index, parsed_template + # Restore previous state with newly found section data. + start_index, content_end_index, parsed_section = end_index, match_index, parsed_template + + (tag_type, tag_key, leading_whitespace, end_index, section_key, parsed_template) = states.pop() else: start_index = end_index - # Variable index is now the next character to process. node = self._make_node(template, tag_type, tag_key, leading_whitespace, end_index, content_end_index, parsed_section) -- cgit v1.2.1 From 4f85f1f06c3d27683d1fdba563e985fd18c65d9f Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 08:16:14 -0700 Subject: Created _make_interpolation_node() and _make_section_node(). --- pystache/parser.py | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 12e887e..446ceb8 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -154,20 +154,22 @@ class Parser(object): continue + start_index = end_index + if tag_type == '/': if tag_key != section_key: raise ParsingError("Section end tag mismatch: %s != %s" % (tag_key, section_key)) # Restore previous state with newly found section data. - start_index, content_end_index, parsed_section = end_index, match_index, parsed_template + content_end_index, parsed_section = match_index, parsed_template (tag_type, tag_key, leading_whitespace, end_index, section_key, parsed_template) = states.pop() + node = self._make_section_node(template, tag_type, tag_key, parsed_section, + end_index, content_end_index) else: - start_index = end_index + node = self._make_interpolation_node(tag_type, tag_key, leading_whitespace) - node = self._make_node(template, tag_type, tag_key, leading_whitespace, - end_index, content_end_index, parsed_section) parsed_template.add(node) # Save the rest of the template. @@ -175,8 +177,7 @@ class Parser(object): return parsed_template - def _make_node(self, template, tag_type, tag_key, leading_whitespace, - section_start_index, section_end_index, parsed_section): + def _make_interpolation_node(self, tag_type, tag_key, leading_whitespace): """ Create and return a node of the parse tree. @@ -196,6 +197,17 @@ class Parser(object): if tag_type == '&': return self.engine._make_get_literal(tag_key) + if tag_type == '>': + return self.engine._make_get_partial(tag_key, leading_whitespace) + + raise Exception("Invalid symbol for interpolation tag: %s" % repr(tag_type)) + + def _make_section_node(self, template, tag_type, tag_key, parsed_section, + section_start_index, section_end_index): + """ + Create and return a node of the parse tree. + + """ if tag_type == '#': return self.engine._make_get_section(tag_key, parsed_section, self._delimiters, template, section_start_index, section_end_index) @@ -203,7 +215,4 @@ class Parser(object): if tag_type == '^': return self.engine._make_get_inverse(tag_key, parsed_section) - if tag_type == '>': - return self.engine._make_get_partial(tag_key, leading_whitespace) - - raise Exception("Unrecognized tag type: %s" % repr(tag_type)) + raise Exception("Invalid symbol for section tag: %s" % repr(tag_type)) -- cgit v1.2.1 From 8b2c78422a26f40f47ac2f2ccfe57d30991ae9d3 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 08:35:32 -0700 Subject: More parser simplifications. --- pystache/parser.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 446ceb8..3230058 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -142,30 +142,27 @@ class Parser(object): match_index += len(leading_whitespace) leading_whitespace = '' + start_index = end_index + if tag_type in ('#', '^'): # Cache current state. - state = (tag_type, tag_key, leading_whitespace, end_index, section_key, parsed_template) + state = (tag_type, tag_key, end_index, section_key, parsed_template) states.append(state) # Initialize new state - start_index, section_key = end_index, tag_key - parsed_template = ParsedTemplate() - content_end_index, parsed_section = None, None - + section_key, parsed_template = tag_key, ParsedTemplate() continue - start_index = end_index - if tag_type == '/': if tag_key != section_key: raise ParsingError("Section end tag mismatch: %s != %s" % (tag_key, section_key)) # Restore previous state with newly found section data. - content_end_index, parsed_section = match_index, parsed_template + parsed_section = parsed_template - (tag_type, tag_key, leading_whitespace, end_index, section_key, parsed_template) = states.pop() + (tag_type, tag_key, end_index, section_key, parsed_template) = states.pop() node = self._make_section_node(template, tag_type, tag_key, parsed_section, - end_index, content_end_index) + end_index, match_index) else: node = self._make_interpolation_node(tag_type, tag_key, leading_whitespace) -- cgit v1.2.1 From d7fac0b90fcbd46ea819071ebf26d6b0a7fd4786 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 08:58:37 -0700 Subject: Removed now unnecessary parse() arguments. --- pystache/parser.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 3230058..eb2f556 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -79,7 +79,7 @@ class Parser(object): self._delimiters = delimiters self.compile_template_re() - def parse(self, template, start_index=0, section_key=None): + def parse(self, template): """ Parse a template string starting at some index. @@ -96,8 +96,9 @@ class Parser(object): a ParsedTemplate instance. """ + start_index = 0 + content_end_index, parsed_section, section_key = None, None, None parsed_template = ParsedTemplate() - content_end_index, parsed_section = None, None states = [] @@ -110,9 +111,8 @@ class Parser(object): match_index = match.start() end_index = match.end() - before_tag = template[start_index : match_index] - - parsed_template.add(before_tag) + # Add string contents before the tag. + parsed_template.add(template[start_index:match_index]) matches = match.groupdict() @@ -169,7 +169,7 @@ class Parser(object): parsed_template.add(node) - # Save the rest of the template. + # Add the remainder of the template. parsed_template.add(template[start_index:]) return parsed_template -- cgit v1.2.1 From cf1c649f75313b5af1fca9a726d4760920b2f3ac Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 09:04:14 -0700 Subject: No need to cache the tag_key. --- pystache/parser.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index eb2f556..3a014ce 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -146,7 +146,7 @@ class Parser(object): if tag_type in ('#', '^'): # Cache current state. - state = (tag_type, tag_key, end_index, section_key, parsed_template) + state = (tag_type, end_index, section_key, parsed_template) states.append(state) # Initialize new state @@ -160,9 +160,9 @@ class Parser(object): # Restore previous state with newly found section data. parsed_section = parsed_template - (tag_type, tag_key, end_index, section_key, parsed_template) = states.pop() + (tag_type, section_start_index, section_key, parsed_template) = states.pop() node = self._make_section_node(template, tag_type, tag_key, parsed_section, - end_index, match_index) + section_start_index, match_index) else: node = self._make_interpolation_node(tag_type, tag_key, leading_whitespace) -- cgit v1.2.1 From f2d1b0ad3f06605e82844e45d39598ac56ad3da6 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 09:16:48 -0700 Subject: Tweaked two docstrings. --- pystache/parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 3a014ce..9e366cb 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -176,7 +176,7 @@ class Parser(object): def _make_interpolation_node(self, tag_type, tag_key, leading_whitespace): """ - Create and return a node of the parse tree. + Create and return a non-section node for the parse tree. """ # TODO: switch to using a dictionary instead of a bunch of ifs and elifs. @@ -202,7 +202,7 @@ class Parser(object): def _make_section_node(self, template, tag_type, tag_key, parsed_section, section_start_index, section_end_index): """ - Create and return a node of the parse tree. + Create and return a section node for the parse tree. """ if tag_type == '#': -- cgit v1.2.1 From 222e15f3982038e73df0bf0ecb0a35a8ab45f7be Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 09:36:56 -0700 Subject: Made the Parser class's compile method private. --- pystache/parser.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 9e366cb..1c6a5ee 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -72,12 +72,12 @@ class Parser(object): self._delimiters = delimiters self.engine = engine - def compile_template_re(self): + def _compile_delimiters(self): self._template_re = _compile_template_re(self._delimiters) def _change_delimiters(self, delimiters): self._delimiters = delimiters - self.compile_template_re() + self._compile_delimiters() def parse(self, template): """ @@ -96,6 +96,8 @@ class Parser(object): a ParsedTemplate instance. """ + self._compile_delimiters() + start_index = 0 content_end_index, parsed_section, section_key = None, None, None parsed_template = ParsedTemplate() -- cgit v1.2.1 From 7eef0a68507d1f01464d9ee980483ba2fca10c28 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 11:42:51 -0700 Subject: Avoid adding spurious empty strings to the parse tree. --- pystache/parser.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 1c6a5ee..99f8d13 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -113,8 +113,9 @@ class Parser(object): match_index = match.start() end_index = match.end() - # Add string contents before the tag. - parsed_template.add(template[start_index:match_index]) + # Avoid adding spurious empty strings to the parse tree. + if start_index != match_index: + parsed_template.add(template[start_index:match_index]) matches = match.groupdict() -- cgit v1.2.1 From f94aa621f125d59ebaf19e9bf110e23a04a10637 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 11:39:46 -0700 Subject: Started decoupling Parser from RenderEngine. --- pystache/parser.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 99f8d13..cb12306 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -52,6 +52,26 @@ class ParsingError(Exception): pass +class VariableNode(object): + + def __init__(self, key): + self.key = key + + def render(self, engine, context): + s = engine._get_string_value(context, self.key) + return engine.escape(s) + + +class LiteralNode(object): + + def __init__(self, key): + self.key = key + + def render(self, engine, context): + s = engine._get_string_value(context, self.key) + return engine.literal(s) + + class Parser(object): _delimiters = None @@ -192,10 +212,10 @@ class Parser(object): return u'' if tag_type == '': - return self.engine._make_get_escaped(tag_key) + return VariableNode(tag_key) if tag_type == '&': - return self.engine._make_get_literal(tag_key) + return LiteralNode(tag_key) if tag_type == '>': return self.engine._make_get_partial(tag_key, leading_whitespace) -- cgit v1.2.1 From a3999641857c1e7b620f3a2513576b493a6101d8 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 13:26:22 -0700 Subject: More progress on removing RenderEngine from Parser. --- pystache/parser.py | 62 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 6 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index cb12306..ad542c3 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -14,6 +14,7 @@ from pystache.parsed import ParsedTemplate DEFAULT_DELIMITERS = (u'{{', u'}}') END_OF_LINE_CHARACTERS = [u'\r', u'\n'] +NON_BLANK_RE = re.compile(ur'^(.)', re.M) def _compile_template_re(delimiters=None): @@ -52,13 +53,31 @@ class ParsingError(Exception): pass +## Node types + + +class CommentNode(object): + + def render(self, engine, context): + return u'' + + +class ChangeNode(object): + + def __init__(self, delimiters): + self.delimiters = delimiters + + def render(self, engine, context): + return u'' + + class VariableNode(object): def __init__(self, key): self.key = key def render(self, engine, context): - s = engine._get_string_value(context, self.key) + s = engine.fetch_string(context, self.key) return engine.escape(s) @@ -68,10 +87,41 @@ class LiteralNode(object): self.key = key def render(self, engine, context): - s = engine._get_string_value(context, self.key) + s = engine.fetch_string(context, self.key) return engine.literal(s) +class PartialNode(object): + + def __init__(self, key, indent): + self.key = key + self.indent = indent + + def render(self, engine, context): + template = engine.resolve_partial(self.key) + # Indent before rendering. + template = re.sub(NON_BLANK_RE, self.indent + ur'\1', template) + + return engine.render(template, context) + + +class InvertedNode(object): + + def __init__(self, key, parsed_section): + self.key = key + self.parsed_section = parsed_section + + def render(self, engine, context): + # TODO: is there a bug because we are not using the same + # logic as in fetch_string()? + data = engine.resolve_context(context, self.key) + # Note that lambdas are considered truthy for inverted sections + # per the spec. + if data: + return u'' + return engine._render_parsed(self.parsed_section, context) + + class Parser(object): _delimiters = None @@ -204,12 +254,12 @@ class Parser(object): """ # TODO: switch to using a dictionary instead of a bunch of ifs and elifs. if tag_type == '!': - return u'' + return CommentNode() if tag_type == '=': delimiters = tag_key.split() self._change_delimiters(delimiters) - return u'' + return ChangeNode(delimiters) if tag_type == '': return VariableNode(tag_key) @@ -218,7 +268,7 @@ class Parser(object): return LiteralNode(tag_key) if tag_type == '>': - return self.engine._make_get_partial(tag_key, leading_whitespace) + return PartialNode(tag_key, leading_whitespace) raise Exception("Invalid symbol for interpolation tag: %s" % repr(tag_type)) @@ -233,6 +283,6 @@ class Parser(object): template, section_start_index, section_end_index) if tag_type == '^': - return self.engine._make_get_inverse(tag_key, parsed_section) + return InvertedNode(tag_key, parsed_section) raise Exception("Invalid symbol for section tag: %s" % repr(tag_type)) -- cgit v1.2.1 From e4108154d7394e218695747b18543376d03ead42 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 14:44:21 -0700 Subject: Parser no longer requires a RenderEngine instance to parse. --- pystache/parser.py | 72 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 17 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index ad542c3..74ffc01 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -71,7 +71,7 @@ class ChangeNode(object): return u'' -class VariableNode(object): +class Tag(object): def __init__(self, key): self.key = key @@ -119,28 +119,65 @@ class InvertedNode(object): # per the spec. if data: return u'' - return engine._render_parsed(self.parsed_section, context) + return engine.render_parsed(self.parsed_section, context) -class Parser(object): +class SectionNode(object): - _delimiters = None - _template_re = None + # TODO: the template_ and parsed_template_ arguments don't both seem + # to be necessary. Can we remove one of them? For example, if + # callable(data) is True, then the initial parsed_template isn't used. + def __init__(self, key, parsed_contents, delimiters, template, section_begin_index, section_end_index): + self.delimiters = delimiters + self.key = key + self.parsed_contents = parsed_contents + self.template = template + self.section_begin_index = section_begin_index + self.section_end_index = section_end_index - def __init__(self, engine, delimiters=None): - """ - Construct an instance. + def render(self, engine, context): + data = engine.fetch_section_data(context, self.key) + + parts = [] + for val in data: + if callable(val): + # Lambdas special case section rendering and bypass pushing + # the data value onto the context stack. From the spec-- + # + # When used as the data value for a Section tag, the + # lambda MUST be treatable as an arity 1 function, and + # invoked as such (passing a String containing the + # unprocessed section contents). The returned value + # MUST be rendered against the current delimiters, then + # interpolated in place of the section. + # + # Also see-- + # + # https://github.com/defunkt/pystache/issues/113 + # + # TODO: should we check the arity? + val = val(self.template[self.section_begin_index:self.section_end_index]) + val = engine._render_value(val, context, delimiters=self.delimiters) + parts.append(val) + continue - Arguments: + context.push(val) + parts.append(engine.render_parsed(self.parsed_contents, context)) + context.pop() - engine: a RenderEngine instance. + return unicode(''.join(parts)) - """ + +class Parser(object): + + _delimiters = None + _template_re = None + + def __init__(self, delimiters=None): if delimiters is None: delimiters = DEFAULT_DELIMITERS self._delimiters = delimiters - self.engine = engine def _compile_delimiters(self): self._template_re = _compile_template_re(self._delimiters) @@ -242,8 +279,9 @@ class Parser(object): parsed_template.add(node) - # Add the remainder of the template. - parsed_template.add(template[start_index:]) + # Avoid adding spurious empty strings to the parse tree. + if start_index != len(template): + parsed_template.add(template[start_index:]) return parsed_template @@ -262,7 +300,7 @@ class Parser(object): return ChangeNode(delimiters) if tag_type == '': - return VariableNode(tag_key) + return Tag(tag_key) if tag_type == '&': return LiteralNode(tag_key) @@ -279,8 +317,8 @@ class Parser(object): """ if tag_type == '#': - return self.engine._make_get_section(tag_key, parsed_section, self._delimiters, - template, section_start_index, section_end_index) + return SectionNode(tag_key, parsed_section, self._delimiters, + template, section_start_index, section_end_index) if tag_type == '^': return InvertedNode(tag_key, parsed_section) -- cgit v1.2.1 From 01a2daf493d23fe8058ed64c522ddbe301b50db8 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 14:55:14 -0700 Subject: Added parse() function and made parser classes private. --- pystache/parser.py | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 74ffc01..5215c64 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -17,6 +17,15 @@ END_OF_LINE_CHARACTERS = [u'\r', u'\n'] NON_BLANK_RE = re.compile(ur'^(.)', re.M) +def parse(template, delimiters=None): + """ + Parse a unicode template string and return a ParsedTemplate instance. + + """ + parser = _Parser(delimiters) + return parser.parse(template) + + def _compile_template_re(delimiters=None): """ Return a regular expresssion object (re.RegexObject) instance. @@ -56,13 +65,13 @@ class ParsingError(Exception): ## Node types -class CommentNode(object): +class _CommentNode(object): def render(self, engine, context): return u'' -class ChangeNode(object): +class _ChangeNode(object): def __init__(self, delimiters): self.delimiters = delimiters @@ -71,7 +80,7 @@ class ChangeNode(object): return u'' -class Tag(object): +class _TagNode(object): def __init__(self, key): self.key = key @@ -81,7 +90,7 @@ class Tag(object): return engine.escape(s) -class LiteralNode(object): +class _LiteralNode(object): def __init__(self, key): self.key = key @@ -91,7 +100,7 @@ class LiteralNode(object): return engine.literal(s) -class PartialNode(object): +class _PartialNode(object): def __init__(self, key, indent): self.key = key @@ -105,7 +114,7 @@ class PartialNode(object): return engine.render(template, context) -class InvertedNode(object): +class _InvertedNode(object): def __init__(self, key, parsed_section): self.key = key @@ -122,7 +131,7 @@ class InvertedNode(object): return engine.render_parsed(self.parsed_section, context) -class SectionNode(object): +class _SectionNode(object): # TODO: the template_ and parsed_template_ arguments don't both seem # to be necessary. Can we remove one of them? For example, if @@ -168,7 +177,7 @@ class SectionNode(object): return unicode(''.join(parts)) -class Parser(object): +class _Parser(object): _delimiters = None _template_re = None @@ -292,21 +301,21 @@ class Parser(object): """ # TODO: switch to using a dictionary instead of a bunch of ifs and elifs. if tag_type == '!': - return CommentNode() + return _CommentNode() if tag_type == '=': delimiters = tag_key.split() self._change_delimiters(delimiters) - return ChangeNode(delimiters) + return _ChangeNode(delimiters) if tag_type == '': - return Tag(tag_key) + return _TagNode(tag_key) if tag_type == '&': - return LiteralNode(tag_key) + return _LiteralNode(tag_key) if tag_type == '>': - return PartialNode(tag_key, leading_whitespace) + return _PartialNode(tag_key, leading_whitespace) raise Exception("Invalid symbol for interpolation tag: %s" % repr(tag_type)) @@ -317,10 +326,10 @@ class Parser(object): """ if tag_type == '#': - return SectionNode(tag_key, parsed_section, self._delimiters, + return _SectionNode(tag_key, parsed_section, self._delimiters, template, section_start_index, section_end_index) if tag_type == '^': - return InvertedNode(tag_key, parsed_section) + return _InvertedNode(tag_key, parsed_section) raise Exception("Invalid symbol for section tag: %s" % repr(tag_type)) -- cgit v1.2.1 From 5dd7fa7c8df7f186abda7ac463c44fc70953cc27 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 16:23:50 -0700 Subject: Moved the default delimiters into pystache.defaults. --- pystache/parser.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 5215c64..9bfc30c 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -1,39 +1,41 @@ # coding: utf-8 """ -Provides a class for parsing template strings. - -This module is only meant for internal use by the renderengine module. +Exposes a parse() function to parse template strings. """ import re +from pystache.defaults import DELIMITERS from pystache.parsed import ParsedTemplate -DEFAULT_DELIMITERS = (u'{{', u'}}') END_OF_LINE_CHARACTERS = [u'\r', u'\n'] NON_BLANK_RE = re.compile(ur'^(.)', re.M) +# TODO: add some unit tests for this. def parse(template, delimiters=None): """ Parse a unicode template string and return a ParsedTemplate instance. + Arguments: + + template: a unicode template string. + + delimiters: a 2-tuple of delimiters. Defaults to the package default. + """ parser = _Parser(delimiters) return parser.parse(template) -def _compile_template_re(delimiters=None): +def _compile_template_re(delimiters): """ Return a regular expresssion object (re.RegexObject) instance. """ - if delimiters is None: - delimiters = DEFAULT_DELIMITERS - # The possible tag type characters following the opening tag, # excluding "=" and "{". tag_types = "!>&/#^" @@ -184,7 +186,7 @@ class _Parser(object): def __init__(self, delimiters=None): if delimiters is None: - delimiters = DEFAULT_DELIMITERS + delimiters = DELIMITERS self._delimiters = delimiters -- cgit v1.2.1 From 37b4e3dc6488943736535a7753b2a7f3b16e8d40 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 17:41:41 -0700 Subject: Reduced the number of elements in the parse tree. --- pystache/parser.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 9bfc30c..ad3ee30 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -231,10 +231,6 @@ class _Parser(object): match_index = match.start() end_index = match.end() - # Avoid adding spurious empty strings to the parse tree. - if start_index != match_index: - parsed_template.add(template[start_index:match_index]) - matches = match.groupdict() # Normalize the matches dictionary. @@ -259,10 +255,13 @@ class _Parser(object): if end_index < len(template): end_index += template[end_index] == '\n' and 1 or 0 elif leading_whitespace: - parsed_template.add(leading_whitespace) match_index += len(leading_whitespace) leading_whitespace = '' + # Avoid adding spurious empty strings to the parse tree. + if start_index != match_index: + parsed_template.add(template[start_index:match_index]) + start_index = end_index if tag_type in ('#', '^'): -- cgit v1.2.1 From 0de74f66c00ea66abb5ee96cd96e9bf42d41c65d Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 18:18:08 -0700 Subject: Added pretty-printing to the nodes of the ParsedTemplate. --- pystache/parser.py | 53 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 8 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index ad3ee30..1a7c37e 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -26,6 +26,11 @@ def parse(template, delimiters=None): delimiters: a 2-tuple of delimiters. Defaults to the package default. + Examples: + + >>> parse("Hey {{#you}}{{name}}!{{/you}}") + ['Hey ', _SectionNode(key='you', index_begin=12, index_end=21, parsed=[_EscapeNode(key='name'), '!'])] + """ parser = _Parser(delimiters) return parser.parse(template) @@ -66,9 +71,23 @@ class ParsingError(Exception): ## Node types +def _format(obj, exclude=None): + if exclude is None: + exclude = [] + exclude.append('key') + attrs = obj.__dict__ + names = list(set(attrs.keys()) - set(exclude)) + names.sort() + names.insert(0, 'key') + args = ["%s=%s" % (name, repr(attrs[name])) for name in names] + return "%s(%s)" % (obj.__class__.__name__, ", ".join(args)) + class _CommentNode(object): + def __repr__(self): + return _format(self) + def render(self, engine, context): return u'' @@ -78,15 +97,21 @@ class _ChangeNode(object): def __init__(self, delimiters): self.delimiters = delimiters + def __repr__(self): + return _format(self) + def render(self, engine, context): return u'' -class _TagNode(object): +class _EscapeNode(object): def __init__(self, key): self.key = key + def __repr__(self): + return _format(self) + def render(self, engine, context): s = engine.fetch_string(context, self.key) return engine.escape(s) @@ -97,6 +122,9 @@ class _LiteralNode(object): def __init__(self, key): self.key = key + def __repr__(self): + return _format(self) + def render(self, engine, context): s = engine.fetch_string(context, self.key) return engine.literal(s) @@ -108,6 +136,9 @@ class _PartialNode(object): self.key = key self.indent = indent + def __repr__(self): + return _format(self) + def render(self, engine, context): template = engine.resolve_partial(self.key) # Indent before rendering. @@ -122,6 +153,9 @@ class _InvertedNode(object): self.key = key self.parsed_section = parsed_section + def __repr__(self): + return _format(self) + def render(self, engine, context): # TODO: is there a bug because we are not using the same # logic as in fetch_string()? @@ -138,13 +172,16 @@ class _SectionNode(object): # TODO: the template_ and parsed_template_ arguments don't both seem # to be necessary. Can we remove one of them? For example, if # callable(data) is True, then the initial parsed_template isn't used. - def __init__(self, key, parsed_contents, delimiters, template, section_begin_index, section_end_index): + def __init__(self, key, parsed, delimiters, template, index_begin, index_end): self.delimiters = delimiters self.key = key - self.parsed_contents = parsed_contents + self.parsed = parsed self.template = template - self.section_begin_index = section_begin_index - self.section_end_index = section_end_index + self.index_begin = index_begin + self.index_end = index_end + + def __repr__(self): + return _format(self, exclude=['delimiters', 'template']) def render(self, engine, context): data = engine.fetch_section_data(context, self.key) @@ -167,13 +204,13 @@ class _SectionNode(object): # https://github.com/defunkt/pystache/issues/113 # # TODO: should we check the arity? - val = val(self.template[self.section_begin_index:self.section_end_index]) + val = val(self.template[self.index_begin:self.index_end]) val = engine._render_value(val, context, delimiters=self.delimiters) parts.append(val) continue context.push(val) - parts.append(engine.render_parsed(self.parsed_contents, context)) + parts.append(engine.render_parsed(self.parsed, context)) context.pop() return unicode(''.join(parts)) @@ -310,7 +347,7 @@ class _Parser(object): return _ChangeNode(delimiters) if tag_type == '': - return _TagNode(tag_key) + return _EscapeNode(tag_key) if tag_type == '&': return _LiteralNode(tag_key) -- cgit v1.2.1 From 2aaa7a28c65ab006c416b8db42d0c540ca0a5900 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 5 May 2012 18:20:02 -0700 Subject: Added a TODO. --- pystache/parser.py | 1 + 1 file changed, 1 insertion(+) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 1a7c37e..d814b55 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -16,6 +16,7 @@ NON_BLANK_RE = re.compile(ur'^(.)', re.M) # TODO: add some unit tests for this. +# TODO: add a test case that checks for spurious spaces. def parse(template, delimiters=None): """ Parse a unicode template string and return a ParsedTemplate instance. -- cgit v1.2.1 From b80d2e949d04954ba7a9a56c18b18ac2d995caff Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sun, 6 May 2012 11:09:54 -0700 Subject: README tweaks and added a TODO. --- pystache/parser.py | 1 + 1 file changed, 1 insertion(+) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index d814b55..0365f76 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -17,6 +17,7 @@ NON_BLANK_RE = re.compile(ur'^(.)', re.M) # TODO: add some unit tests for this. # TODO: add a test case that checks for spurious spaces. +# TODO: add test cases for delimiters. def parse(template, delimiters=None): """ Parse a unicode template string and return a ParsedTemplate instance. -- cgit v1.2.1 From 331a48d0984b37dafd07efb2f3883ab6fafb2b34 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sun, 6 May 2012 11:40:55 -0700 Subject: ParsedTemplate docstring udpates and removed RenderEngine.render_parsed(). --- pystache/parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 0365f76..81d189a 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -166,7 +166,7 @@ class _InvertedNode(object): # per the spec. if data: return u'' - return engine.render_parsed(self.parsed_section, context) + return self.parsed_section.render(engine, context) class _SectionNode(object): @@ -212,7 +212,7 @@ class _SectionNode(object): continue context.push(val) - parts.append(engine.render_parsed(self.parsed, context)) + parts.append(self.parsed.render(engine, context)) context.pop() return unicode(''.join(parts)) -- cgit v1.2.1 From ea9f711c9074a09a9629e02d9508596e30fd65c8 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sun, 6 May 2012 13:19:45 -0700 Subject: Renderer.render() now accepts ParsedTemplate instances. --- pystache/parser.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 81d189a..4c37ec3 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -30,10 +30,13 @@ def parse(template, delimiters=None): Examples: - >>> parse("Hey {{#you}}{{name}}!{{/you}}") - ['Hey ', _SectionNode(key='you', index_begin=12, index_end=21, parsed=[_EscapeNode(key='name'), '!'])] + >>> parsed = parse(u"Hey {{#who}}{{name}}!{{/who}}") + >>> print str(parsed).replace('u', '') # This is a hack to get the test to pass both in Python 2 and 3. + ['Hey ', _SectionNode(key='who', index_begin=12, index_end=21, parsed=[_EscapeNode(key='name'), '!'])] """ + if type(template) is not unicode: + raise Exception("Template is not unicode: %s" % type(template)) parser = _Parser(delimiters) return parser.parse(template) -- cgit v1.2.1 From 353da3daf5a918c9862fe58b6b403d20d99ed2ff Mon Sep 17 00:00:00 2001 From: Ben Leslie Date: Tue, 18 Sep 2012 21:53:53 +1000 Subject: Enable defaults.DELIMITERS to be monkey-patched by module users. This updates the way in which default.DELIMITERS is used to enable simple monkey-patching should a user desire. Monkey-patching isn't the preferred approach however, it can at times be useful and it simple to support. Additionally, test cases are added to ensure certain defaults can be monkey-patched at run-time. --- pystache/parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 4c37ec3..8b82776 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -7,7 +7,7 @@ Exposes a parse() function to parse template strings. import re -from pystache.defaults import DELIMITERS +from pystache import defaults from pystache.parsed import ParsedTemplate @@ -228,7 +228,7 @@ class _Parser(object): def __init__(self, delimiters=None): if delimiters is None: - delimiters = DELIMITERS + delimiters = defaults.DELIMITERS self._delimiters = delimiters -- cgit v1.2.1 From 78f4e11012d94b8a0f8abb6342fc5395392d29a0 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Fri, 19 Oct 2012 15:43:27 -0700 Subject: Rename variable for return value of RenderEngine.fetch_section_data(). --- pystache/parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'pystache/parser.py') diff --git a/pystache/parser.py b/pystache/parser.py index 4c37ec3..8dc74b5 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -189,10 +189,10 @@ class _SectionNode(object): return _format(self, exclude=['delimiters', 'template']) def render(self, engine, context): - data = engine.fetch_section_data(context, self.key) + values = engine.fetch_section_data(context, self.key) parts = [] - for val in data: + for val in values: if callable(val): # Lambdas special case section rendering and bypass pushing # the data value onto the context stack. From the spec-- -- cgit v1.2.1