Commit 4794333c by Chris Jerdonek

Merge branch 'issue_47' into development: closing issue #47.

parents 4e20cc2f 38c51a86
......@@ -5,6 +5,7 @@ Next Release (version TBD)
--------------------------
* Bugfix: Whitespace surrounding sections is no longer altered, in
accordance with the mustache spec. [heliodor]
* A custom template loader can now be passed to a View. [cjerdonek]
* Added some docstrings. [kennethreitz]
0.4.0 (2011-01-12)
......
......@@ -10,42 +10,45 @@ import os
class Loader(object):
template_extension = 'mustache'
template_path = '.'
template_encoding = None
def load_template(self, template_name, template_dirs=None, encoding=None, extension=None):
def __init__(self, search_dirs=None, encoding=None, extension=None):
"""
Find and load the given template, and return it as a string.
Construct a template loader.
Raises an IOError if the template cannot be found.
Arguments:
search_dirs: the directories in which to search for templates.
Defaults to the current working directory.
"""
if None == template_dirs:
template_dirs = self.template_path
if extension is None:
extension = 'mustache'
if search_dirs is None:
search_dirs = os.curdir # i.e. "."
if encoding is not None:
self.template_encoding = encoding
if isinstance(search_dirs, basestring):
search_dirs = [search_dirs]
if extension is not None:
self.template_extension = extension
self.search_dirs = search_dirs
self.template_encoding = encoding
self.template_extension = extension
file_name = template_name + '.' + self.template_extension
def load_template(self, template_name):
"""
Find and load the given template, and return it as a string.
# Given a single directory, we'll load from it.
if isinstance(template_dirs, basestring):
file_path = os.path.join(template_dirs, file_name)
Raises an IOError if the template cannot be found.
return self._load_template_file(file_path)
"""
search_dirs = self.search_dirs
file_name = template_name + '.' + self.template_extension
# Given a list of directories, we'll check each for our file.
for path in template_dirs:
file_path = os.path.join(path, file_name)
for dir_path in search_dirs:
file_path = os.path.join(dir_path, file_name)
if os.path.exists(file_path):
return self._load_template_file(file_path)
# TODO: we should probably raise an exception of our own type.
raise IOError('"%s" not found in "%s"' % (template_name, ':'.join(template_dirs),))
raise IOError('"%s" not found in "%s"' % (template_name, ':'.join(search_dirs),))
def _load_template_file(self, file_path):
"""
......
......@@ -42,8 +42,19 @@ class View(object):
template_encoding = None
template_extension = 'mustache'
def __init__(self, template=None, context=None, **kwargs):
self.template = template
# A function that accepts a single template_name parameter.
_load_template = None
def __init__(self, template=None, context=None, load_template=None, **kwargs):
"""
Construct a View instance.
"""
if load_template is not None:
self._load_template = load_template
if template is not None:
self.template = template
context = context or {}
context.update(**kwargs)
......@@ -63,37 +74,42 @@ class View(object):
return attr
def load_template(self, template_name):
from pystache import Loader
return Loader().load_template(template_name, self.template_path,
encoding=self.template_encoding, extension=self.template_extension)
def get_template(self, template_name):
if self._load_template is None:
# We delay setting self._load_template until now (in the case
# that the user did not supply a load_template to the constructor)
# to let users set the template_extension attribute, etc. after
# View.__init__() has already been called.
loader = Loader(search_dirs=self.template_path, encoding=self.template_encoding,
extension=self.template_extension)
self._load_template = loader.load_template
return self._load_template(template_name)
def get_template(self):
"""
Return the current template after setting it, if necessary.
"""
if not self.template:
template_name = self._get_template_name(template_name)
template_name = self._get_template_name()
self.template = self.load_template(template_name)
return self.template
# TODO: consider removing the template_name parameter and using
# self.template_name instead.
def _get_template_name(self, template_name=None):
def _get_template_name(self):
"""
Return the name of this Template instance.
If no template_name parameter is provided, this method returns the
class name modified as follows, for example:
If the template_name attribute is not set, then this method constructs
the template name from the class name as follows, for example:
TemplatePartial => template_partial
TemplatePartial => template_partial
Otherwise, it returns the given template_name.
Otherwise, this method returns the template_name.
"""
if template_name:
return template_name
if self.template_name:
return self.template_name
template_name = self.__class__.__name__
......@@ -114,7 +130,7 @@ class View(object):
Return the view rendered using the current context.
"""
template = Template(self.get_template(self.template_name), self)
template = Template(self.get_template(), self)
return template.render(encoding=encoding)
def __contains__(self, needle):
......
import os
import unittest
import pystache
class TestLoader(unittest.TestCase):
from pystache.loader import Loader
class LoaderTestCase(unittest.TestCase):
def test_init(self):
"""
Test the __init__() constructor.
"""
loader = Loader()
self.assertEquals(loader.search_dirs, [os.curdir])
self.assertTrue(loader.template_encoding is None)
self.assertEquals(loader.template_extension, 'mustache')
loader = Loader(search_dirs=['foo'], encoding='utf-8', extension='txt')
self.assertEquals(loader.search_dirs, ['foo'])
self.assertEquals(loader.template_encoding, 'utf-8')
self.assertEquals(loader.template_extension, 'txt')
def test_template_is_loaded(self):
loader = pystache.Loader()
template = loader.load_template('simple', 'examples')
loader = Loader(search_dirs='examples')
template = loader.load_template('simple')
self.assertEqual(template, 'Hi {{thing}}!{{blank}}')
def test_using_list_of_paths(self):
loader = pystache.Loader()
template = loader.load_template('simple', ['doesnt_exist', 'examples'])
loader = Loader(search_dirs=['doesnt_exist', 'examples'])
template = loader.load_template('simple')
self.assertEqual(template, 'Hi {{thing}}!{{blank}}')
def test_non_existent_template_fails(self):
loader = pystache.Loader()
self.assertRaises(IOError, loader.load_template, 'simple', 'doesnt_exist')
\ No newline at end of file
loader = Loader()
self.assertRaises(IOError, loader.load_template, 'doesnt_exist')
......@@ -5,11 +5,26 @@ from examples.simple import Simple
from examples.complex_view import ComplexView
from examples.lambdas import Lambdas
from examples.inverted import Inverted, InvertedLists
from pystache.view import View
class Thing(object):
pass
class TestView(unittest.TestCase):
class ViewTestCase(unittest.TestCase):
def test_init(self):
"""
Test the constructor.
"""
class TestView(View):
template = "foo"
view = TestView()
self.assertEquals(view.template, "foo")
def test_basic(self):
view = Simple("Hi {{thing}}!", { 'thing': 'world' })
self.assertEquals(view.render(), "Hi world!")
......@@ -30,6 +45,19 @@ class TestView(unittest.TestCase):
template = Simple().load_template("escaped")
self.assertEquals(template, "<h1>{{title}}</h1>")
def test_custom_load_template(self):
"""
Test passing a custom load_template to View.__init__().
"""
partials_dict = {"partial": "Loaded from dictionary"}
load_template = lambda template_name: partials_dict[template_name]
view = Simple(load_template=load_template)
actual = view.load_template("partial")
self.assertEquals(actual, "Loaded from dictionary")
def test_template_load_from_multiple_path(self):
path = Simple.template_path
Simple.template_path = ('examples/nowhere','examples',)
......
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