diff --git a/pystache/common.py b/pystache/common.py index fb266dd8..dc869655 100644 --- a/pystache/common.py +++ b/pystache/common.py @@ -53,6 +53,10 @@ def read(path): f.close() +class _BaseNode(object): + pass + + class MissingTags(object): """Contains the valid values for Renderer.missing_tags.""" diff --git a/pystache/parsed.py b/pystache/parsed.py index 372d96c6..a80bf905 100644 --- a/pystache/parsed.py +++ b/pystache/parsed.py @@ -5,6 +5,8 @@ """ +from pystache.common import _BaseNode + class ParsedTemplate(object): @@ -48,3 +50,35 @@ def get_unicode(node): s = ''.join(parts) return unicode(s) + + def get_node(self, key): + for node in self._parse_tree: + if not isinstance(node, _BaseNode): + continue + + _found_key = getattr(node, 'key', None) + + if _found_key == key: + # Node with given key is found + return node + + parsed = getattr(node, 'parsed', getattr(node, 'parsed_section', None)) + + if parsed is None: + continue + + found_in_nested = parsed.get_node(key) + if found_in_nested is None: + continue + else: + return found_in_nested + + return None + + +def _as_template(self): + template = ParsedTemplate() + template.add(self) + return template + +_BaseNode.as_template = _as_template diff --git a/pystache/parser.py b/pystache/parser.py index c6a171f0..c30fb783 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -9,6 +9,7 @@ from pystache import defaults from pystache.parsed import ParsedTemplate +from pystache.common import _BaseNode END_OF_LINE_CHARACTERS = [u'\r', u'\n'] @@ -88,7 +89,7 @@ def _format(obj, exclude=None): return "%s(%s)" % (obj.__class__.__name__, ", ".join(args)) -class _CommentNode(object): +class _CommentNode(_BaseNode): def __repr__(self): return _format(self) @@ -97,7 +98,7 @@ def render(self, engine, context): return u'' -class _ChangeNode(object): +class _ChangeNode(_BaseNode): def __init__(self, delimiters): self.delimiters = delimiters @@ -109,7 +110,7 @@ def render(self, engine, context): return u'' -class _EscapeNode(object): +class _EscapeNode(_BaseNode): def __init__(self, key): self.key = key @@ -122,7 +123,7 @@ def render(self, engine, context): return engine.escape(s) -class _LiteralNode(object): +class _LiteralNode(_BaseNode): def __init__(self, key): self.key = key @@ -135,7 +136,7 @@ def render(self, engine, context): return engine.literal(s) -class _PartialNode(object): +class _PartialNode(_BaseNode): def __init__(self, key, indent): self.key = key @@ -152,7 +153,7 @@ def render(self, engine, context): return engine.render(template, context) -class _InvertedNode(object): +class _InvertedNode(_BaseNode): def __init__(self, key, parsed_section): self.key = key @@ -172,7 +173,7 @@ def render(self, engine, context): return self.parsed_section.render(engine, context) -class _SectionNode(object): +class _SectionNode(_BaseNode): # TODO: the template_ and parsed_template_ arguments don't both seem # to be necessary. Can we remove one of them? For example, if diff --git a/pystache/tests/examples/node_as_template.mustache b/pystache/tests/examples/node_as_template.mustache new file mode 100644 index 00000000..c07ebd78 --- /dev/null +++ b/pystache/tests/examples/node_as_template.mustache @@ -0,0 +1,5 @@ +{{#foo}} +
+ {{#bar}}Hello {{name}}!{{/bar}} +
+{{/foo}} diff --git a/pystache/tests/test_examples.py b/pystache/tests/test_examples.py index 5c9f74da..484f2257 100644 --- a/pystache/tests/test_examples.py +++ b/pystache/tests/test_examples.py @@ -16,7 +16,7 @@ from examples.unicode_output import UnicodeOutput from examples.unicode_input import UnicodeInput from examples.nested_context import NestedContext -from pystache import Renderer +from pystache import Renderer, parse from pystache.tests.common import EXAMPLES_DIR from pystache.tests.common import AssertStringMixin @@ -102,5 +102,14 @@ def test_partial_in_partial_has_access_to_grand_parent_context(self): actual = renderer.render(view, {'prop': 'derp'}) self.assertEqual(actual, 'Hi derp!') + def test_node_as_template(self): + renderer = Renderer(search_dirs=EXAMPLES_DIR) + + full_template = parse(renderer.load_template('node_as_template')) + node_template = full_template.get_node('bar').as_template() + + actual = renderer.render(node_template, {'bar': {'name': 'Chris'}}) + self.assertEqual(actual, 'Hello Chris!') + if __name__ == '__main__': unittest.main()