| Index: third_party/handlebar/handlebar.py
|
| diff --git a/third_party/handlebar/handlebar.py b/third_party/handlebar/handlebar.py
|
| index f35764f4b8277cbc663739079d375ea886d753bd..7e06868e19380cfdcc4faa8c49f4620e4c0a5d1d 100644
|
| --- a/third_party/handlebar/handlebar.py
|
| +++ b/third_party/handlebar/handlebar.py
|
| @@ -155,6 +155,11 @@ class _Contexts(object):
|
| # [0] is the stack of nodes that |found_key| has been found in.
|
| self._value_info[found_key][0].pop()
|
|
|
| + def FirstLocal(self):
|
| + if len(self._nodes) == self._first_local:
|
| + return None
|
| + return self._nodes[-1]._value
|
| +
|
| def Resolve(self, path):
|
| # This method is only efficient at finding |key|; if |tail| has a value (and
|
| # |key| evaluates to an indexable value) we'll need to descend into that.
|
| @@ -643,6 +648,45 @@ class _JsonNode(_LeafNode):
|
| def __repr__(self):
|
| return '{{*%s}}' % self._id
|
|
|
| +# TODO: Better common model of _PartialNodeWithArguments, _PartialNodeInContext,
|
| +# and _PartialNode.
|
| +class _PartialNodeWithArguments(_DecoratorNode):
|
| + def __init__(self, partial, args):
|
| + if isinstance(partial, Handlebar):
|
| + # Preserve any get() method that the caller has added.
|
| + if hasattr(partial, 'get'):
|
| + self.get = partial.get
|
| + partial = partial._top_node
|
| + _DecoratorNode.__init__(self, partial)
|
| + self._partial = partial
|
| + self._args = args
|
| +
|
| + def Render(self, render_state):
|
| + render_state.contexts.Scope(self._args, self._partial.Render, render_state)
|
| +
|
| +class _PartialNodeInContext(_DecoratorNode):
|
| + def __init__(self, partial, context):
|
| + if isinstance(partial, Handlebar):
|
| + # Preserve any get() method that the caller has added.
|
| + if hasattr(partial, 'get'):
|
| + self.get = partial.get
|
| + partial = partial._top_node
|
| + _DecoratorNode.__init__(self, partial)
|
| + self._partial = partial
|
| + self._context = context
|
| +
|
| + def Render(self, render_state):
|
| + original_contexts = render_state.contexts
|
| + try:
|
| + render_state.contexts = self._context
|
| + render_state.contexts.Scope(
|
| + # The first local context of |original_contexts| will be the
|
| + # arguments that were passed to the partial, if any.
|
| + original_contexts.FirstLocal() or {},
|
| + self._partial.Render, render_state)
|
| + finally:
|
| + render_state.contexts = original_contexts
|
| +
|
| class _PartialNode(_LeafNode):
|
| '''{{+var:foo}} ... {{/foo}}
|
| '''
|
| @@ -651,7 +695,6 @@ class _PartialNode(_LeafNode):
|
| self._bind_to = bind_to
|
| self._id = id_
|
| self._content = content
|
| - self._resolved_args = None
|
| self._args = None
|
| self._pass_through_id = None
|
|
|
| @@ -680,20 +723,17 @@ class _PartialNode(_LeafNode):
|
| context = render_state.contexts.Resolve(self._pass_through_id.name)
|
| if context is not None:
|
| arg_context[self._pass_through_id.name] = context
|
| - if self._resolved_args is not None:
|
| - arg_context.update(self._resolved_args)
|
| if self._args is not None:
|
| def resolve_args(args):
|
| resolved = {}
|
| for key, value in args.iteritems():
|
| if isinstance(value, dict):
|
| assert len(value.keys()) == 1
|
| - inner_id, inner_args = value.items()[0]
|
| - inner_partial = render_state.contexts.Resolve(inner_id.name)
|
| - if inner_partial is not None:
|
| - context = _PartialNode(None, inner_id, inner_partial)
|
| - context.SetResolvedArguments(resolve_args(inner_args))
|
| - resolved[key] = context
|
| + id_of_partial, partial_args = value.items()[0]
|
| + partial = render_state.contexts.Resolve(id_of_partial.name)
|
| + if partial is not None:
|
| + resolved[key] = _PartialNodeWithArguments(
|
| + partial, resolve_args(partial_args))
|
| else:
|
| context = render_state.contexts.Resolve(value.name)
|
| if context is not None:
|
| @@ -701,7 +741,8 @@ class _PartialNode(_LeafNode):
|
| return resolved
|
| arg_context.update(resolve_args(self._args))
|
| if self._bind_to and self._content:
|
| - arg_context[self._bind_to.name] = self._content
|
| + arg_context[self._bind_to.name] = _PartialNodeInContext(
|
| + self._content, render_state.contexts)
|
| if arg_context:
|
| partial_render_state.contexts.Push(arg_context)
|
|
|
| @@ -711,9 +752,6 @@ class _PartialNode(_LeafNode):
|
| partial_render_state,
|
| text_transform=lambda text: text[:-1] if text.endswith('\n') else text)
|
|
|
| - def SetResolvedArguments(self, args):
|
| - self._resolved_args = args
|
| -
|
| def SetArguments(self, args):
|
| self._args = args
|
|
|
| @@ -1092,10 +1130,14 @@ class Handlebar(object):
|
| '''Renders this template given a variable number of contexts to read out
|
| values from (such as those appearing in {{foo}}).
|
| '''
|
| - name = self._name or '<root>'
|
| internal_context = _InternalContext()
|
| - render_state = _RenderState(
|
| - name, _Contexts([{'_': internal_context}] + list(user_contexts)))
|
| + contexts = list(user_contexts)
|
| + contexts.append({
|
| + '_': internal_context,
|
| + 'false': False,
|
| + 'true': True,
|
| + })
|
| + render_state = _RenderState(self._name or '<root>', _Contexts(contexts))
|
| internal_context.SetRenderState(render_state)
|
| self._top_node.Render(render_state)
|
| return render_state.GetResult()
|
|
|