Commit 2f3864f9 by Chris Jerdonek

Merge branch 'issue-127' into development: address issue #127

This merge addresses issue #127 by adding support for finding and loading
templates by file name in addition to by template name.

Thanks again, @xgecko.
parents 3d995628 a1623d7c
...@@ -6,6 +6,8 @@ History ...@@ -6,6 +6,8 @@ History
- Added option of raising errors on missing tags/partials: - Added option of raising errors on missing tags/partials:
`Renderer(missing_tags='strict')` (issue \#110). `Renderer(missing_tags='strict')` (issue \#110).
- Added support for finding and loading templates by file name in
addition to by template name (issue \#127). [xgecko]
- Added a `parse()` function that yields a printable, pre-compiled - Added a `parse()` function that yields a printable, pre-compiled
parse tree. parse tree.
- Added support for rendering pre-compiled templates. - Added support for rendering pre-compiled templates.
......
...@@ -61,5 +61,5 @@ SEARCH_DIRS = [os.curdir] # i.e. ['.'] ...@@ -61,5 +61,5 @@ SEARCH_DIRS = [os.curdir] # i.e. ['.']
# #
TAG_ESCAPE = lambda u: escape(u, quote=True) TAG_ESCAPE = lambda u: escape(u, quote=True)
# The default template extension. # The default template extension, without the leading dot.
TEMPLATE_EXTENSION = 'mustache' TEMPLATE_EXTENSION = 'mustache'
...@@ -42,9 +42,9 @@ class Loader(object): ...@@ -42,9 +42,9 @@ class Loader(object):
Arguments: Arguments:
extension: the template file extension. Pass False for no extension: the template file extension, without the leading dot.
extension (i.e. to use extensionless template files). Pass False for no extension (e.g. to use extensionless template
Defaults to the package default. files). Defaults to the package default.
file_encoding: the name of the encoding to use when converting file file_encoding: the name of the encoding to use when converting file
contents to unicode. Defaults to the package default. contents to unicode. Defaults to the package default.
...@@ -119,17 +119,29 @@ class Loader(object): ...@@ -119,17 +119,29 @@ class Loader(object):
return self.unicode(b, encoding) return self.unicode(b, encoding)
# TODO: unit-test this method. def load_file(self, file_name):
"""
Find and return the template with the given file name.
Arguments:
file_name: the file name of the template.
"""
locator = self._make_locator()
path = locator.find_file(file_name, self.search_dirs)
return self.read(path)
def load_name(self, name): def load_name(self, name):
""" """
Find and return the template with the given name. Find and return the template with the given template name.
Arguments: Arguments:
name: the name of the template. name: the name of the template.
search_dirs: the list of directories in which to search.
""" """
locator = self._make_locator() locator = self._make_locator()
......
...@@ -21,9 +21,9 @@ class Locator(object): ...@@ -21,9 +21,9 @@ class Locator(object):
Arguments: Arguments:
extension: the template file extension. Pass False for no extension: the template file extension, without the leading dot.
extension (i.e. to use extensionless template files). Pass False for no extension (e.g. to use extensionless template
Defaults to the package default. files). Defaults to the package default.
""" """
if extension is None: if extension is None:
...@@ -123,10 +123,29 @@ class Locator(object): ...@@ -123,10 +123,29 @@ class Locator(object):
return path return path
def find_file(self, file_name, search_dirs):
"""
Return the path to a template with the given file name.
Arguments:
file_name: the file name of the template.
search_dirs: the list of directories in which to search.
"""
return self._find_path_required(search_dirs, file_name)
def find_name(self, template_name, search_dirs): def find_name(self, template_name, search_dirs):
""" """
Return the path to a template with the given name. Return the path to a template with the given name.
Arguments:
template_name: the name of the template.
search_dirs: the list of directories in which to search.
""" """
file_name = self.make_file_name(template_name) file_name = self.make_file_name(template_name)
......
...@@ -14,6 +14,10 @@ from pystache import defaults ...@@ -14,6 +14,10 @@ from pystache import defaults
from pystache.loader import Loader from pystache.loader import Loader
# We use the same directory as the locator tests for now.
LOADER_DATA_DIR = os.path.join(DATA_DIR, 'locator')
class LoaderTests(unittest.TestCase, AssertStringMixin, SetupDefaults): class LoaderTests(unittest.TestCase, AssertStringMixin, SetupDefaults):
def setUp(self): def setUp(self):
...@@ -178,7 +182,7 @@ class LoaderTests(unittest.TestCase, AssertStringMixin, SetupDefaults): ...@@ -178,7 +182,7 @@ class LoaderTests(unittest.TestCase, AssertStringMixin, SetupDefaults):
actual = loader.read(path, encoding='utf-8') actual = loader.read(path, encoding='utf-8')
self.assertString(actual, u'non-ascii: é') self.assertString(actual, u'non-ascii: é')
def test_loader__to_unicode__attribute(self): def test_read__to_unicode__attribute(self):
""" """
Test read(): to_unicode attribute respected. Test read(): to_unicode attribute respected.
...@@ -192,3 +196,14 @@ class LoaderTests(unittest.TestCase, AssertStringMixin, SetupDefaults): ...@@ -192,3 +196,14 @@ class LoaderTests(unittest.TestCase, AssertStringMixin, SetupDefaults):
#actual = loader.read(path) #actual = loader.read(path)
#self.assertString(actual, u'non-ascii: ') #self.assertString(actual, u'non-ascii: ')
def test_load_file(self):
loader = Loader(search_dirs=[DATA_DIR, LOADER_DATA_DIR])
template = loader.load_file('template.txt')
self.assertEqual(template, 'Test template file\n')
def test_load_name(self):
loader = Loader(search_dirs=[DATA_DIR, LOADER_DATA_DIR],
extension='txt')
template = loader.load_name('template')
self.assertEqual(template, 'Test template file\n')
...@@ -19,6 +19,9 @@ from pystache.tests.common import DATA_DIR, EXAMPLES_DIR, AssertExceptionMixin ...@@ -19,6 +19,9 @@ from pystache.tests.common import DATA_DIR, EXAMPLES_DIR, AssertExceptionMixin
from pystache.tests.data.views import SayHello from pystache.tests.data.views import SayHello
LOCATOR_DATA_DIR = os.path.join(DATA_DIR, 'locator')
class LocatorTests(unittest.TestCase, AssertExceptionMixin): class LocatorTests(unittest.TestCase, AssertExceptionMixin):
def _locator(self): def _locator(self):
...@@ -87,6 +90,13 @@ class LocatorTests(unittest.TestCase, AssertExceptionMixin): ...@@ -87,6 +90,13 @@ class LocatorTests(unittest.TestCase, AssertExceptionMixin):
self.assertEqual(locator.make_file_name('foo', template_extension='bar'), 'foo.bar') self.assertEqual(locator.make_file_name('foo', template_extension='bar'), 'foo.bar')
def test_find_file(self):
locator = Locator()
path = locator.find_file('template.txt', [LOCATOR_DATA_DIR])
expected_path = os.path.join(LOCATOR_DATA_DIR, 'template.txt')
self.assertEqual(path, expected_path)
def test_find_name(self): def test_find_name(self):
locator = Locator() locator = Locator()
path = locator.find_name(search_dirs=[EXAMPLES_DIR], template_name='simple') path = locator.find_name(search_dirs=[EXAMPLES_DIR], template_name='simple')
...@@ -107,7 +117,7 @@ class LocatorTests(unittest.TestCase, AssertExceptionMixin): ...@@ -107,7 +117,7 @@ class LocatorTests(unittest.TestCase, AssertExceptionMixin):
locator = Locator() locator = Locator()
dir1 = DATA_DIR dir1 = DATA_DIR
dir2 = os.path.join(DATA_DIR, 'locator') dir2 = LOCATOR_DATA_DIR
self.assertTrue(locator.find_name(search_dirs=[dir1], template_name='duplicate')) self.assertTrue(locator.find_name(search_dirs=[dir1], template_name='duplicate'))
self.assertTrue(locator.find_name(search_dirs=[dir2], template_name='duplicate')) self.assertTrue(locator.find_name(search_dirs=[dir2], template_name='duplicate'))
......
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