Commit c6e3e50b by Carl Whittaker

Merge branch 'development' of https://github.com/zacharyvoase/pystache into development

parents a9bae002 c106cf86
...@@ -4,40 +4,49 @@ import collections ...@@ -4,40 +4,49 @@ import collections
import os import os
import copy import copy
modifiers = {}
def modifier(symbol):
"""Decorator for associating a function with a Mustache tag modifier.
@modifier('P') class Modifiers(dict):
def render_tongue(self, tag_name=None, context=None): """Dictionary with a decorator for assigning functions to keys."""
return ":P %s" % tag_name
def set(self, key):
"""
Decorator function to set the given key to the decorated function.
>>> modifiers = {}
>>> @modifiers.set('P')
... def render_tongue(self, tag_name=None, context=None):
... return ":P %s" % tag_name
>>> modifiers
{'P': <function render_tongue at 0x...>}
"""
def setter(func):
self[key] = func
return func
return setter
{{P yo }} => :P yo
"""
def set_modifier(func):
modifiers[symbol] = func
return func
return set_modifier
class Template(object): class Template(object):
tag_re = None tag_re = None
otag = '{{' otag = '{{'
ctag = '}}' ctag = '}}'
modifiers = Modifiers()
def __init__(self, template=None, context=None, **kwargs): def __init__(self, template=None, context=None, **kwargs):
from view import View from view import View
self.template = template self.template = template
if kwargs: if kwargs:
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._compile_regexps() self._compile_regexps()
def _compile_regexps(self): def _compile_regexps(self):
tags = { tags = {
'otag': re.escape(self.otag), 'otag': re.escape(self.otag),
...@@ -49,7 +58,7 @@ class Template(object): ...@@ -49,7 +58,7 @@ class Template(object):
tag = r"%(otag)s(#|=|&|!|>|\{)?(.+?)\1?%(ctag)s+" tag = r"%(otag)s(#|=|&|!|>|\{)?(.+?)\1?%(ctag)s+"
self.tag_re = re.compile(tag % tags) self.tag_re = re.compile(tag % tags)
def _render_sections(self, template, view): def _render_sections(self, template, view):
while True: while True:
match = self.section_re.search(template) match = self.section_re.search(template)
...@@ -79,23 +88,23 @@ class Template(object): ...@@ -79,23 +88,23 @@ class Template(object):
# Falsey and Negated or Truthy and Not Negated # Falsey and Negated or Truthy and Not Negated
elif (not it and section[2] == '^') or (it and section[2] != '^'): elif (not it and section[2] == '^') or (it and section[2] != '^'):
replacer = inner replacer = inner
template = template.replace(section, replacer) template = template.replace(section, replacer)
return template return template
def _render_tags(self, template): def _render_tags(self, template):
while True: while True:
match = self.tag_re.search(template) match = self.tag_re.search(template)
if match is None: if match is None:
break break
tag, tag_type, tag_name = match.group(0, 1, 2) tag, tag_type, tag_name = match.group(0, 1, 2)
tag_name = tag_name.strip() tag_name = tag_name.strip()
func = modifiers[tag_type] func = self.modifiers[tag_type]
replacement = func(self, tag_name) replacement = func(self, tag_name)
template = template.replace(tag, replacement) template = template.replace(tag, replacement)
return template return template
def _render_dictionary(self, template, context): def _render_dictionary(self, template, context):
...@@ -104,53 +113,53 @@ class Template(object): ...@@ -104,53 +113,53 @@ class Template(object):
out = template.render() out = template.render()
self.view.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):
insides = [] insides = []
for item in listing: for item in listing:
insides.append(self._render_dictionary(template, item)) insides.append(self._render_dictionary(template, item))
return ''.join(insides) return ''.join(insides)
@modifier(None) @modifiers.set(None)
def _render_tag(self, tag_name): def _render_tag(self, tag_name):
raw = self.view.get(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:
return '' return ''
return cgi.escape(unicode(raw)) return cgi.escape(unicode(raw))
@modifier('!') @modifiers.set('!')
def _render_comment(self, tag_name): def _render_comment(self, tag_name):
return '' return ''
@modifier('>') @modifiers.set('>')
def _render_partial(self, template_name): def _render_partial(self, template_name):
from pystache import Loader from pystache import Loader
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)
return template.render() return template.render()
@modifier('=') @modifiers.set('=')
def _change_delimiter(self, tag_name): def _change_delimiter(self, tag_name):
"""Changes the Mustache delimiter.""" """Changes the Mustache delimiter."""
self.otag, self.ctag = tag_name.split(' ') self.otag, self.ctag = tag_name.split(' ')
self._compile_regexps() self._compile_regexps()
return '' return ''
@modifier('{') @modifiers.set('{')
@modifier('&') @modifiers.set('&')
def render_unescaped(self, tag_name): def render_unescaped(self, tag_name):
"""Render a tag without escaping it.""" """Render a tag without escaping it."""
return unicode(self.view.get(tag_name, '')) return unicode(self.view.get(tag_name, ''))
def render(self, encoding=None): def render(self, encoding=None):
template = self._render_sections(self.template, self.view) template = self._render_sections(self.template, self.view)
result = self._render_tags(template) result = self._render_tags(template)
if encoding is not None: if encoding is not None:
result = result.encode(encoding) result = result.encode(encoding)
return result return result
\ No newline at end of file
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