Commit d7475e63 by Chris Jerdonek

Refactoring of Locator class: make_template_name() and locate_path().

Changed make_template_name() from a function into a method.  Moved
the search_dirs argument from a Locator constructor argument to
an argument of Locator.locate_path().
parent 04176645
# coding: utf-8 # coding: utf-8
""" """
This module provides a Locator class. This module provides a Locator class for finding template files.
""" """
...@@ -13,42 +13,14 @@ import sys ...@@ -13,42 +13,14 @@ import sys
DEFAULT_EXTENSION = 'mustache' DEFAULT_EXTENSION = 'mustache'
def make_template_name(obj):
"""
Return the canonical template name for an object instance.
This method converts Python-style class names (PEP 8's recommended
CamelCase, aka CapWords) to lower_case_with_underscords. Here
is an example with code:
>>> class HelloWorld(object):
... pass
>>> hi = HelloWorld()
>>> make_template_name(hi)
'hello_world'
"""
template_name = obj.__class__.__name__
def repl(match):
return '_' + match.group(0).lower()
return re.sub('[A-Z]', repl, template_name)[1:]
class Locator(object): class Locator(object):
def __init__(self, search_dirs=None, extension=None): def __init__(self, extension=None):
""" """
Construct a template locator. Construct a template locator.
Arguments: Arguments:
search_dirs: the list of directories in which to search for templates,
for example when looking for partials. Defaults to the current
working directory. If given a string, the string is interpreted
as a single directory.
extension: the template file extension. Defaults to "mustache". extension: the template file extension. Defaults to "mustache".
Pass False for no extension (i.e. extensionless template files). Pass False for no extension (i.e. extensionless template files).
...@@ -56,13 +28,6 @@ class Locator(object): ...@@ -56,13 +28,6 @@ class Locator(object):
if extension is None: if extension is None:
extension = DEFAULT_EXTENSION extension = DEFAULT_EXTENSION
if search_dirs is None:
search_dirs = os.curdir # i.e. "."
if isinstance(search_dirs, basestring):
search_dirs = [search_dirs]
self.search_dirs = search_dirs
self.template_extension = extension self.template_extension = extension
def make_file_name(self, template_name): def make_file_name(self, template_name):
...@@ -72,15 +37,41 @@ class Locator(object): ...@@ -72,15 +37,41 @@ class Locator(object):
return file_name return file_name
def locate_path(self, template_name): def make_template_name(self, obj):
"""
Return the canonical template name for an object instance.
This method converts Python-style class names (PEP 8's recommended
CamelCase, aka CapWords) to lower_case_with_underscords. Here
is an example with code:
>>> class HelloWorld(object):
... pass
>>> hi = HelloWorld()
>>>
>>> locator = Locator()
>>> locator.make_template_name(hi)
'hello_world'
"""
template_name = obj.__class__.__name__
def repl(match):
return '_' + match.group(0).lower()
return re.sub('[A-Z]', repl, template_name)[1:]
def locate_path(self, template_name, search_dirs):
""" """
Find and return the path to the template with the given name. Find and return the path to the template with the given name.
Raises an IOError if the template cannot be found. Raises an IOError if the template cannot be found.
""" Arguments:
search_dirs = self.search_dirs
search_dirs: the list of directories in which to search for templates.
"""
file_name = self.make_file_name(template_name) file_name = self.make_file_name(template_name)
for dir_path in search_dirs: for dir_path in search_dirs:
......
...@@ -174,12 +174,12 @@ class Renderer(object): ...@@ -174,12 +174,12 @@ class Renderer(object):
""" """
return Reader(encoding=self.file_encoding, decode_errors=self.decode_errors) return Reader(encoding=self.file_encoding, decode_errors=self.decode_errors)
def _make_locator(self): def make_locator(self):
""" """
Create a Locator instance using current attributes. Create a Locator instance using current attributes.
""" """
return Locator(search_dirs=self.search_dirs, extension=self.file_extension) return Locator(extension=self.file_extension)
def _make_load_template(self): def _make_load_template(self):
""" """
...@@ -187,10 +187,10 @@ class Renderer(object): ...@@ -187,10 +187,10 @@ class Renderer(object):
""" """
reader = self._make_reader() reader = self._make_reader()
locator = self._make_locator() locator = self.make_locator()
def load_template(template_name): def load_template(template_name):
path = locator.locate_path(template_name) path = locator.locate_path(template_name=template_name, search_dirs=self.search_dirs)
return reader.read(path) return reader.read(path)
return load_template return load_template
......
...@@ -6,7 +6,7 @@ This module provides a View class. ...@@ -6,7 +6,7 @@ This module provides a View class.
""" """
from .context import Context from .context import Context
from .locator import make_template_name from .locator import Locator
from .renderer import Renderer from .renderer import Renderer
...@@ -20,6 +20,8 @@ class View(object): ...@@ -20,6 +20,8 @@ class View(object):
_renderer = None _renderer = None
locator = Locator()
def __init__(self, template=None, context=None, partials=None, **kwargs): def __init__(self, template=None, context=None, partials=None, **kwargs):
""" """
Construct a View instance. Construct a View instance.
...@@ -85,7 +87,7 @@ class View(object): ...@@ -85,7 +87,7 @@ class View(object):
if self.template_name: if self.template_name:
return self.template_name return self.template_name
return make_template_name(self) return self.locator.make_template_name(self)
def render(self): def render(self):
""" """
......
...@@ -9,27 +9,12 @@ import os ...@@ -9,27 +9,12 @@ import os
import sys import sys
import unittest import unittest
from pystache.locator import make_template_name
from pystache.locator import Locator from pystache.locator import Locator
from pystache.reader import Reader from pystache.reader import Reader
from .common import DATA_DIR from .common import DATA_DIR
class MakeTemplateNameTests(unittest.TestCase):
"""
Test the make_template_name() function.
"""
def test(self):
class FooBar(object):
pass
foo = FooBar()
self.assertEquals(make_template_name(foo), 'foo_bar')
class LocatorTests(unittest.TestCase): class LocatorTests(unittest.TestCase):
search_dirs = 'examples' search_dirs = 'examples'
...@@ -37,14 +22,6 @@ class LocatorTests(unittest.TestCase): ...@@ -37,14 +22,6 @@ class LocatorTests(unittest.TestCase):
def _locator(self): def _locator(self):
return Locator(search_dirs=DATA_DIR) return Locator(search_dirs=DATA_DIR)
def test_init__search_dirs(self):
# Test the default value.
locator = Locator()
self.assertEquals(locator.search_dirs, [os.curdir])
locator = Locator(search_dirs=['foo'])
self.assertEquals(locator.search_dirs, ['foo'])
def test_init__extension(self): def test_init__extension(self):
# Test the default value. # Test the default value.
locator = Locator() locator = Locator()
...@@ -69,14 +46,14 @@ class LocatorTests(unittest.TestCase): ...@@ -69,14 +46,14 @@ class LocatorTests(unittest.TestCase):
self.assertEquals(locator.make_file_name('foo'), 'foo.') self.assertEquals(locator.make_file_name('foo'), 'foo.')
def test_locate_path(self): def test_locate_path(self):
locator = Locator(search_dirs='examples') locator = Locator()
path = locator.locate_path('simple') path = locator.locate_path('simple', search_dirs=['examples'])
self.assertEquals(os.path.basename(path), 'simple.mustache') self.assertEquals(os.path.basename(path), 'simple.mustache')
def test_locate_path__using_list_of_paths(self): def test_locate_path__using_list_of_paths(self):
locator = Locator(search_dirs=['doesnt_exist', 'examples']) locator = Locator()
path = locator.locate_path('simple') path = locator.locate_path('simple', search_dirs=['doesnt_exist', 'examples'])
self.assertTrue(path) self.assertTrue(path)
...@@ -90,13 +67,10 @@ class LocatorTests(unittest.TestCase): ...@@ -90,13 +67,10 @@ class LocatorTests(unittest.TestCase):
dir1 = DATA_DIR dir1 = DATA_DIR
dir2 = os.path.join(DATA_DIR, 'locator') dir2 = os.path.join(DATA_DIR, 'locator')
locator.search_dirs = [dir1] self.assertTrue(locator.locate_path('duplicate', search_dirs=[dir1]))
self.assertTrue(locator.locate_path('duplicate')) self.assertTrue(locator.locate_path('duplicate', search_dirs=[dir2]))
locator.search_dirs = [dir2]
self.assertTrue(locator.locate_path('duplicate'))
locator.search_dirs = [dir2, dir1] path = locator.locate_path('duplicate', search_dirs=[dir2, dir1])
path = locator.locate_path('duplicate')
dirpath = os.path.dirname(path) dirpath = os.path.dirname(path)
dirname = os.path.split(dirpath)[-1] dirname = os.path.split(dirpath)[-1]
...@@ -105,5 +79,17 @@ class LocatorTests(unittest.TestCase): ...@@ -105,5 +79,17 @@ class LocatorTests(unittest.TestCase):
def test_locate_path__non_existent_template_fails(self): def test_locate_path__non_existent_template_fails(self):
locator = Locator() locator = Locator()
self.assertRaises(IOError, locator.locate_path, 'doesnt_exist') self.assertRaises(IOError, locator.locate_path, 'doesnt_exist', search_dirs=[])
def test_make_template_name(self):
"""
Test make_template_name().
"""
locator = Locator()
class FooBar(object):
pass
foo = FooBar()
self.assertEquals(locator.make_template_name(foo), 'foo_bar')
...@@ -216,53 +216,40 @@ class RendererTestCase(unittest.TestCase): ...@@ -216,53 +216,40 @@ class RendererTestCase(unittest.TestCase):
actual = self._read(renderer, filename) actual = self._read(renderer, filename)
self.assertEquals(actual, 'non-ascii: ') self.assertEquals(actual, 'non-ascii: ')
## Test the _make_locator() method. ## Test the make_locator() method.
def test__make_locator__return_type(self): def test_make_locator__return_type(self):
""" """
Test that _make_locator() returns a Locator. Test that make_locator() returns a Locator.
""" """
renderer = Renderer() renderer = Renderer()
locator = renderer._make_locator() locator = renderer.make_locator()
self.assertEquals(type(locator), Locator) self.assertEquals(type(locator), Locator)
def test__make_locator__file_extension(self): def test_make_locator__file_extension(self):
""" """
Test that _make_locator() respects the file_extension attribute. Test that make_locator() respects the file_extension attribute.
""" """
renderer = Renderer() renderer = Renderer()
renderer.file_extension = 'foo' renderer.file_extension = 'foo'
locator = renderer._make_locator() locator = renderer.make_locator()
self.assertEquals(locator.template_extension, 'foo') self.assertEquals(locator.template_extension, 'foo')
def test__make_locator__search_dirs(self):
"""
Test that _make_locator() respects the search_dirs attribute.
"""
renderer = Renderer()
renderer.search_dirs = ['foo']
locator = renderer._make_locator()
self.assertEquals(locator.search_dirs, ['foo'])
# This test is a sanity check. Strictly speaking, it shouldn't # This test is a sanity check. Strictly speaking, it shouldn't
# be necessary based on our tests above. # be necessary based on our tests above.
def test__make_locator__default(self): def test_make_locator__default(self):
renderer = Renderer() renderer = Renderer()
actual = renderer._make_locator() actual = renderer.make_locator()
expected = Locator() expected = Locator()
self.assertEquals(type(actual), type(expected)) self.assertEquals(type(actual), type(expected))
self.assertEquals(actual.template_extension, expected.template_extension) self.assertEquals(actual.template_extension, expected.template_extension)
self.assertEquals(actual.search_dirs, expected.search_dirs)
## Test the render() method. ## Test the render() method.
......
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