mustache / spec

The Mustache spec.
MIT License
364 stars 71 forks source link

Clarification: Context inheritance vs recursive partials #79

Closed estan closed 10 years ago

estan commented 10 years ago

Hi everyone,

Sorry if this has been brought up before.

The spec explicitly states that:

  1. "recursive partials are possible" , and that they also
  2. "inherit the calling context"

But I'm having trouble reconciling the two. If partials inherit the calling context, then why shouldn't the Recursion test case

- name: Recursion
  desc: The greater-than operator should properly recurse.
  data: { content: "X", nodes: [ { content: "Y", nodes: [] } ] }
  template: '{{>node}}'
  partials: { node: '{{content}}<{{#nodes}}{{>node}}{{/nodes}}>' }
  expected: 'X<Y<>>'

lead to infinite recursion? Since nodes is truthy in the context of the first partial application, wouldn't its truthiness be inherited by the context of the second application of the partial, and by the context of the third, and so on and so on?

I'm probably misunderstanding something, and perhaps there's no need for a clarification in the spec, but I would definitely appriciate one here :) I'd like to know what in the spec it is that breaks the recursion.

My goal is to fix the infinite recursion issue that qt-mustache currently suffers from.

Thanks for all the great work on the spec!

groue commented 10 years ago

The value for nodes is an array. So it is not its "truthiness" which is used: instead, the array is iterated, and the section is rendered as many times as there are elements in the array. Each element becomes the "context" while the section is rendered. Consider it this way, and you'll see that there is no infinite recursion. The spec is already clear about the iteration of arrays, so I don't think it needs any further clarification.

estan commented 10 years ago

@groue: Bah. I totally misread the test case. You're right of course.

But just so that I understand this completely: If we were to remove the empty nodes array from the inner "Y" node, so that it would be just

{ content: "X", nodes: [ { content: "Y" } ] }

Then we would get infinite recursion right?

groue commented 10 years ago

Yes, you are absolutely right.

  1. The {{#nodes}} section is rendered with { content: "X", nodes: [ { content: "Y" } ] } as the context. The nodes key evaluates, against this context, to the [ { content: "Y" } ] array. So the content of the section is rendered as many times as there are objects in the array.
  2. The content of the {{#nodes}} section, {{>node}}, is rendered with { content: "Y" } as the context, the first item of the array. The node partial is loaded, the {{content}} tag is rendered as Y, extracted from the context. And then the {{#nodes}} section is rendered with the same { content: "Y" } context. This object does not contain any nodes key. So the Mustache rendering engine has to look up in the context stack for the first context that would provide this nodes key. It's easily found, it is the previous context { content: "X", nodes: [ { content: "Y" } ] }. So we go back to step 1, and here is the infinite recursion.
estan commented 10 years ago

Crystal clear. Thank you very much. Closing this issue.