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