summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pystache/context.py61
-rw-r--r--pystache/renderengine.py6
-rw-r--r--pystache/tests/test_context.py6
3 files changed, 42 insertions, 31 deletions
diff --git a/pystache/context.py b/pystache/context.py
index bd927e0..cf36c7d 100644
--- a/pystache/context.py
+++ b/pystache/context.py
@@ -1,7 +1,7 @@
# coding: utf-8
"""
-Exposes a ContextStack class and functions to retrieve names from context.
+Exposes a ContextStack class.
"""
@@ -27,6 +27,8 @@ def _is_callable(obj):
return hasattr(obj, '__call__')
+# TODO: rename item to context (now that we have a separate notion of context stack).
+# TODO: document what a "context" is as opposed to a context stack.
def _get_value(item, key):
"""
Retrieve a key's value from an item.
@@ -168,54 +170,62 @@ class ContextStack(object):
return context
# TODO: add some unit tests for this.
- def resolve(self, name):
+ def get(self, name, default=u''):
"""
- Resolve a name against a context stack.
+ Resolve a dotted name against the current context stack.
This function follows the rules outlined in the section of the spec
regarding tag interpolation.
Arguments:
- context_stack: a ContextStack instance.
+ name: a dotted or non-dotted name.
+
+ default: the value to return if name resolution fails at any point.
+ Defaults to the empty string since the Mustache spec says that if
+ name resolution fails at any point, the result should be considered
+ falsey, and should interpolate as the empty string.
This function does not coerce the return value to a string.
"""
if name == '.':
+ # TODO: should we add a test case for an empty context stack?
return self.top()
parts = name.split('.')
- value = self.get(parts[0], _NOT_FOUND)
+ value = self._get_simple(parts[0])
- # TODO: make sure we have a test case for the following point.
- #
- # The full context stack is not used to resolve the remaining parts.
- # From the spec--
- #
- # If any name parts were retained in step 1, each should be resolved
- # against a context stack containing only the result from the former
- # resolution.
- #
for part in parts[1:]:
# TODO: consider using EAFP here instead.
# http://docs.python.org/glossary.html#term-eafp
if value is _NOT_FOUND:
break
+ # The full context stack is not used to resolve the remaining parts.
+ # From the spec--
+ #
+ # If any name parts were retained in step 1, each should be resolved
+ # against a context stack containing only the result from the former
+ # resolution.
+ #
+ # TODO: make sure we have a test case for the above point.
value = _get_value(value, part)
- # The spec says that if name resolution fails at any point, the result
- # should be considered falsey, and should interpolate as the empty string.
if value is _NOT_FOUND:
- return ''
+ return default
return value
- # TODO: rename this method _get_part().
- def get(self, key, default=None):
+ # TODO: combine the docstring for this method with the docstring for
+ # the get() method.
+ def _get_simple(self, key):
"""
- Query the stack for the given key, and return the resulting value.
+ Query the stack for a non-dotted key, and return the resulting value.
+
+ Arguments:
+
+ key: a non-dotted name.
This method queries items in the stack in order from last-added
objects to first (last in, first out). The value returned is
@@ -280,15 +290,16 @@ class ContextStack(object):
TODO: explain the rationale for this difference in treatment.
"""
- for obj in reversed(self._stack):
- val = _get_value(obj, key)
+ val = _NOT_FOUND
+
+ for item in reversed(self._stack):
+ val = _get_value(item, key)
if val is _NOT_FOUND:
continue
# Otherwise, the key was found.
- return val
- # Otherwise, no item in the stack contained the key.
+ break
- return default
+ return val
def push(self, item):
"""
diff --git a/pystache/renderengine.py b/pystache/renderengine.py
index 918acfb..b05e022 100644
--- a/pystache/renderengine.py
+++ b/pystache/renderengine.py
@@ -68,7 +68,7 @@ class RenderEngine(object):
Get a value from the given context as a basestring instance.
"""
- val = context.resolve(tag_name)
+ val = context.get(tag_name)
if callable(val):
# According to the spec:
@@ -135,7 +135,7 @@ class RenderEngine(object):
"""
# TODO: is there a bug because we are not using the same
# logic as in _get_string_value()?
- data = context.resolve(name)
+ data = context.get(name)
# Per the spec, lambdas in inverted sections are considered truthy.
if data:
return u''
@@ -154,7 +154,7 @@ class RenderEngine(object):
"""
template = template_
parsed_template = parsed_template_
- data = context.resolve(name)
+ data = context.get(name)
# From the spec:
#
diff --git a/pystache/tests/test_context.py b/pystache/tests/test_context.py
index dd9fdae..538c74e 100644
--- a/pystache/tests/test_context.py
+++ b/pystache/tests/test_context.py
@@ -11,7 +11,7 @@ import unittest
from pystache.context import _NOT_FOUND
from pystache.context import _get_value
from pystache.context import ContextStack
-from pystache.tests.common import AssertIsMixin
+from pystache.tests.common import AssertIsMixin, AssertStringMixin
class SimpleObject(object):
@@ -204,7 +204,7 @@ class GetValueTests(unittest.TestCase, AssertIsMixin):
self.assertNotFound(item2, 'pop')
-class ContextStackTests(unittest.TestCase, AssertIsMixin):
+class ContextStackTests(unittest.TestCase, AssertIsMixin, AssertStringMixin):
"""
Test the ContextStack class.
@@ -320,7 +320,7 @@ class ContextStackTests(unittest.TestCase, AssertIsMixin):
"""
context = ContextStack()
- self.assertTrue(context.get("foo") is None)
+ self.assertString(context.get("foo"), u'')
def test_get__default(self):
"""