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
@@ -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');
}
/**
* @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.
*
+113
View File
@@ -88,6 +88,7 @@ class Mustache_Test_ParserTest extends PHPUnit_Framework_TestCase
Mustache_Tokenizer::VALUE => 'bar'
),
),
array(
array(
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,
)
)
),
);
}
}