diff options
author | Rodrigo Bernardo Pimentel <rbp@isnomore.net> | 2012-04-04 11:50:48 +0200 |
---|---|---|
committer | Rodrigo Bernardo Pimentel <rbp@isnomore.net> | 2012-04-04 11:50:48 +0200 |
commit | ca2cd4c0651b7d6e2e9e999323af96815723e9f5 (patch) | |
tree | cfe523684912e0036db24c8820d5c9018fe02326 | |
parent | d23da511a54714aa7ba641aefb234a21a5c12d37 (diff) | |
parent | 02a2472def23f1760b30af56d4b67fa58f1b620a (diff) | |
download | pystache-ca2cd4c0651b7d6e2e9e999323af96815723e9f5.tar.gz |
Merge branch 'spec-1.1.2-compliant' into development
-rw-r--r-- | pystache/context.py | 5 | ||||
-rw-r--r-- | tests/common.py | 17 | ||||
-rw-r--r-- | tests/test_context.py | 38 | ||||
-rw-r--r-- | tests/test_renderengine.py | 46 | ||||
-rw-r--r-- | tests/test_simple.py | 20 |
5 files changed, 102 insertions, 24 deletions
diff --git a/pystache/context.py b/pystache/context.py index 6e75c07..2ebf549 100644 --- a/pystache/context.py +++ b/pystache/context.py @@ -54,8 +54,9 @@ def _get_value(item, key): value = attr for part in parts[1:]: - if value is not _NOT_FOUND: - value = _get_value(value, part) + if value is _NOT_FOUND: + break + value = _get_value(value, part) return value diff --git a/tests/common.py b/tests/common.py index adc3ec2..5d1ef5c 100644 --- a/tests/common.py +++ b/tests/common.py @@ -51,3 +51,20 @@ class AssertIsMixin: # http://docs.python.org/library/unittest.html#unittest.TestCase.assertIsNone def assertIs(self, first, second): self.assertTrue(first is second, msg="%s is not %s" % (repr(first), repr(second))) + + +class Attachable(object): + """A trivial object that attaches all constructor named parameters as attributes. + For instance, + + >>> o = Attachable(foo=42, size="of the universe") + >>> o.foo + 42 + >>> o.size + of the universe + """ + def __init__(self, **kwargs): + for arg, value in kwargs.iteritems(): + setattr(self, arg, value) + + diff --git a/tests/test_context.py b/tests/test_context.py index decf4fb..e216405 100644 --- a/tests/test_context.py +++ b/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 Context -from tests.common import AssertIsMixin +from tests.common import AssertIsMixin, Attachable class SimpleObject(object): @@ -398,3 +398,39 @@ class ContextTests(unittest.TestCase, AssertIsMixin): # Confirm the original is unchanged. self.assertEquals(original.get(key), "buzz") + def test_dot_notation__dict(self): + key = "foo.bar" + original = Context({"foo": {"bar": "baz"}}) + self.assertEquals(original.get(key), "baz") + + # Works all the way down + key = "a.b.c.d.e.f.g" + original = Context({"a": {"b": {"c": {"d": {"e": {"f": {"g": "w00t!"}}}}}}}) + self.assertEquals(original.get(key), "w00t!") + + def test_dot_notation__user_object(self): + key = "foo.bar" + original = Context({"foo": Attachable(bar="baz")}) + self.assertEquals(original.get(key), "baz") + + # Works on multiple levels, too + key = "a.b.c.d.e.f.g" + Obj = Attachable + original = Context({"a": Obj(b=Obj(c=Obj(d=Obj(e=Obj(f=Obj(g="w00t!"))))))}) + self.assertEquals(original.get(key), "w00t!") + + def test_dot_notation__mixed_dict_and_obj(self): + key = "foo.bar.baz.bak" + original = Context({"foo": Attachable(bar={"baz": Attachable(bak=42)})}) + self.assertEquals(original.get(key), 42) + + def test_dot_notation__missing_attr_or_key(self): + key = "foo.bar.baz.bak" + original = Context({"foo": {"bar": {}}}) + self.assertEquals(original.get(key), None) + + original = Context({"foo": Attachable(bar=Attachable())}) + self.assertEquals(original.get(key), None) + + + diff --git a/tests/test_renderengine.py b/tests/test_renderengine.py index 6c2831a..7752161 100644 --- a/tests/test_renderengine.py +++ b/tests/test_renderengine.py @@ -11,7 +11,7 @@ import unittest from pystache.context import Context from pystache.parser import ParsingError from pystache.renderengine import RenderEngine -from tests.common import AssertStringMixin +from tests.common import AssertStringMixin, Attachable class RenderEngineTestCase(unittest.TestCase): @@ -453,3 +453,47 @@ class RenderTests(unittest.TestCase, AssertStringMixin): expected = u' {{foo}} ' self._assert_render(expected, '{{=$ $=}} {{foo}} ') self._assert_render(expected, '{{=$ $=}} {{foo}} $={{ }}=$') # was yielding u' '. + + def test_dot_notation(self): + """ + Check that we can use dot notation when the variable is a dict, + a used-defined object, or a combination of both + """ + template = 'Hello, {{person.name}}. I see you are {{person.details.age}}.' + person = Attachable(name='Biggles', details={'age': 42}) + context = {'person': person} + self._assert_render(u'Hello, Biggles. I see you are 42.', template, context) + + def test_dot_notation__missing_attributes_or_keys(self): + """ + Check that, when using dot notation, if the key or attribute does not + exist then its value is rendered as empty + """ + template = """I cannot see {{person.name}}'s age: {{person.age}}. + Nor {{other_person.name}}'s: .""" + expected = u"""I cannot see Biggles's age: . + Nor Mr. Bradshaw's: .""" + context = {'person': {'name': 'Biggles'}, + 'other_person': Attachable(name='Mr. Bradshaw')} + self._assert_render(expected, template, context) + + def test_dot_notation__multiple_levels(self): + """ + Check that using multiple levels of dot attributes works as expected + """ + template = """Hello, Mr. {{person.name.lastname}}. + I see you're back from {{person.travels.last.country.city}}. + I'm missing some of your details: {{person.details.private.editor}}.""" + expected = u"""Hello, Mr. Pither. + I see you're back from Cornwall. + I'm missing some of your details: .""" + context = {'person': {'name': {'firstname': 'unknown', 'lastname': 'Pither'}, + 'travels': {'last': {'country': {'city': 'Cornwall'}}}, + 'details': {'public': 'likes cycling'}}} + self._assert_render(expected, template, context) + + # It should also work with user-defined objects + context = {'person': Attachable(name={'firstname': 'unknown', 'lastname': 'Pither'}, + travels=Attachable(last=Attachable(country=Attachable(city='Cornwall'))), + details=Attachable())} + self._assert_render(expected, template, context) diff --git a/tests/test_simple.py b/tests/test_simple.py index 7dd6f53..a8fc815 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -60,26 +60,6 @@ class TestSimple(unittest.TestCase, AssertStringMixin): template = '{{not_set}} {{blank}}' self.assertEquals(pystache.Renderer().render(template), ' ') - def test_dot_notation_with_dict(self): - template = 'Name: {{person.name}}. Age: {{person.details.age}}. Intimate details (should be empty): {{person.details.intimate}}.' - renderer = Renderer() - context = {'person': {'name': 'Biggles', 'details': {'age': 42}}} - actual = renderer.render(template, context) - self.assertEquals(actual, 'Name: Biggles. Age: 42. Intimate details (should be empty): .') - - def test_dot_notation_with_user_objects(self): - template = 'Name: {{person.name}}. Age: {{person.details.age}}. Intimate details (should be empty): {{person.details.intimate}}.' - renderer = Renderer() - - class Person(object): - def __init__(self, name, details): - self.name = name - self.details = details - - context = {'person': Person('Biggles', {'age': 42})} - actual = renderer.render(template, context) - self.assertEquals(actual, 'Name: Biggles. Age: 42. Intimate details (should be empty): .') - def test_template_partial_extension(self): """ Side note: |