Commit 19ac543d by Chris Jerdonek

Created _Parser class inside renderengine.py.

parent 73306a88
...@@ -110,12 +110,9 @@ class RenderEngine(object): ...@@ -110,12 +110,9 @@ class RenderEngine(object):
""" """
_delimiters = None
_template_re = None
nonblank_re = re.compile(r'^(.)', re.M) nonblank_re = re.compile(r'^(.)', re.M)
def __init__(self, load_partial=None, literal=None, escape=None, delimiters=None): def __init__(self, load_partial=None, literal=None, escape=None):
""" """
Arguments: Arguments:
...@@ -145,64 +142,10 @@ class RenderEngine(object): ...@@ -145,64 +142,10 @@ class RenderEngine(object):
from plain unicode strings. from plain unicode strings.
""" """
if delimiters is None:
delimiters = DEFAULT_DELIMITERS
self._delimiters = delimiters
self.escape = escape self.escape = escape
self.literal = literal self.literal = literal
self.load_partial = load_partial self.load_partial = load_partial
def _compile_template_re(self):
self._template_re = _compile_template_re(self._delimiters)
def _change_delimiters(self, delimiters):
self._delimiters = delimiters
self._compile_template_re()
def render(self, template, context):
"""
Return a template rendered as a string with type unicode.
Arguments:
template: a template string of type unicode (but not a proper
subclass of unicode).
context: a Context instance.
"""
# Be strict but not too strict. In other words, accept str instead
# of unicode, but don't assume anything about the encoding (e.g.
# don't use self.literal).
template = unicode(template)
return self._render_template(template=template, context=context)
def _render_template(self, template, context):
"""
Returns: a string of type unicode.
Arguments:
template: template string
context: a Context instance
"""
if type(template) is not unicode:
raise Exception("Argument 'template' not unicode: %s: %s" % (type(template), repr(template)))
parse_tree = self.parse_string_to_tree(template_string=template)
return render_parse_tree(parse_tree, context)
def parse_string_to_tree(self, template_string, delims=None):
engine = RenderEngine(load_partial=self.load_partial,
literal=self.literal, escape=self.escape, delimiters=delims)
engine._compile_template_re()
return engine.parse_to_tree(template=template_string)
def _get_string_value(self, context, tag_name): def _get_string_value(self, context, tag_name):
""" """
Get a value from the given context as a basestring instance. Get a value from the given context as a basestring instance.
...@@ -233,7 +176,7 @@ class RenderEngine(object): ...@@ -233,7 +176,7 @@ class RenderEngine(object):
template = str(template) template = str(template)
if type(template) is not unicode: if type(template) is not unicode:
template = self.literal(template) template = self.literal(template)
val = self._render_template(template, context) val = self._render(template, context)
if not isinstance(val, basestring): if not isinstance(val, basestring):
val = str(val) val = str(val)
...@@ -275,7 +218,7 @@ class RenderEngine(object): ...@@ -275,7 +218,7 @@ class RenderEngine(object):
template = self.load_partial(name) template = self.load_partial(name)
# Indent before rendering. # Indent before rendering.
template = re.sub(self.nonblank_re, indentation + r'\1', template) template = re.sub(self.nonblank_re, indentation + r'\1', template)
return self._render_template(template, context) return self._render(template, context)
return get_partial return get_partial
...@@ -293,7 +236,7 @@ class RenderEngine(object): ...@@ -293,7 +236,7 @@ class RenderEngine(object):
elif callable(data): elif callable(data):
# TODO: should we check the arity? # TODO: should we check the arity?
template = data(template) template = data(template)
parse_tree = self.parse_string_to_tree(template_string=template, delims=delims) parse_tree = self._parse_to_tree(template_string=template, delimiters=delims)
data = [ data ] data = [ data ]
elif type(data) not in [list, tuple]: elif type(data) not in [list, tuple]:
data = [ data ] data = [ data ]
...@@ -308,7 +251,77 @@ class RenderEngine(object): ...@@ -308,7 +251,77 @@ class RenderEngine(object):
return get_section return get_section
def parse_to_tree(self, template, index=0): def _parse_to_tree(self, template_string, delimiters=None):
"""
Parse the given template into a parse tree using a new parser.
"""
parser = _Parser(self, delimiters=delimiters)
parser.compile_template_re()
return parser.parse(template=template_string)
def _render(self, template, context):
"""
Returns: a string of type unicode.
Arguments:
template: template string
context: a Context instance
"""
if type(template) is not unicode:
raise Exception("Argument 'template' not unicode: %s: %s" % (type(template), repr(template)))
parse_tree = self._parse_to_tree(template_string=template)
return render_parse_tree(parse_tree, context)
def render(self, template, context):
"""
Return a template rendered as a string with type unicode.
Arguments:
template: a template string of type unicode (but not a proper
subclass of unicode).
context: a Context instance.
"""
# Be strict but not too strict. In other words, accept str instead
# of unicode, but don't assume anything about the encoding (e.g.
# don't use self.literal).
template = unicode(template)
return self._render(template, context)
class _Parser(object):
_delimiters = None
_template_re = None
def __init__(self, engine, delimiters=None):
"""
Construct an instance.
"""
if delimiters is None:
delimiters = DEFAULT_DELIMITERS
self._delimiters = delimiters
self.engine = engine
def compile_template_re(self):
self._template_re = _compile_template_re(self._delimiters)
def _change_delimiters(self, delimiters):
self._delimiters = delimiters
self.compile_template_re()
def parse(self, template, index=0):
""" """
Parse a template string into a syntax tree using current attributes. Parse a template string into a syntax tree using current attributes.
...@@ -343,11 +356,13 @@ class RenderEngine(object): ...@@ -343,11 +356,13 @@ class RenderEngine(object):
def _handle_match(self, template, parse_tree, matches, start_index, match_index, end_index): def _handle_match(self, template, parse_tree, matches, start_index, match_index, end_index):
engine = self.engine
# Normalize the matches dictionary. # Normalize the matches dictionary.
if matches['change'] is not None: if matches['change'] is not None:
matches.update(tag='=', name=matches['delims']) matches.update(tag='=', name=matches['delims'])
elif matches['raw'] is not None: elif matches['raw'] is not None:
matches.update(tag='{', name=matches['raw_name']) matches.update(tag='&', name=matches['raw_name'])
tag_type = matches['tag'] tag_type = matches['tag']
...@@ -355,7 +370,7 @@ class RenderEngine(object): ...@@ -355,7 +370,7 @@ class RenderEngine(object):
# both leading whitespace and trailing newline. # both leading whitespace and trailing newline.
did_tag_begin_line = match_index == 0 or template[match_index - 1] in END_OF_LINE_CHARACTERS did_tag_begin_line = match_index == 0 or template[match_index - 1] in END_OF_LINE_CHARACTERS
did_tag_end_line = end_index == len(template) or template[end_index] in END_OF_LINE_CHARACTERS did_tag_end_line = end_index == len(template) or template[end_index] in END_OF_LINE_CHARACTERS
is_tag_interpolating = tag_type in ['', '&', '{'] is_tag_interpolating = tag_type in ['', '&']
if did_tag_begin_line and did_tag_end_line and not is_tag_interpolating: if did_tag_begin_line and did_tag_end_line and not is_tag_interpolating:
if end_index < len(template): if end_index < len(template):
...@@ -378,28 +393,28 @@ class RenderEngine(object): ...@@ -378,28 +393,28 @@ class RenderEngine(object):
return end_index return end_index
if tag_type == '>': if tag_type == '>':
func = self._make_get_partial(name, matches['whitespace']) func = engine._make_get_partial(name, matches['whitespace'])
elif tag_type in ['#', '^']: elif tag_type in ['#', '^']:
try: try:
self.parse_to_tree(template=template, index=end_index) self.parse(template=template, index=end_index)
except EndOfSection as e: except EndOfSection as e:
bufr = e.parse_tree bufr = e.parse_tree
tmpl = e.template tmpl = e.template
end_index = e.position end_index = e.position
if tag_type == '#': if tag_type == '#':
func = self._make_get_section(name, bufr, tmpl, self._delimiters) func = engine._make_get_section(name, bufr, tmpl, self._delimiters)
else: else:
func = _make_get_inverse(name, bufr) func = _make_get_inverse(name, bufr)
elif tag_type in ['{', '&']: elif tag_type == '&':
func = self._make_get_literal(name) func = engine._make_get_literal(name)
elif tag_type == '': elif tag_type == '':
func = self._make_get_escaped(name) func = engine._make_get_escaped(name)
elif tag_type == '/': elif tag_type == '/':
......
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