Implement section (and inverted section) filters.
This is a super powerful construct. It's also prolly a violation of the "logic-less-ness" of Mustache templates :(
This commit is contained in:
@@ -178,7 +178,8 @@ class Mustache_Compiler
|
|||||||
|
|
||||||
const SECTION_CALL = '
|
const SECTION_CALL = '
|
||||||
// %s section
|
// %s section
|
||||||
$buffer .= $this->section%s($context, $indent, $context->%s(%s));
|
$value = $context->%s(%s);%s
|
||||||
|
$buffer .= $this->section%s($context, $indent, $value);
|
||||||
';
|
';
|
||||||
|
|
||||||
const SECTION = '
|
const SECTION = '
|
||||||
@@ -216,6 +217,12 @@ class Mustache_Compiler
|
|||||||
*/
|
*/
|
||||||
private function section($nodes, $id, $start, $end, $otag, $ctag, $level)
|
private function section($nodes, $id, $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);
|
$method = $this->getFindMethod($id);
|
||||||
$id = var_export($id, true);
|
$id = var_export($id, true);
|
||||||
$source = var_export(substr($this->source, $start, $end - $start), true);
|
$source = var_export(substr($this->source, $start, $end - $start), true);
|
||||||
@@ -233,12 +240,12 @@ class Mustache_Compiler
|
|||||||
$this->sections[$key] = sprintf($this->prepare(self::SECTION), $key, $callable, $source, $delims, $this->walk($nodes, 2));
|
$this->sections[$key] = sprintf($this->prepare(self::SECTION), $key, $callable, $source, $delims, $this->walk($nodes, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
return sprintf($this->prepare(self::SECTION_CALL, $level), $id, $key, $method, $id);
|
return sprintf($this->prepare(self::SECTION_CALL, $level), $id, $method, $id, $filters, $key);
|
||||||
}
|
}
|
||||||
|
|
||||||
const INVERTED_SECTION = '
|
const INVERTED_SECTION = '
|
||||||
// %s inverted section
|
// %s inverted section
|
||||||
$value = $context->%s(%s);
|
$value = $context->%s(%s);%s
|
||||||
if (empty($value)) {
|
if (empty($value)) {
|
||||||
%s
|
%s
|
||||||
}';
|
}';
|
||||||
@@ -254,10 +261,16 @@ class Mustache_Compiler
|
|||||||
*/
|
*/
|
||||||
private function invertedSection($nodes, $id, $level)
|
private function invertedSection($nodes, $id, $level)
|
||||||
{
|
{
|
||||||
|
$filters = '';
|
||||||
|
|
||||||
|
if (isset($this->pragmas[Mustache_Engine::PRAGMA_FILTERS])) {
|
||||||
|
list($id, $filters) = $this->getFilters($id, $level);
|
||||||
|
}
|
||||||
|
|
||||||
$method = $this->getFindMethod($id);
|
$method = $this->getFindMethod($id);
|
||||||
$id = var_export($id, true);
|
$id = var_export($id, true);
|
||||||
|
|
||||||
return sprintf($this->prepare(self::INVERTED_SECTION, $level), $id, $method, $id, $this->walk($nodes, $level));
|
return sprintf($this->prepare(self::INVERTED_SECTION, $level), $id, $method, $id, $filters, $this->walk($nodes, $level));
|
||||||
}
|
}
|
||||||
|
|
||||||
const PARTIAL = '
|
const PARTIAL = '
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Mustache.php.
|
||||||
|
*
|
||||||
|
* (c) 2013 Justin Hileman
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group filters
|
||||||
|
* @group functional
|
||||||
|
*/
|
||||||
|
class Mustache_Test_FiveThree_Functional_SectionFiltersTest extends PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
private $mustache;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
$this->mustache = new Mustache_Engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSingleFilter()
|
||||||
|
{
|
||||||
|
$tpl = $this->mustache->loadTemplate('{{% FILTERS }}{{# word | echo }}{{ . }}!{{/ word | echo }}');
|
||||||
|
|
||||||
|
$this->mustache->addHelper('echo', function($value) {
|
||||||
|
return array($value, $value, $value);
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->assertEquals('bacon!bacon!bacon!', $tpl->render(array('word' => 'bacon')));
|
||||||
|
}
|
||||||
|
|
||||||
|
const CHAINED_FILTERS_TPL = <<<EOS
|
||||||
|
{{% FILTERS }}
|
||||||
|
{{# word | echo | with_index }}
|
||||||
|
{{ key }}: {{ value }}
|
||||||
|
{{/ word | echo | with_index }}
|
||||||
|
EOS;
|
||||||
|
|
||||||
|
public function testChainedFilters()
|
||||||
|
{
|
||||||
|
$tpl = $this->mustache->loadTemplate(self::CHAINED_FILTERS_TPL);
|
||||||
|
|
||||||
|
$this->mustache->addHelper('echo', function($value) {
|
||||||
|
return array($value, $value, $value);
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->mustache->addHelper('with_index', function($value) {
|
||||||
|
return array_map(function($k, $v) {
|
||||||
|
return array(
|
||||||
|
'key' => $k,
|
||||||
|
'value' => $v,
|
||||||
|
);
|
||||||
|
}, array_keys($value), $value);
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->assertEquals("0: bacon\n1: bacon\n2: bacon\n", $tpl->render(array('word' => 'bacon')));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInterpolateFirst()
|
||||||
|
{
|
||||||
|
$tpl = $this->mustache->loadTemplate('{{% FILTERS }}{{# foo | bar }}{{ . }}{{/ foo | bar }}');
|
||||||
|
$this->assertEquals('win!', $tpl->render(array(
|
||||||
|
'foo' => 'FOO',
|
||||||
|
'bar' => function($value) {
|
||||||
|
return ($value === 'FOO') ? 'win!' : 'fail :(';
|
||||||
|
},
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException Mustache_Exception_UnknownFilterException
|
||||||
|
* @dataProvider getBrokenPipes
|
||||||
|
*/
|
||||||
|
public function testThrowsExceptionForBrokenPipes($tpl, $data)
|
||||||
|
{
|
||||||
|
$this->mustache
|
||||||
|
->loadTemplate(sprintf('{{%% FILTERS }}{{# %s }}{{ . }}{{/ %s }}', $tpl, $tpl))
|
||||||
|
->render($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBrokenPipes()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
array('foo | bar', array()),
|
||||||
|
array('foo | bar', array('foo' => 'FOO')),
|
||||||
|
array('foo | bar', array('foo' => 'FOO', 'bar' => 'BAR')),
|
||||||
|
array('foo | bar', array('foo' => 'FOO', 'bar' => array(1, 2))),
|
||||||
|
array('foo | bar | baz', array('foo' => 'FOO', 'bar' => function() { return 'BAR'; })),
|
||||||
|
array('foo | bar | baz', array('foo' => 'FOO', 'baz' => function() { return 'BAZ'; })),
|
||||||
|
array('foo | bar | baz', array('bar' => function() { return 'BAR'; })),
|
||||||
|
array('foo | bar | baz', array('baz' => function() { return 'BAZ'; })),
|
||||||
|
array('foo | bar.baz', array('foo' => 'FOO', 'bar' => function() { return 'BAR'; }, 'baz' => function() { return 'BAZ'; })),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user