Commit e256e732 by Chris Jerdonek

Added a load_template() method to the Renderer class.

parent 98e4f43f
......@@ -16,6 +16,12 @@ from .reader import Reader
from .renderengine import RenderEngine
# The quote=True argument causes double quotes to be escaped,
# but not single quotes:
# http://docs.python.org/library/cgi.html#cgi.escape
DEFAULT_ESCAPE = lambda s: cgi.escape(s, quote=True)
class Renderer(object):
"""
......@@ -35,6 +41,7 @@ class Renderer(object):
"""
# TODO: rename the loader argument to "partials".
def __init__(self, loader=None, file_encoding=None, default_encoding=None,
decode_errors='strict', search_dirs=None, file_extension=None,
escape=None):
......@@ -43,16 +50,17 @@ class Renderer(object):
Arguments:
loader: the object (e.g. pystache.Loader or dictionary) that will
load templates during the rendering process, for example when
loading a partial.
loader: an object (e.g. pystache.Loader or dictionary) for custom
partial loading during the rendering process.
The loader should have a get() method that accepts a string
and returns the corresponding template as a string, preferably
as a unicode string. If there is no template with that name,
the method should either return None (as dict.get() does) or
raise an exception.
Defaults to constructing a default Loader, but using the
file_encoding and decode_errors arguments.
If this argument is None, partial loading takes place using
the normal procedure of reading templates from the file system
using the Loader-related instance attributes (search_dirs,
file_encoding, etc).
escape: the function used to escape variable tag values when
rendering a template. The function should accept a unicode
......@@ -96,10 +104,7 @@ class Renderer(object):
default_encoding = sys.getdefaultencoding()
if escape is None:
# The quote=True argument causes double quotes to be escaped,
# but not single quotes:
# http://docs.python.org/library/cgi.html#cgi.escape
escape = lambda s: cgi.escape(s, quote=True)
escape = DEFAULT_ESCAPE
# This needs to be after we set the default default_encoding.
if file_encoding is None:
......@@ -114,21 +119,12 @@ class Renderer(object):
if isinstance(search_dirs, basestring):
search_dirs = [search_dirs]
# This needs to be after we set some of the defaults above.
if loader is None:
reader = Reader(encoding=file_encoding, decode_errors=decode_errors)
loader = Loader(reader=reader, search_dirs=search_dirs, extension=file_extension)
self.decode_errors = decode_errors
self.default_encoding = default_encoding
self.escape = escape
self.file_encoding = file_encoding
self.file_extension = file_extension
# TODO: we should not store a loader attribute because the loader
# would no longer reflect the current attributes if, say, someone
# changed the search_dirs attribute after instantiation. Instead,
# we should construct the Loader instance each time on the fly,
# as we do with the Reader in the read() method.
# TODO: rename self.loader to self.partials.
self.loader = loader
self.search_dirs = search_dirs
......@@ -191,9 +187,39 @@ class Renderer(object):
return context
def _make_reader(self):
"""
Create a Reader instance using current attributes.
"""
return Reader(encoding=self.file_encoding, decode_errors=self.decode_errors)
def _make_loader(self):
"""
Create a Loader instance using current attributes.
"""
reader = self._make_reader()
loader = Loader(reader=reader, search_dirs=self.search_dirs, extension=self.file_extension)
return loader
def _make_load_partial(self):
"""
Return the load_partial function to pass to RenderEngine.__init__().
"""
if self.loader is None:
loader = self._make_loader()
return loader.get
# Otherwise, create a load_partial function from the custom loader
# that satisfies RenderEngine requirements (and that provides a
# nicer exception, etc).
loader = self.loader
def load_partial(name):
template = self.loader.get(name)
template = loader.get(name)
if template is None:
# TODO: make a TemplateNotFoundException type that provides
......@@ -226,9 +252,18 @@ class Renderer(object):
attributes.
"""
reader = Reader(encoding=self.file_encoding, decode_errors=self.decode_errors)
reader = self._make_reader()
return reader.read(path)
# TODO: add unit tests for this method.
def load_template(self, template_name):
"""
Load a template by name from the file system.
"""
loader = self._make_loader()
return loader.get(template_name)
def render_path(self, template_path, context=None, **kwargs):
"""
Render the template at the given path using the given context.
......
......@@ -76,7 +76,7 @@ class View(object):
if not self.template:
template_name = self._get_template_name()
renderer = self._get_renderer()
self.template = renderer.loader.get(template_name)
self.template = renderer.load_template(template_name)
return self.template
......
......@@ -29,8 +29,8 @@ class RendererInitTestCase(unittest.TestCase):
"""
loader = {'foo': 'bar'}
r = Renderer(loader=loader)
self.assertEquals(r.loader, {'foo': 'bar'})
renderer = Renderer(loader=loader)
self.assertEquals(renderer.loader, {'foo': 'bar'})
def test_loader__default(self):
"""
......@@ -40,52 +40,7 @@ class RendererInitTestCase(unittest.TestCase):
renderer = Renderer()
actual = renderer.loader
expected = Loader()
self.assertEquals(type(actual), type(expected))
self.assertEquals(actual.template_extension, expected.template_extension)
self.assertEquals(actual.search_dirs, expected.search_dirs)
self.assertEquals(actual.reader.__dict__, expected.reader.__dict__)
def test_loader__default__encoding(self):
"""
Test that the default loader inherits the correct encoding.
"""
renderer = Renderer(file_encoding='foo')
reader = renderer.loader.reader
self.assertEquals(reader.encoding, 'foo')
def test_loader__default__decode_errors(self):
"""
Test that the default loader inherits decode_errors.
"""
renderer = Renderer(decode_errors='foo')
reader = renderer.loader.reader
self.assertEquals(reader.decode_errors, 'foo')
def test_loader__default__file_extension(self):
"""
Test that the default loader inherits file_extension.
"""
renderer = Renderer(file_extension='foo')
loader = renderer.loader
self.assertEquals(loader.template_extension, 'foo')
def test_loader__default__search_dirs(self):
"""
Test that the default loader inherits search_dirs.
"""
renderer = Renderer(search_dirs='foo')
loader = renderer.loader
self.assertEquals(loader.search_dirs, ['foo'])
self.assertTrue(renderer.loader is None)
def test_escape__default(self):
escape = Renderer().escape
......@@ -264,6 +219,79 @@ class RendererTestCase(unittest.TestCase):
actual = self._read(renderer, filename)
self.assertEquals(actual, 'non-ascii: ')
## Test the _make_loader() method.
def test__make_loader__return_type(self):
"""
Test that _make_loader() returns a Loader.
"""
renderer = Renderer()
loader = renderer._make_loader()
self.assertEquals(type(loader), Loader)
def test__make_loader__file_encoding(self):
"""
Test that _make_loader() respects the file_encoding attribute.
"""
renderer = Renderer()
renderer.file_encoding = 'foo'
loader = renderer._make_loader()
self.assertEquals(loader.reader.encoding, 'foo')
def test__make_loader__decode_errors(self):
"""
Test that _make_loader() respects the decode_errors attribute.
"""
renderer = Renderer()
renderer.decode_errors = 'foo'
loader = renderer._make_loader()
self.assertEquals(loader.reader.decode_errors, 'foo')
def test__make_loader__file_extension(self):
"""
Test that _make_loader() respects the file_extension attribute.
"""
renderer = Renderer()
renderer.file_extension = 'foo'
loader = renderer._make_loader()
self.assertEquals(loader.template_extension, 'foo')
def test__make_loader__search_dirs(self):
"""
Test that _make_loader() respects the search_dirs attribute.
"""
renderer = Renderer()
renderer.search_dirs = ['foo']
loader = renderer._make_loader()
self.assertEquals(loader.search_dirs, ['foo'])
# This test is a sanity check. Strictly speaking, it shouldn't
# be necessary based on our tests above.
def test__make_loader__default(self):
renderer = Renderer()
actual = renderer._make_loader()
expected = Loader()
self.assertEquals(type(actual), type(expected))
self.assertEquals(actual.template_extension, expected.template_extension)
self.assertEquals(actual.search_dirs, expected.search_dirs)
self.assertEquals(actual.reader.__dict__, expected.reader.__dict__)
## Test the render() method.
def test_render__return_type(self):
......
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