Commit 16ce94a2 by Carl Whittaker

Moving context logic into view

parent ac941e56
<h1>{{ header }}</h1> <h1>{{ header }}</h1>{{#list}}<ul>{{#item}}{{# current }}<li><strong>{{name}}</strong></li>{{/ current }}{{#link}}<li><a href="{{url}}">{{name}}</a></li>{{/link}}{{/item}}</ul>{{/list}}{{#empty}}<p>The list is empty.</p>{{/empty}}
{{#list}} \ No newline at end of file
<ul>
{{#item}}
{{# current }}
<li><strong>{{name}}</strong></li>
{{/ current }}
{{#link}}
<li><a href="{{url}}">{{name}}</a></li>
{{/link}}
{{/item}}
</ul>
{{/list}}
{{#empty}}
<p>The list is empty.</p>
{{/empty}}
\ No newline at end of file
{{#t}} {{#t}}* first{{/t}}
* first
{{/t}}
* {{two}} * {{two}}
{{#t}} {{#t}}* third{{/t}}
* third \ No newline at end of file
{{/t}}
\ No newline at end of file
{{#replace_foo_with_bar}} {{#replace_foo_with_bar}}foo != bar. oh, it does!{{/replace_foo_with_bar}}
foo != bar. oh, it does! \ No newline at end of file
{{/replace_foo_with_bar}}
\ No newline at end of file
...@@ -19,21 +19,21 @@ def modifier(symbol): ...@@ -19,21 +19,21 @@ def modifier(symbol):
return func return func
return set_modifier return set_modifier
def get_or_attr(context_list, name, default=None): # def get_or_attr(context_list, name, default=None):
if not context_list: # if not context_list:
return default # return default
#
for obj in context_list: # for obj in context_list:
try: # try:
return obj[name] # return obj[name]
except KeyError: # except KeyError:
pass # pass
except: # except:
try: # try:
return getattr(obj, name) # return getattr(obj, name)
except AttributeError: # except AttributeError:
pass # pass
return default # return default
class Template(object): class Template(object):
...@@ -52,7 +52,6 @@ class Template(object): ...@@ -52,7 +52,6 @@ class Template(object):
context.update(kwargs) context.update(kwargs)
self.view = context if isinstance(context, View) else View(context=context) self.view = context if isinstance(context, View) else View(context=context)
self.context_list = [self.view]
self._compile_regexps() self._compile_regexps()
def _compile_regexps(self): def _compile_regexps(self):
...@@ -76,7 +75,7 @@ class Template(object): ...@@ -76,7 +75,7 @@ class Template(object):
section, section_name, inner = match.group(0, 1, 2) section, section_name, inner = match.group(0, 1, 2)
section_name = section_name.strip() section_name = section_name.strip()
it = get_or_attr(self.context_list, section_name, None) it = self.view.get(section_name, None)
replacer = '' replacer = ''
# Callable # Callable
...@@ -113,11 +112,10 @@ class Template(object): ...@@ -113,11 +112,10 @@ class Template(object):
return template return template
def _render_dictionary(self, template, context): def _render_dictionary(self, template, context):
self.view.context_list.insert(0, context)
template = Template(template, self.view) template = Template(template, self.view)
self.context_list.insert(0, context)
template.context_list = self.context_list
out = template.render() out = template.render()
self.context_list.pop(0) self.view.context_list.pop(0)
return out return out
def _render_list(self, template, listing): def _render_list(self, template, listing):
...@@ -129,7 +127,7 @@ class Template(object): ...@@ -129,7 +127,7 @@ class Template(object):
@modifier(None) @modifier(None)
def _render_tag(self, tag_name): def _render_tag(self, tag_name):
raw = get_or_attr(self.context_list, tag_name, '') raw = self.view.get(tag_name, '')
# For methods with no return value # For methods with no return value
if not raw and raw is not 0: if not raw and raw is not 0:
...@@ -147,7 +145,7 @@ class Template(object): ...@@ -147,7 +145,7 @@ class Template(object):
markup = Loader().load_template(template_name, self.view.template_path, encoding=self.view.template_encoding) markup = Loader().load_template(template_name, self.view.template_path, encoding=self.view.template_encoding)
template = Template(markup, self.view) template = Template(markup, self.view)
template.context_list = self.context_list # template.context_list = self.context_list
return template.render() return template.render()
@modifier('=') @modifier('=')
......
...@@ -3,6 +3,22 @@ import os.path ...@@ -3,6 +3,22 @@ import os.path
import re import re
from types import * from types import *
def get_or_attr(context_list, name, default=None):
if not context_list:
return default
for obj in context_list:
try:
return obj[name]
except KeyError:
pass
except:
try:
return getattr(obj, name)
except AttributeError:
pass
return default
class View(object): class View(object):
template_name = None template_name = None
...@@ -13,15 +29,15 @@ class View(object): ...@@ -13,15 +29,15 @@ class View(object):
def __init__(self, template=None, context=None, **kwargs): def __init__(self, template=None, context=None, **kwargs):
self.template = template self.template = template
self.context = context or {} context = context or {}
self.context.update(**kwargs) context.update(**kwargs)
self.context_list = [context]
def get(self, attr, default=None): def get(self, attr, default=None):
attr = self.context.get(attr, getattr(self, attr, default)) attr = get_or_attr(self.context_list, attr, getattr(self, attr, default))
if hasattr(attr, '__call__') and type(attr) is UnboundMethodType: if hasattr(attr, '__call__') and type(attr) is UnboundMethodType:
return attr() return attr()
if hasattr(attr, 'render'):
return attr.render(encoding=self.template_encoding)
else: else:
return attr return attr
...@@ -48,7 +64,7 @@ class View(object): ...@@ -48,7 +64,7 @@ class View(object):
return re.sub('[A-Z]', repl, template_name)[1:] return re.sub('[A-Z]', repl, template_name)[1:]
def render(self, encoding=None): def render(self, encoding=None):
return Template(self.get_template(self.template_name), self).render(encoding=encoding) return Template(self.get_template(self.template_name), self).render(encoding=encoding)
def __contains__(self, needle): def __contains__(self, needle):
...@@ -56,9 +72,10 @@ class View(object): ...@@ -56,9 +72,10 @@ class View(object):
def __getitem__(self, attr): def __getitem__(self, attr):
val = self.get(attr, None) val = self.get(attr, None)
if not val and val is not 0: if not val and val is not 0:
raise KeyError("No such key.") raise KeyError("No such key.")
return val return val
def __str__(self): def __str__(self):
return self.render() return self.render()
\ No newline at end of file
...@@ -19,9 +19,7 @@ class TestView(unittest.TestCase): ...@@ -19,9 +19,7 @@ class TestView(unittest.TestCase):
""") """)
def test_double_section(self): def test_double_section(self):
self.assertEquals(DoubleSection().render(), """* first self.assertEquals(DoubleSection().render(),"""* first\n* second\n* third""")
* second
* third""")
def test_unicode_output(self): def test_unicode_output(self):
self.assertEquals(UnicodeOutput().render(), u'<p>Name: Henri Poincaré</p>') self.assertEquals(UnicodeOutput().render(), u'<p>Name: Henri Poincaré</p>')
...@@ -77,8 +75,7 @@ Again, Welcome! ...@@ -77,8 +75,7 @@ Again, Welcome!
self.assertEquals(view.render(), 'it works!') self.assertEquals(view.render(), 'it works!')
def test_partial_in_partial_has_access_to_grand_parent_context(self): def test_partial_in_partial_has_access_to_grand_parent_context(self):
view = TemplatePartial() view = TemplatePartial(context = {'prop': 'derp'})
view.context = {'prop': 'derp'}
view.template = '''{{>partial_in_partial}}''' view.template = '''{{>partial_in_partial}}'''
self.assertEquals(view.render(), 'Hi derp!') self.assertEquals(view.render(), 'Hi derp!')
......
...@@ -63,21 +63,11 @@ class TestPystache(unittest.TestCase): ...@@ -63,21 +63,11 @@ class TestPystache(unittest.TestCase):
self.assertEquals(ret, u'Name: Henri Poincaré; Age: 156') self.assertEquals(ret, u'Name: Henri Poincaré; Age: 156')
def test_sections(self): def test_sections(self):
template = """ template = """<ul>{{#users}}<li>{{name}}</li>{{/users}}</ul>"""
<ul>
{{#users}}
<li>{{name}}</li>
{{/users}}
</ul>
"""
context = { 'users': [ {'name': 'Chris'}, {'name': 'Tom'}, {'name': 'PJ'} ] } context = { 'users': [ {'name': 'Chris'}, {'name': 'Tom'}, {'name': 'PJ'} ] }
ret = pystache.render(template, context) ret = pystache.render(template, context)
self.assertEquals(ret, """ self.assertEquals(ret, """<ul><li>Chris</li><li>Tom</li><li>PJ</li></ul>""")
<ul>
<li>Chris</li><li>Tom</li><li>PJ</li>
</ul>
""")
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -54,12 +54,8 @@ class TestView(unittest.TestCase): ...@@ -54,12 +54,8 @@ class TestView(unittest.TestCase):
self.assertEquals(view.render(), "Hi chris!") self.assertEquals(view.render(), "Hi chris!")
def test_complex(self): def test_complex(self):
self.assertEquals(ComplexView().render(), """<h1>Colors</h1> self.assertEquals(ComplexView().render(),
<ul> """<h1>Colors</h1><ul><li><strong>red</strong></li><li><a href="#Green">green</a></li><li><a href="#Blue">blue</a></li></ul>""")
<li><strong>red</strong></li>\n \n <li><a href="#Green">green</a></li>
<li><a href="#Blue">blue</a></li>
</ul>
""")
def test_higher_order_replace(self): def test_higher_order_replace(self):
view = Lambdas() view = Lambdas()
...@@ -90,6 +86,11 @@ class TestView(unittest.TestCase): ...@@ -90,6 +86,11 @@ class TestView(unittest.TestCase):
view = Inverted() view = Inverted()
self.assertEquals(view.render(), """one, two, three, empty list""") self.assertEquals(view.render(), """one, two, three, empty list""")
# def test_accessing_properties_on_parent_view(self):
# view = Simple(context={'child':child})
# view.template = '{{#child}}{{#t}}{{thing}}{{/t}}{{/child}}'
#
# self.assertEquals(view.render(), 'pizza1')
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
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