Commit fd2f53da by Chris Jerdonek

Merge branch 'issue_46' into development: closing issue #46

parents 4ce9bf1d c1718296
...@@ -124,49 +124,60 @@ class Template(object): ...@@ -124,49 +124,60 @@ class Template(object):
# The section contents include white space to comply with the spec's # The section contents include white space to comply with the spec's
# requirement that sections not alter surrounding whitespace. # requirement that sections not alter surrounding whitespace.
section = r"%(otag)s[\#|^]([^\}]*)%(ctag)s(.+?)%(otag)s/\1%(ctag)s" section = r"%(otag)s([#|^])([^\}]*)%(ctag)s(.+?)%(otag)s/\2%(ctag)s" % tags
self.section_re = re.compile(section % tags, re.M|re.S) self.section_re = re.compile(section, re.M|re.S)
tag = r"%(otag)s(#|=|&|!|>|\{)?(.+?)\1?%(ctag)s+" tag = r"%(otag)s(#|=|&|!|>|\{)?(.+?)\1?%(ctag)s+" % tags
self.tag_re = re.compile(tag % tags) self.tag_re = re.compile(tag)
def _render(self, template):
output = []
def _render_sections(self, template):
while True: while True:
match = self.section_re.search(template) parts = self.section_re.split(template, maxsplit=1)
if match is None:
start = self._render_tags(parts[0])
output.append(start)
if len(parts) < 2:
# Then there was no match.
break break
section, section_name, inner = match.group(0, 1, 2) section_type, section_key, section_contents, template = parts[1:]
section_name = section_name.strip()
it = self.context.get(section_name, None) section_key = section_key.strip()
replacer = '' section_value = self.context.get(section_key, None)
rendered = ''
# Callable # Callable
if it and check_callable(it): if section_value and check_callable(section_value):
replacer = it(inner) rendered = section_value(section_contents)
# Dictionary # Dictionary
elif it and hasattr(it, 'keys') and hasattr(it, '__getitem__'): elif section_value and hasattr(section_value, 'keys') and hasattr(section_value, '__getitem__'):
if section[2] != '^': if section_type != '^':
replacer = self._render_dictionary(inner, it) rendered = self._render_dictionary(section_contents, section_value)
# Lists # Lists
elif it and hasattr(it, '__iter__'): elif section_value and hasattr(section_value, '__iter__'):
if section[2] != '^': if section_type != '^':
replacer = self._render_list(inner, it) rendered = self._render_list(section_contents, section_value)
# Other objects # Other objects
elif it and isinstance(it, object): elif section_value and isinstance(section_value, object):
if section[2] != '^': if section_type != '^':
replacer = self._render_dictionary(inner, it) rendered = self._render_dictionary(section_contents, section_value)
# Falsey and Negated or Truthy and Not Negated # Falsey and Negated or Truthy and Not Negated
elif (not it and section[2] == '^') or (it and section[2] != '^'): elif (not section_value and section_type == '^') or (section_value and section_type != '^'):
replacer = self._render_dictionary(inner, it) rendered = self._render_dictionary(section_contents, section_value)
template = literal(template.replace(section, replacer)) # Render template prior to section too
output.append(rendered)
return template output = "".join(output)
return output
def _render_tags(self, template): def _render_tags(self, template):
output = [] output = []
...@@ -275,8 +286,7 @@ class Template(object): ...@@ -275,8 +286,7 @@ class Template(object):
""" """
self._initialize_context(context, **kwargs) self._initialize_context(context, **kwargs)
template = self._render_sections(self.template) result = self._render(self.template)
result = self._render_tags(template)
if self.output_encoding is not None: if self.output_encoding is not None:
result = result.encode(self.output_encoding) result = result.encode(self.output_encoding)
......
...@@ -80,6 +80,3 @@ class TestPystache(unittest.TestCase): ...@@ -80,6 +80,3 @@ class TestPystache(unittest.TestCase):
template = "first{{#spacing}} second {{/spacing}}third" template = "first{{#spacing}} second {{/spacing}}third"
ret = pystache.render(template, {"spacing": True}) ret = pystache.render(template, {"spacing": True})
self.assertEquals(ret, "first second third") self.assertEquals(ret, "first second third")
if __name__ == '__main__':
unittest.main()
...@@ -101,3 +101,19 @@ class TemplateTestCase(unittest.TestCase): ...@@ -101,3 +101,19 @@ class TemplateTestCase(unittest.TestCase):
context = {'test': '{{#hello}}'} context = {'test': '{{#hello}}'}
actual = template.render(context) actual = template.render(context)
self.assertEquals(actual, '{{#hello}}') self.assertEquals(actual, '{{#hello}}')
def test_render__section__lambda(self):
template = Template('{{#test}}Mom{{/test}}')
context = {'test': (lambda text: 'Hi %s' % text)}
actual = template.render(context)
self.assertEquals(actual, 'Hi Mom')
def test_render__section__lambda__tag_in_output(self):
"""
Check that callable output isn't treated as a template string (issue #46).
"""
template = Template('{{#test}}Mom{{/test}}')
context = {'test': (lambda text: '{{hi}} %s' % text)}
actual = template.render(context)
self.assertEquals(actual, '{{hi}} Mom')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment