From 25c37da8b73880d2762ee9a94d51773294f0bda6 Mon Sep 17 00:00:00 2001 From: "Kay-Uwe (Kiwi) Lorenz" Date: Sat, 28 Jul 2018 08:36:06 +0200 Subject: [PATCH] implement #27 -- Lambdas --- chevron/renderer.py | 48 ++++++++++++++++++++++++-- test_spec.py | 82 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 127 insertions(+), 3 deletions(-) diff --git a/chevron/renderer.py b/chevron/renderer.py index 4286f5b..2f93367 100644 --- a/chevron/renderer.py +++ b/chevron/renderer.py @@ -92,7 +92,6 @@ def _get_partial(name, partials_dict, partials_path, partials_ext): # Alright I give up on you return '' - # # The main rendering function # @@ -149,6 +148,8 @@ def render(template='', data={}, partials_path='.', partials_ext='mustache', A string containing the rendered template. """ + function = type(render) + # If the template is a list if type(template) is list: # Then we don't need to tokenize it @@ -213,8 +214,51 @@ def render(template='', data={}, partials_path='.', partials_ext='mustache', # Get the sections scope scope = _get_key(key, scopes) + # If the scope is a callable (as described in https://mustache.github.io/mustache.5.html) + if type(scope) is function: + + # Gather up all the tags inside the section and generate a template text + tags = [] + + text = unicode('', 'utf-8') + for tag in tokens: + if tag == ('end', key): + break + + tag_type, tag_key = tag + if tag_type == 'literal': + text += tag_key + elif tag_type == 'no escape': + text += "%s& %s %s" % (def_ldel, tag_key, def_rdel) + else: + text += "%s%s %s%s" % (def_ldel,{ + 'commment': '!', + 'section': '#', + 'inverted section': '^', + 'end': '/', + 'partial': '>', + 'set delimiter': '=', + 'no escape': '&' + }[tag_type], tag_key, def_rdel) + + tags.append(tag) + + rend = scope(text, lambda template, data=None: render(template, + data={}, + partials_path=partials_path, + partials_ext=partials_ext, + partials_dict=partials_dict, + padding=padding, + def_ldel=def_ldel, def_rdel=def_rdel, + scopes=data and [data]+scopes or scopes)) + + if python3: + output += rend + else: # python 2 + output += rend.decode('utf-8') + # If the scope is a list - if type(scope) is list: + elif type(scope) is list: # Then we need to do some looping # Gather up all the tags inside the section diff --git a/test_spec.py b/test_spec.py index 250f547..14e8eee 100755 --- a/test_spec.py +++ b/test_spec.py @@ -6,9 +6,14 @@ import os import json import chevron +from textwrap import dedent SPECS_PATH = os.path.join('spec', 'specs') -SPECS = [path for path in os.listdir(SPECS_PATH) if path.endswith('.json')] +if os.path.exists(SPECS_PATH): + SPECS = [path for path in os.listdir(SPECS_PATH) if path.endswith('.json')] +else: + SPECS = [] + STACHE = chevron.render @@ -228,6 +233,81 @@ class ExpandedCoverage(unittest.TestCase): 'Looks like it was not opened.\n' 'line 2') + # https://github.com/noahmorrison/chevron/issues/17 + def test_callable_1(self): + args_passed = {} + def first(content, render): + args_passed['content'] = content + args_passed['render'] = render + + return "not implemented" + + args = { + 'template': '{{{postcode}}} {{#first}} {{{city}}} || {{{town}}} || {{{village}}} || {{{state}}} {{/first}}', + 'data': { + "postcode": "1234", + "city": "Mustache City", + "state": "Nowhere", + "first": first, + } + + } + + result = chevron.render(**args) + expected = '1234 not implemented' + template_content = " {{& city }} || {{& town }} || {{& village }} || {{& state }} " + + self.assertEqual(result, expected) + self.assertEqual(args_passed['content'], template_content) + + def test_callable_2(self): + args_passed = {} + def first(content, render): + result = render(content) + result = [ x.strip() for x in result.split(" || ") if x.strip() ] + return result[0] + + args = { + 'template': '{{{postcode}}} {{#first}} {{{city}}} || {{{town}}} || {{{village}}} || {{{state}}} {{/first}}', + 'data': { + "postcode": "1234", + "town": "Mustache Town", + "state": "Nowhere", + "first": first, + } + } + + result = chevron.render(**args) + expected = '1234 Mustache Town' + template_content = " {{& city }} || {{& town }} || {{& village }} || {{& state }} " + + self.assertEqual(result, expected) + + def test_callable_3(self): + '''Test generating some data within the function + ''' + args_passed = {} + def first(content, render): + result = render(content, {'city': "Injected City"}) + result = [ x.strip() for x in result.split(" || ") if x.strip() ] + return result[0] + + args = { + 'template': '{{{postcode}}} {{#first}} {{{city}}} || {{{town}}} || {{{village}}} || {{{state}}} {{/first}}', + 'data': { + "postcode": "1234", + "town": "Mustache Town", + "state": "Nowhere", + "first": first, + } + } + + result = chevron.render(**args) + expected = '1234 Injected City' + template_content = " {{& city }} || {{& town }} || {{& village }} || {{& state }} " + + self.assertEqual(result, expected) + # Run unit tests from command line if __name__ == "__main__": -- 2.47.3