Skip to content

Commit

Permalink
Add block functions to the template, so they can be evaluated lazily.
Browse files Browse the repository at this point in the history
Fixes #264
  • Loading branch information
Damyon Wiese committed Jul 17, 2015
1 parent 11ad87a commit ceb2267
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 10 deletions.
48 changes: 38 additions & 10 deletions src/Mustache/Compiler.php
Expand Up @@ -19,6 +19,7 @@ class Mustache_Compiler
private $pragmas;
private $defaultPragmas = array();
private $sections;
private $blocks;
private $source;
private $indentNextLine;
private $customEscape;
Expand All @@ -43,6 +44,7 @@ public function compile($source, array $tree, $name, $customEscape = false, $cha
{
$this->pragmas = $this->defaultPragmas;
$this->sections = array();
$this->blocks = array();
$this->source = $source;
$this->indentNextLine = true;
$this->customEscape = $customEscape;
Expand Down Expand Up @@ -195,6 +197,7 @@ public function renderInternal(Mustache_Context $context, $indent = \'\')
return $buffer;
}
%s
%s
}';

const KLASS_NO_LAMBDAS = '<?php
Expand Down Expand Up @@ -225,18 +228,18 @@ private function writeCode($tree, $name)
{
$code = $this->walk($tree);
$sections = implode("\n", $this->sections);
$klass = empty($this->sections) ? self::KLASS_NO_LAMBDAS : self::KLASS;
$blocks = implode("\n", $this->blocks);
$klass = empty($this->sections) && empty($this->blocks) ? self::KLASS_NO_LAMBDAS : self::KLASS;

$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, $blocks);
}

const BLOCK_VAR = '
$blockFunction = $context->findInBlock(%s);
if (is_callable($blockFunction)) {
$boundFunction = $blockFunction->bindTo($this, $this);
$boundFunction($context, $buffer);
$buffer .= call_user_func($blockFunction, $context);
} else {
%s
}
Expand Down Expand Up @@ -264,12 +267,37 @@ private function blockVar($nodes, $id, $start, $end, $otag, $ctag, $level)

const BLOCK_ARG = '
// %s block_arg
$blockFunction = function(& $context, & $buffer, $indent=\'\') {
%s
};
$newContext[%s] = $blockFunction;
$blockid = %s;
$newContext[%s] = array($this, \'block\' . $blockid);
';

const BLOCK_FUNCTION = 'public function block%s($context) {
$indent = $buffer = \'\';
%s
return $buffer;
}';

/**
* Generate Mustache Template inheritance block function PHP source.
*
* @param array $nodes Array of child tokens
*
* @return string key of new block function
*/
private function block($nodes)
{
$code = $this->walk($nodes, 1);

$key = ucfirst(md5($code));

if (!isset($this->blocks[$key])) {
$this->blocks[$key] = sprintf($this->prepare(self::BLOCK_FUNCTION, 1), $key, $code);
}
return $key;
}

/**
* Generate Mustache Template inheritance block argument PHP source.
*
Expand All @@ -285,10 +313,10 @@ private function blockVar($nodes, $id, $start, $end, $otag, $ctag, $level)
*/
private function blockArg($nodes, $id, $start, $end, $otag, $ctag, $level)
{
$key = var_export($this->block($nodes), true);
$id = var_export($id, true);
$code = $this->walk($nodes, 1);

return sprintf($this->prepare(self::BLOCK_ARG, 1), $id, $code, $id);
return sprintf($this->prepare(self::BLOCK_ARG, 1), $key, $key, $id);
}

const SECTION_CALL = '
Expand Down
17 changes: 17 additions & 0 deletions test/Mustache/Test/Functional/InheritanceTest.php
Expand Up @@ -467,6 +467,23 @@ public function testInheritanceWithLazyEvaluationWhitespaceIgnored()
$this->assertEquals('<1><2><3>', $tpl->render($data));
}

public function testInheritanceWithLazyEvaluationAndSections()
{
$partials = array(
'parent' => '{{#items}}{{$value}}\n\nignored {{.}} {{#more}} there is more {{/more}}\n\n{{/value}}{{/items}}',
);

$this->mustache->setPartials($partials);

$tpl = $this->mustache->loadTemplate(
'{{<parent}}\n\n\n{{$value}}<{{ . }}>{{#more}} there is less {{/more}}{{/value}}\n\n{{/parent}}'
);

$data = array('items' => array(1, 2, 3), 'more' => 'stuff');

$this->assertEquals('<1> there is less <2> there is less <3> there is less ', $tpl->render($data));
}

/**
* @dataProvider getIllegalInheritanceExamples
* @expectedException Mustache_Exception_SyntaxException
Expand Down

0 comments on commit ceb2267

Please sign in to comment.