Mercurial > piecrust2
changeset 185:139179dc7abd
render: Add support for a Mustache template engine.
Add unit tests for the new class.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sun, 04 Jan 2015 14:59:12 -0800 |
parents | 27d623a241c6 |
children | e61fbae61402 |
files | piecrust/plugins/builtin.py piecrust/templating/pystacheengine.py tests/test_templating_pystacheengine.py |
diffstat | 3 files changed, 124 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/piecrust/plugins/builtin.py Sun Jan 04 14:58:40 2015 -0800 +++ b/piecrust/plugins/builtin.py Sun Jan 04 14:59:12 2015 -0800 @@ -28,6 +28,7 @@ from piecrust.sources.autoconfig import AutoConfigSource from piecrust.sources.prose import ProseSource from piecrust.templating.jinjaengine import JinjaTemplateEngine +from piecrust.templating.pystacheengine import PystacheTemplateEngine class BuiltInPlugin(PieCrustPlugin): @@ -73,7 +74,8 @@ def getTemplateEngines(self): return [ - JinjaTemplateEngine()] + JinjaTemplateEngine(), + PystacheTemplateEngine()] def getFormatters(self): return [
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/piecrust/templating/pystacheengine.py Sun Jan 04 14:59:12 2015 -0800 @@ -0,0 +1,57 @@ +import logging +import pystache +from piecrust.templating.base import ( + TemplateEngine, TemplateNotFoundError, TemplatingError) + + +logger = logging.getLogger(__name__) + + +class PystacheTemplateEngine(TemplateEngine): + ENGINE_NAMES = ['mustache'] + EXTENSIONS = ['mustache'] + + def __init__(self): + self.renderer = None + + def renderString(self, txt, data, filename=None): + self._ensureLoaded() + try: + return self.renderer.render(txt, data) + except pystache.TemplateNotFoundError as ex: + raise TemplateNotFoundError() from ex + except pystache.PystacheError as ex: + raise TemplatingError(str(ex), filename) from ex + + def renderFile(self, paths, data): + self._ensureLoaded() + tpl = None + logger.debug("Looking for template: %s" % paths) + for p in paths: + if not p.endswith('.mustache'): + raise TemplatingError( + "The Mustache template engine only accepts template " + "filenames with a `.mustache` extension. Got: %s" % + p) + name = p[:-9] # strip `.mustache` + try: + tpl = self.renderer.load_template(name) + except Exception as ex: + print(p, ex) + pass + + if tpl is None: + raise TemplateNotFoundError() + + try: + return self.renderer.render(tpl, data) + except pystache.PystacheError as ex: + raise TemplatingError(str(ex)) from ex + + def _ensureLoaded(self): + if self.renderer: + return + + self.renderer = pystache.Renderer( + search_dirs=self.app.templates_dirs) +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test_templating_pystacheengine.py Sun Jan 04 14:59:12 2015 -0800 @@ -0,0 +1,64 @@ +import pytest +from .mockutil import ( + mock_fs, mock_fs_scope, get_simple_page, render_simple_page) + + +app_config = { + 'site': { + 'default_format': 'none', + 'default_template_engine': 'mustache'}, + 'foo': 'bar'} +page_config = {'layout': 'none'} + +open_patches = ['pystache.common'] + + +@pytest.mark.parametrize( + 'contents, expected', + [ + ("Raw text", "Raw text"), + ("This is {{foo}}", "This is bar"), + ("Info:\n{{#page}}\nMy URL: {{url}}\n{{/page}}\n", + "Info:\nMy URL: /foo\n") + ]) +def test_simple(contents, expected): + fs = (mock_fs() + .withConfig(app_config) + .withPage('pages/foo', config=page_config, contents=contents)) + with mock_fs_scope(fs, open_patches=open_patches): + app = fs.getApp() + page = get_simple_page(app, 'foo.md') + output = render_simple_page(page, '/foo') + assert output == expected + + +def test_layout(): + contents = "Blah\n" + layout = "{{content}}\nFor site: {{foo}}\n" + expected = "Blah\n\nFor site: bar\n" + fs = (mock_fs() + .withConfig(app_config) + .withAsset('templates/blah.mustache', layout) + .withPage('pages/foo', config={'layout': 'blah'}, + contents=contents)) + with mock_fs_scope(fs, open_patches=open_patches): + app = fs.getApp() + page = get_simple_page(app, 'foo.md') + output = render_simple_page(page, '/foo') + assert output == expected + + +def test_partial(): + contents = "Info:\n{{#page}}\n{{> page_info}}\n{{/page}}\n" + partial = "- URL: {{url}}\n- SLUG: {{slug}}\n" + expected = "Info:\n- URL: /foo\n- SLUG: foo\n" + fs = (mock_fs() + .withConfig(app_config) + .withAsset('templates/page_info.mustache', partial) + .withPage('pages/foo', config=page_config, contents=contents)) + with mock_fs_scope(fs, open_patches=open_patches): + app = fs.getApp() + page = get_simple_page(app, 'foo.md') + output = render_simple_page(page, '/foo') + assert output == expected +