hogan.js style template inheritance

This commit is contained in:
Dan Miller
2014-04-04 18:41:24 +00:00
parent 6fa8518a9a
commit db14a6c863
8 changed files with 614 additions and 8 deletions
+124 -3
View File
@@ -17,6 +17,7 @@
class Mustache_Compiler class Mustache_Compiler
{ {
private $pragmas;
private $sections; private $sections;
private $source; private $source;
private $indentNextLine; private $indentNextLine;
@@ -24,7 +25,6 @@ class Mustache_Compiler
private $entityFlags; private $entityFlags;
private $charset; private $charset;
private $strictCallables; private $strictCallables;
private $pragmas;
/** /**
* Compile a Mustache token parse tree into PHP source code. * Compile a Mustache token parse tree into PHP source code.
@@ -94,7 +94,6 @@ class Mustache_Compiler
break; break;
case Mustache_Tokenizer::T_PARTIAL: case Mustache_Tokenizer::T_PARTIAL:
case Mustache_Tokenizer::T_PARTIAL_2:
$code .= $this->partial( $code .= $this->partial(
$node[Mustache_Tokenizer::NAME], $node[Mustache_Tokenizer::NAME],
isset($node[Mustache_Tokenizer::INDENT]) ? $node[Mustache_Tokenizer::INDENT] : '', isset($node[Mustache_Tokenizer::INDENT]) ? $node[Mustache_Tokenizer::INDENT] : '',
@@ -102,6 +101,39 @@ class Mustache_Compiler
); );
break; break;
case Mustache_Tokenizer::T_PARENT:
$code .= $this->parent(
$node[Mustache_Tokenizer::NAME],
isset($node[Mustache_Tokenizer::INDENT]) ? $node[Mustache_Tokenizer::INDENT] : '',
$level,
$node['nodes']
);
break;
case Mustache_Tokenizer::T_PARENT_ARG:
$code .= $this->parentArg(
$node[Mustache_Tokenizer::NODES],
$node[Mustache_Tokenizer::NAME],
$node[Mustache_Tokenizer::INDEX],
$node[Mustache_Tokenizer::END],
$node[Mustache_Tokenizer::OTAG],
$node[Mustache_Tokenizer::CTAG],
$level
);
break;
case Mustache_Tokenizer::T_PARENT_VAR:
$code .= $this->parentVar(
$node[Mustache_Tokenizer::NODES],
$node[Mustache_Tokenizer::NAME],
$node[Mustache_Tokenizer::INDEX],
$node[Mustache_Tokenizer::END],
$node[Mustache_Tokenizer::OTAG],
$node[Mustache_Tokenizer::CTAG],
$level
);
break;
case Mustache_Tokenizer::T_UNESCAPED: case Mustache_Tokenizer::T_UNESCAPED:
case Mustache_Tokenizer::T_UNESCAPED_2: case Mustache_Tokenizer::T_UNESCAPED_2:
$code .= $this->variable($node[Mustache_Tokenizer::NAME], false, $level); $code .= $this->variable($node[Mustache_Tokenizer::NAME], false, $level);
@@ -136,6 +168,7 @@ class Mustache_Compiler
{ {
$this->lambdaHelper = new Mustache_LambdaHelper($this->mustache, $context); $this->lambdaHelper = new Mustache_LambdaHelper($this->mustache, $context);
$buffer = \'\'; $buffer = \'\';
$new_context = array();
%s %s
return $buffer; return $buffer;
@@ -150,6 +183,7 @@ class Mustache_Compiler
public function renderInternal(Mustache_Context $context, $indent = \'\') public function renderInternal(Mustache_Context $context, $indent = \'\')
{ {
$buffer = \'\'; $buffer = \'\';
$new_context = array();
%s %s
return $buffer; return $buffer;
@@ -171,11 +205,71 @@ class Mustache_Compiler
$code = $this->walk($tree); $code = $this->walk($tree);
$sections = implode("\n", $this->sections); $sections = implode("\n", $this->sections);
$klass = empty($this->sections) ? self::KLASS_NO_LAMBDAS : self::KLASS; $klass = empty($this->sections) ? self::KLASS_NO_LAMBDAS : self::KLASS;
$callable = $this->strictCallables ? $this->prepare(self::STRICT_CALLABLE) : ''; $callable = $this->strictCallables ? $this->prepare(self::STRICT_CALLABLE) : '';
return sprintf($this->prepare($klass, 0, false, true), $name, $callable, $code, $sections); return sprintf($this->prepare($klass, 0, false, true), $name, $callable, $code, $sections);
} }
const PARENT_VAR = '
$value = $this->resolveValue($context->%s(%s), $context, $indent);
if($value && !is_array($value) && !is_object($value)) {
$buffer .= %s;
} else {
%s
}
';
private function parentVar($nodes, $id, $start, $end, $otag, $ctag, $level)
{
$method = 'findFromParent';
$id_str = var_export($id, true);
$value = $this->getEscape();
return sprintf($this->prepare(self::PARENT_VAR, $level), $method, $id_str, $value, $this->walk($nodes, 2));
}
function parentArgSection($nodes, $start, $end, $otag, $ctag, $level)
{
$source = var_export(substr($this->source, $start, $end - $start), true);
$callable = $this->getCallable();
if ($otag !== '{{' || $ctag !== '}}') {
$delims = ', '.var_export(sprintf('{{= %s %s =}}', $otag, $ctag), true);
} else {
$delims = '';
}
$key = ucfirst(md5($delims."\n".$source));
if (!isset($this->sections[$key])) {
$this->sections[$key] = sprintf($this->prepare(self::SECTION), $key, $callable, $source, $delims, $this->walk($nodes, 2));
}
return $key;
}
const PARENT_ARG = '
// %s parent_arg
$value = $this->section%s($context, $indent, true);
$new_context[%s] = %s$value;
';
private function parentArg($nodes, $id, $start, $end, $otag, $ctag, $level)
{
$key = $this->parentArgSection($nodes, $start, $end, $otag, $ctag, $level);
$filters = '';
if (isset($this->pragmas[Mustache_Engine::PRAGMA_FILTERS])) {
list($id, $filters) = $this->getFilters($id, $level);
}
$method = $this->getFindMethod($id);
$id = var_export($id, true);
return sprintf($this->prepare(self::PARENT_ARG, $level), $key, $key, $id, $this->flushIndent());
}
const SECTION_CALL = ' const SECTION_CALL = '
// %s section // %s section
$value = $context->%s(%s);%s $value = $context->%s(%s);%s
@@ -199,7 +293,8 @@ class Mustache_Compiler
} elseif (!empty($value)) { } elseif (!empty($value)) {
$values = $this->isIterable($value) ? $value : array($value); $values = $this->isIterable($value) ? $value : array($value);
foreach ($values as $value) { foreach ($values as $value) {
$context->push($value);%s $context->push($value);
%s
$context->pop(); $context->pop();
} }
} }
@@ -302,6 +397,32 @@ class Mustache_Compiler
); );
} }
const PARENT = '
if ($parent = $this->mustache->LoadPartial(%s)) {
$context->push($new_context);
$buffer .= $parent->renderInternal($context, $indent);
$context->pop();
}
';
private function parent($id, $indent, $level, $children)
{
$block = '';
$real_children = array_filter($children, function($ch) {
return $ch[Mustache_Tokenizer::TYPE] == Mustache_Tokenizer::T_PARENT_ARG;
});
$block = $this->walk($real_children, $level);
return $block. sprintf(
$this->prepare(self::PARENT, $level),
var_export($id, true),
var_export($indent, true)
);
}
const VARIABLE = ' const VARIABLE = '
$value = $this->resolveValue($context->%s(%s), $context, $indent);%s $value = $this->resolveValue($context->%s(%s), $context, $indent);%s
$buffer .= %s%s; $buffer .= %s%s;
+12
View File
@@ -120,6 +120,18 @@ class Mustache_Context
return $value; return $value;
} }
public function findFromParent($id)
{
$stack = $this->stack;
foreach($stack as $context) {
if (is_array($context) && array_key_exists($id, $context)) {
return $context[$id];
}
}
return '';
}
/** /**
* Helper function to find a variable in the Context stack. * Helper function to find a variable in the Context stack.
* *
+13 -3
View File
@@ -95,17 +95,27 @@ class Mustache_Parser
$parent[Mustache_Tokenizer::NODES] = $nodes; $parent[Mustache_Tokenizer::NODES] = $nodes;
return $parent; return $parent;
break;
case Mustache_Tokenizer::T_PARTIAL: case Mustache_Tokenizer::T_PARTIAL:
case Mustache_Tokenizer::T_PARTIAL_2: //store the whitespace prefix for laters!
// store the whitespace prefix for laters!
if ($indent = $this->clearStandaloneLines($nodes, $tokens)) { if ($indent = $this->clearStandaloneLines($nodes, $tokens)) {
$token[Mustache_Tokenizer::INDENT] = $indent[Mustache_Tokenizer::VALUE]; $token[Mustache_Tokenizer::INDENT] = $indent[Mustache_Tokenizer::VALUE];
} }
$nodes[] = $token; $nodes[] = $token;
break; break;
case Mustache_Tokenizer::T_PARENT:
$nodes[] = $this->buildTree($tokens, $token);
break;
case Mustache_Tokenizer::T_PARENT_VAR:
if ($parent[Mustache_Tokenizer::TYPE] == Mustache_Tokenizer::T_PARENT) {
$token[Mustache_Tokenizer::TYPE] = Mustache_Tokenizer::T_PARENT_ARG;
}
$this->clearStandaloneLines($nodes, $tokens);
$nodes[] = $this->buildTree($tokens, $token);
break;
case Mustache_Tokenizer::T_PRAGMA: case Mustache_Tokenizer::T_PRAGMA:
case Mustache_Tokenizer::T_COMMENT: case Mustache_Tokenizer::T_COMMENT:
$this->clearStandaloneLines($nodes, $tokens); $this->clearStandaloneLines($nodes, $tokens);
+5 -2
View File
@@ -28,13 +28,15 @@ class Mustache_Tokenizer
const T_END_SECTION = '/'; const T_END_SECTION = '/';
const T_COMMENT = '!'; const T_COMMENT = '!';
const T_PARTIAL = '>'; const T_PARTIAL = '>';
const T_PARTIAL_2 = '<'; const T_PARENT = '<';
const T_DELIM_CHANGE = '='; const T_DELIM_CHANGE = '=';
const T_ESCAPED = '_v'; const T_ESCAPED = '_v';
const T_UNESCAPED = '{'; const T_UNESCAPED = '{';
const T_UNESCAPED_2 = '&'; const T_UNESCAPED_2 = '&';
const T_TEXT = '_t'; const T_TEXT = '_t';
const T_PRAGMA = '%'; const T_PRAGMA = '%';
const T_PARENT_VAR = '$';
const T_PARENT_ARG = '$arg';
// Valid token types // Valid token types
private static $tagTypes = array( private static $tagTypes = array(
@@ -43,12 +45,13 @@ class Mustache_Tokenizer
self::T_END_SECTION => true, self::T_END_SECTION => true,
self::T_COMMENT => true, self::T_COMMENT => true,
self::T_PARTIAL => true, self::T_PARTIAL => true,
self::T_PARTIAL_2 => true, self::T_PARENT => true,
self::T_DELIM_CHANGE => true, self::T_DELIM_CHANGE => true,
self::T_ESCAPED => true, self::T_ESCAPED => true,
self::T_UNESCAPED => true, self::T_UNESCAPED => true,
self::T_UNESCAPED_2 => true, self::T_UNESCAPED_2 => true,
self::T_PRAGMA => true, self::T_PRAGMA => true,
self::T_PARENT_VAR => true,
); );
// Interpolated tags // Interpolated tags
@@ -0,0 +1,303 @@
<?php
/**
* @group inheritance
* @group functional
*/
class Mustache_Test_Functional_InheritanceTest extends PHPUnit_Framework_TestCase
{
private $mustache;
public function setUp()
{
$this->mustache = new Mustache_Engine;
}
public function testDefaultContent()
{
$tpl = $this->mustache->loadTemplate('{{$title}}Default title{{/title}}');
$data = array();
$this->assertEquals('Default title', $tpl->render($data));
}
public function testDefaultContentRendersVariables()
{
$tpl = $this->mustache->loadTemplate('{{$foo}}default {{bar}} content{{/foo}}');
$data = array(
'bar' => 'baz'
);
$this->assertEquals('default baz content', $tpl->render($data));
}
public function testDefaultContentRendersTripleMustacheVariables()
{
$tpl = $this->mustache->loadTemplate('{{$foo}}default {{{bar}}} content{{/foo}}');
$data = array(
'bar' => '<baz>'
);
$this->assertEquals('default <baz> content', $tpl->render($data));
}
public function testDefaultContentRendersSections()
{
$tpl = $this->mustache->loadTemplate(
'{{$foo}}default {{#bar}}{{baz}}{{/bar}} content{{/foo}}'
);
$data = array(
'bar' => array('baz' => 'qux')
);
$this->assertEquals('default qux content', $tpl->render($data));
}
public function testDefaultContentRendersNegativeSections()
{
$tpl = $this->mustache->loadTemplate(
'{{$foo}}default {{^bar}}{{baz}}{{/bar}} content{{/foo}}'
);
$data = array(
'foo' => array('bar' => 'qux'),
'baz' => 'three'
);
$this->assertEquals('default three content', $tpl->render($data));
}
public function testMustacheInjectionInDefaultContent()
{
$tpl = $this->mustache->loadTemplate(
'{{$foo}}default {{#bar}}{{baz}}{{/bar}} content{{/foo}}'
);
$data = array(
'bar' => array('baz' => '{{qux}}')
);
$this->assertEquals('default {{qux}} content', $tpl->render($data));
}
public function testDefaultContentRenderedInsideIncludedTemplates()
{
$partials = array(
'include' => '{{$foo}}default content{{/foo}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<include}}{{/include}}'
);
$data = array();
$this->assertEquals('default content', $tpl->render($data));
}
public function testOverriddenContent()
{
$partials = array(
'super' => '...{{$title}}Default title{{/title}}...'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<super}}{{$title}}sub template title{{/title}}{{/super}}'
);
$data = array();
$this->assertEquals('...sub template title...', $tpl->render($data));
}
public function testOverriddenPartial()
{
$partials = array(
'partial' => '|{{$stuff}}...{{/stuff}}{{$default}} default{{/default}}|'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'test {{<partial}}{{$stuff}}override1{{/stuff}}{{/partial}} {{<partial}}{{$stuff}}override2{{/stuff}}{{/partial}}'
);
$data = array();
$this->assertEquals('test |override1 default| |override2 default|', $tpl->render($data));
}
public function testOverridePartialWithNewlines()
{
$partials = array(
'partial' => '{{$ballmer}}peaking{{/ballmer}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
"{{<partial}}{{\$ballmer}}\npeaked\n\n:(\n{{/ballmer}}{{/partial}}"
);
$data = array();
$this->assertEquals("peaked\n\n:(\n", $tpl->render($data));
}
public function testInheritIndentationWhenOverridingAPartial()
{
$partials = array(
'partial' =>
'stop:
{{$nineties}}collaborate and listen{{/nineties}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<partial}}{{$nineties}}hammer time{{/nineties}}{{/partial}}'
);
$data = array();
$this->assertEquals(
'stop:
hammer time',
$tpl->render($data)
);
}
public function testOverrideOneSubstitutionButNotTheOther()
{
$partials = array(
'partial' => '{{$stuff}}default one{{/stuff}}, {{$stuff2}}default two{{/stuff2}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<partial}}{{$stuff2}}override two{{/stuff2}}{{/partial}}'
);
$data = array();
$this->assertEquals('default one, override two', $tpl->render($data));
}
public function testSuperTemplatesWithNoParameters()
{
$partials = array(
'include' => '{{$foo}}default content{{/foo}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{>include}}|{{<include}}{{/include}}'
);
$data = array();
$this->assertEquals('default content|default content', $tpl->render($data));
}
public function testRecursionInInheritedTemplates()
{
$partials = array(
'include' => '{{$foo}}default content{{/foo}} {{$bar}}{{<include2}}{{/include2}}{{/bar}}',
'include2' => '{{$foo}}include2 default content{{/foo}} {{<include}}{{$bar}}don\'t recurse{{/bar}}{{/include}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<include}}{{$foo}}override{{/foo}}{{/include}}'
);
$data = array();
$this->assertEquals('override override override don\'t recurse', $tpl->render($data));
}
public function testTopLevelSubstitutionsTakePrecedenceInMultilevelInheritance()
{
$partials = array(
'parent' => '{{<older}}{{$a}}p{{/a}}{{/older}}',
'older' => '{{<grandParent}}{{$a}}o{{/a}}{{/grandParent}}',
'grandParent' => '{{$a}}g{{/a}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<parent}}{{$a}}c{{/a}}{{/parent}}'
);
$data = array();
$this->assertEquals('c', $tpl->render($data));
}
public function testMultiLevelInheritanceNoSubChild()
{
$partials = array(
'parent' => '{{<older}}{{$a}}p{{/a}}{{/older}}',
'older' => '{{<grandParent}}{{$a}}o{{/a}}{{/grandParent}}',
'grandParent' => '{{$a}}g{{/a}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<parent}}{{/parent}}'
);
$data = array();
$this->assertEquals('p', $tpl->render($data));
}
public function testIgnoreTextInsideSuperTemplatesButParseArgs()
{
$partials = array(
'include' => '{{$foo}}default content{{/foo}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<include}} asdfasd {{$foo}}hmm{{/foo}} asdfasdfasdf {{/include}}'
);
$data = array();
$this->assertEquals('hmm', $tpl->render($data));
}
public function IgnoreTextInsideSuperTemplates()
{
$partials = array(
'include' => '{{$foo}}default content{{/foo}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<include}} asdfasd asdfasdfasdf {{/include}}'
);
$data = array();
$this->assertEquals('default content', $tpl->render($data));
}
}
@@ -127,6 +127,21 @@ class Mustache_Test_Functional_MustacheSpecTest extends PHPUnit_Framework_TestCa
return $this->loadSpec('sections'); return $this->loadSpec('sections');
} }
/**
* @group inheritance
* @dataProvider loadInheritanceSpec
*/
public function testInheritanceSpec($desc, $source, $partials, $data, $expected)
{
$template = self::loadTemplate($source, $partials);
$this->assertEquals($expected, $template->render($data), $desc);
}
public function loadInheritanceSpec()
{
return $this->loadSpec('inheritance');
}
/** /**
* Data provider for the mustache spec test. * Data provider for the mustache spec test.
* *
+113
View File
@@ -88,6 +88,7 @@ class Mustache_Test_ParserTest extends PHPUnit_Framework_TestCase
Mustache_Tokenizer::VALUE => 'bar' Mustache_Tokenizer::VALUE => 'bar'
), ),
), ),
array( array(
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
@@ -116,6 +117,118 @@ class Mustache_Test_ParserTest extends PHPUnit_Framework_TestCase
), ),
), ),
array(
array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_PARENT,
Mustache_Tokenizer::NAME => 'foo',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::INDEX => 8
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_PARENT_VAR,
Mustache_Tokenizer::NAME => 'bar',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::INDEX => 16
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::VALUE => 'baz'
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_END_SECTION,
Mustache_Tokenizer::NAME => 'bar',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::INDEX => 19
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_END_SECTION,
Mustache_Tokenizer::NAME => 'foo',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::INDEX => 27
)
),
array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_PARENT,
Mustache_Tokenizer::NAME => 'foo',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::INDEX => 8,
Mustache_Tokenizer::END => 27,
Mustache_Tokenizer::NODES => array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_PARENT_ARG,
Mustache_Tokenizer::NAME => 'bar',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::INDEX => 16,
Mustache_Tokenizer::END => 19,
Mustache_Tokenizer::NODES => array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::VALUE => 'baz'
)
)
)
)
)
)
),
array(
array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_PARENT_VAR,
Mustache_Tokenizer::NAME => 'foo',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::VALUE => 'bar'
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_END_SECTION,
Mustache_Tokenizer::NAME => 'foo',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::INDEX => 11,
),
),
array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_PARENT_VAR,
Mustache_Tokenizer::NAME => 'foo',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::END => 11,
Mustache_Tokenizer::NODES => array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::VALUE => 'bar'
)
)
)
)
)
); );
} }
+29
View File
@@ -188,6 +188,35 @@ class Mustache_Test_TokenizerTest extends PHPUnit_Framework_TestCase
), ),
) )
), ),
// Ensure that $arg token is not picked up during tokenization
array(
'{{$arg}}default{{/arg}}',
null,
array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_PARENT_VAR,
Mustache_Tokenizer::NAME => 'arg',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::INDEX => 8
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::VALUE => "default",
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_END_SECTION,
Mustache_Tokenizer::NAME => 'arg',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::INDEX => 15,
)
)
),
); );
} }
} }