Commit b6c4b4af by Chris Jerdonek

RenderEngine constructor now accepts resolve_partial() instead of load_partial().

parent 0085bd9d
......@@ -7,7 +7,6 @@ Defines a class responsible for rendering logic.
import re
from pystache.common import TemplateNotFoundError
from pystache.context import KeyNotFoundError
from pystache.parser import Parser
......@@ -31,14 +30,13 @@ class RenderEngine(object):
"""
def __init__(self, load_partial=None, literal=None, escape=None):
def __init__(self, resolve_partial=None, literal=None, escape=None):
"""
Arguments:
load_partial: the function to call when loading a partial. The
function should accept a string template name and return a
template string of type unicode (not a subclass). If the
template is not found, it should raise a TemplateNotFoundError.
resolve_partial: the function to call when loading a partial.
The function should accept a string template name and return a
template string of type unicode (not a subclass).
literal: the function used to convert unescaped variable tag
values to unicode, e.g. the value corresponding to a tag
......@@ -64,7 +62,7 @@ class RenderEngine(object):
"""
self.escape = escape
self.literal = literal
self.load_partial = load_partial
self.resolve_partial = resolve_partial
def resolve_context(self, stack, name):
try:
......@@ -72,12 +70,6 @@ class RenderEngine(object):
except KeyNotFoundError:
return u''
def resolve_partial(self, key):
try:
return self.load_partial(key)
except TemplateNotFoundError:
return u''
def _get_string_value(self, context, tag_name):
"""
Get a value from the given context as a basestring instance.
......
......@@ -222,40 +222,49 @@ class Renderer(object):
return load_template
def _make_load_partial(self):
# TODO: rename this to _make_resolve_partial().
def _make_resolve_partial(self):
"""
Return the load_partial function to pass to RenderEngine.__init__().
Return the resolve_partial function to pass to RenderEngine.__init__().
"""
if self.partials is None:
load_template = self._make_load_template()
return load_template
def resolve_partial(name):
try:
return load_template(name)
except TemplateNotFoundError:
return u''
return resolve_partial
# Otherwise, create a load_partial function from the custom partial
# Otherwise, create a resolve_partial function from the custom partial
# loader that satisfies RenderEngine requirements (and that provides
# a nicer exception, etc).
partials = self.partials
def load_partial(name):
def resolve_partial(name):
template = partials.get(name)
if template is None:
raise TemplateNotFoundError("Name %s not found in partials: %s" %
(repr(name), type(partials)))
return u''
# if template is None:
# raise TemplateNotFoundError("Name %s not found in partials: %s" %
# (repr(name), type(partials)))
# RenderEngine requires that the return value be unicode.
return self._to_unicode_hard(template)
return load_partial
return resolve_partial
def _make_render_engine(self):
"""
Return a RenderEngine instance for rendering.
"""
load_partial = self._make_load_partial()
resolve_partial = self._make_resolve_partial()
engine = RenderEngine(load_partial=load_partial,
engine = RenderEngine(resolve_partial=resolve_partial,
literal=self._to_unicode_hard,
escape=self._escape_to_unicode)
return engine
......
......@@ -45,11 +45,11 @@ class RenderEngineTestCase(unittest.TestCase):
"""
# In real-life, these arguments would be functions
engine = RenderEngine(load_partial="foo", literal="literal", escape="escape")
engine = RenderEngine(resolve_partial="foo", literal="literal", escape="escape")
self.assertEqual(engine.escape, "escape")
self.assertEqual(engine.literal, "literal")
self.assertEqual(engine.load_partial, "foo")
self.assertEqual(engine.resolve_partial, "foo")
class RenderTests(unittest.TestCase, AssertStringMixin):
......@@ -69,7 +69,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin):
"""
escape = defaults.TAG_ESCAPE
engine = RenderEngine(literal=unicode, escape=escape, load_partial=None)
engine = RenderEngine(literal=unicode, escape=escape, resolve_partial=None)
return engine
def _assert_render(self, expected, template, *context, **kwargs):
......@@ -81,7 +81,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin):
engine = kwargs.get('engine', self._engine())
if partials is not None:
engine.load_partial = lambda key: unicode(partials[key])
engine.resolve_partial = lambda key: unicode(partials[key])
context = ContextStack(*context)
......@@ -92,14 +92,14 @@ class RenderTests(unittest.TestCase, AssertStringMixin):
def test_render(self):
self._assert_render(u'Hi Mom', 'Hi {{person}}', {'person': 'Mom'})
def test__load_partial(self):
def test__resolve_partial(self):
"""
Test that render() uses the load_template attribute.
"""
engine = self._engine()
partials = {'partial': u"{{person}}"}
engine.load_partial = lambda key: partials[key]
engine.resolve_partial = lambda key: partials[key]
self._assert_render(u'Hi Mom', 'Hi {{>partial}}', {'person': 'Mom'}, engine=engine)
......
......@@ -319,37 +319,37 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
renderer.string_encoding = 'utf_8'
self.assertEqual(renderer.render(template), u"déf")
def test_make_load_partial(self):
def test_make_resolve_partial(self):
"""
Test the _make_load_partial() method.
Test the _make_resolve_partial() method.
"""
renderer = Renderer()
renderer.partials = {'foo': 'bar'}
load_partial = renderer._make_load_partial()
resolve_partial = renderer._make_resolve_partial()
actual = load_partial('foo')
actual = resolve_partial('foo')
self.assertEqual(actual, 'bar')
self.assertEqual(type(actual), unicode, "RenderEngine requires that "
"load_partial return unicode strings.")
"resolve_partial return unicode strings.")
def test_make_load_partial__unicode(self):
def test_make_resolve_partial__unicode(self):
"""
Test _make_load_partial(): that load_partial doesn't "double-decode" Unicode.
Test _make_resolve_partial(): that resolve_partial doesn't "double-decode" Unicode.
"""
renderer = Renderer()
renderer.partials = {'partial': 'foo'}
load_partial = renderer._make_load_partial()
self.assertEqual(load_partial("partial"), "foo")
resolve_partial = renderer._make_resolve_partial()
self.assertEqual(resolve_partial("partial"), "foo")
# Now with a value that is already unicode.
renderer.partials = {'partial': u'foo'}
load_partial = renderer._make_load_partial()
resolve_partial = renderer._make_resolve_partial()
# If the next line failed, we would get the following error:
# TypeError: decoding Unicode is not supported
self.assertEqual(load_partial("partial"), "foo")
self.assertEqual(resolve_partial("partial"), "foo")
def test_render_path(self):
"""
......@@ -406,7 +406,7 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
# we no longer need to exercise all rendering code paths through
# the Renderer. It suffices to test rendering paths through the
# RenderEngine for the same amount of code coverage.
class Renderer_MakeRenderEngineTests(unittest.TestCase, AssertExceptionMixin):
class Renderer_MakeRenderEngineTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin):
"""
Check the RenderEngine returned by Renderer._make_render_engine().
......@@ -420,11 +420,11 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase, AssertExceptionMixin):
"""
return _make_renderer()
## Test the engine's load_partial attribute.
## Test the engine's resolve_partial attribute.
def test__load_partial__returns_unicode(self):
def test__resolve_partial__returns_unicode(self):
"""
Check that load_partial returns unicode (and not a subclass).
Check that resolve_partial returns unicode (and not a subclass).
"""
class MyUnicode(unicode):
......@@ -436,43 +436,70 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase, AssertExceptionMixin):
engine = renderer._make_render_engine()
actual = engine.load_partial('str')
actual = engine.resolve_partial('str')
self.assertEqual(actual, "foo")
self.assertEqual(type(actual), unicode)
# Check that unicode subclasses are not preserved.
actual = engine.load_partial('subclass')
actual = engine.resolve_partial('subclass')
self.assertEqual(actual, "abc")
self.assertEqual(type(actual), unicode)
def test__load_partial__not_found__default(self):
def test__resolve_partial__not_found__default(self):
"""
Check that load_partial provides a nice message when a template is not found.
Check that resolve_partial returns the empty string when a template is not found.
"""
renderer = Renderer()
engine = renderer._make_render_engine()
load_partial = engine.load_partial
resolve_partial = engine.resolve_partial
self.assertException(TemplateNotFoundError, "File 'foo.mustache' not found in dirs: ['.']",
load_partial, "foo")
self.assertString(resolve_partial('foo'), u'')
def test__load_partial__not_found__dict(self):
# TODO: add this test case back when we add support to Renderer for strict mode.
# def test__resolve_partial__not_found__default(self):
# """
# Check that resolve_partial provides a nice message when a template is not found.
# """
# renderer = Renderer()
# engine = renderer._make_render_engine()
# resolve_partial = engine.resolve_partial
# self.assertException(TemplateNotFoundError, "File 'foo.mustache' not found in dirs: ['.']",
# resolve_partial, "foo")
def test__resolve_partial__not_found__dict(self):
"""
Check that load_partial provides a nice message when a template is not found.
Check that resolve_partial returns the empty string when a template is not found.
"""
renderer = Renderer()
renderer.partials = {}
engine = renderer._make_render_engine()
load_partial = engine.load_partial
resolve_partial = engine.resolve_partial
self.assertString(resolve_partial('foo'), u'')
# TODO: add this test case back when we add support to Renderer for strict mode.
# def test__resolve_partial__not_found__dict(self):
# """
# Check that resolve_partial provides a nice message when a template is not found.
# """
# renderer = Renderer()
# renderer.partials = {}
# engine = renderer._make_render_engine()
# resolve_partial = engine.resolve_partial
# Include dict directly since str(dict) is different in Python 2 and 3:
# <type 'dict'> versus <class 'dict'>, respectively.
self.assertException(TemplateNotFoundError, "Name 'foo' not found in partials: %s" % dict,
load_partial, "foo")
# self.assertException(TemplateNotFoundError, "Name 'foo' not found in partials: %s" % dict,
# resolve_partial, "foo")
## Test the engine's literal attribute.
......
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