Separate stacks are necessary for blocks to be resolved independently of variables. Renamed parent_* to block_*.

This commit is contained in:
Dan Miller
2014-04-08 21:02:23 +00:00
parent 63b835bd09
commit af8a62c5e2
8 changed files with 82 additions and 31 deletions
+17 -18
View File
@@ -110,8 +110,8 @@ class Mustache_Compiler
);
break;
case Mustache_Tokenizer::T_PARENT_ARG:
$code .= $this->parentArg(
case Mustache_Tokenizer::T_BLOCK_ARG:
$code .= $this->blockArg(
$node[Mustache_Tokenizer::NODES],
$node[Mustache_Tokenizer::NAME],
$node[Mustache_Tokenizer::INDEX],
@@ -122,8 +122,8 @@ class Mustache_Compiler
);
break;
case Mustache_Tokenizer::T_PARENT_VAR:
$code .= $this->parentVar(
case Mustache_Tokenizer::T_BLOCK_VAR:
$code .= $this->blockVar(
$node[Mustache_Tokenizer::NODES],
$node[Mustache_Tokenizer::NAME],
$node[Mustache_Tokenizer::INDEX],
@@ -154,7 +154,6 @@ class Mustache_Compiler
throw new Mustache_Exception_SyntaxException(sprintf('Unknown token type: %s', $node[Mustache_Tokenizer::TYPE]), $node);
}
}
return $code;
}
@@ -211,7 +210,7 @@ class Mustache_Compiler
return sprintf($this->prepare($klass, 0, false, true), $name, $callable, $code, $sections);
}
const PARENT_VAR = '
const BLOCK_VAR = '
$value = $this->resolveValue($context->%s(%s), $context, $indent);
if($value && !is_array($value) && !is_object($value)) {
$buffer .= %s;
@@ -220,22 +219,22 @@ class Mustache_Compiler
}
';
private function parentVar($nodes, $id, $start, $end, $otag, $ctag, $level)
private function blockVar($nodes, $id, $start, $end, $otag, $ctag, $level)
{
$method = 'findFromParent';
$method = 'findInBlock';
$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));
return sprintf($this->prepare(self::BLOCK_VAR, $level), $method, $id_str, $value, $this->walk($nodes, 2));
}
const PARENT_ARG = '
// %s parent_arg
const BLOCK_ARG = '
// %s block_arg
$value = $this->section%s($context, $indent, true);
$newContext[%s] = %s$value;
';
private function parentArg($nodes, $id, $start, $end, $otag, $ctag, $level)
private function blockArg($nodes, $id, $start, $end, $otag, $ctag, $level)
{
$key = $this->section($nodes, $id, $start, $end, $otag, $ctag, $level, true);
$filters = '';
@@ -247,7 +246,7 @@ class Mustache_Compiler
$method = $this->getFindMethod($id);
$id = var_export($id, true);
return sprintf($this->prepare(self::PARENT_ARG, $level), $key, $key, $id, $this->flushIndent());
return sprintf($this->prepare(self::BLOCK_ARG, $level), $key, $key, $id, $this->flushIndent());
}
const SECTION_CALL = '
@@ -384,9 +383,9 @@ class Mustache_Compiler
const PARENT = '
if ($parent = $this->mustache->LoadPartial(%s)) {
$context->push($newContext);
$context->pushBlockContext($newContext);
$buffer .= $parent->renderInternal($context, $indent);
$context->pop();
$context->popBlockContext();
}
';
@@ -394,7 +393,7 @@ class Mustache_Compiler
{
$block = '';
$real_children = array_filter($children, array(__CLASS__, 'return_only_parent_args'));
$real_children = array_filter($children, array(__CLASS__, 'return_only_block_args'));
$block = $this->walk($real_children, $level);
@@ -405,9 +404,9 @@ class Mustache_Compiler
);
}
private static function return_only_parent_args($child)
private static function return_only_block_args($child)
{
return $child[Mustache_Tokenizer::TYPE] == Mustache_Tokenizer::T_PARENT_ARG;
return $child[Mustache_Tokenizer::TYPE] == Mustache_Tokenizer::T_BLOCK_ARG;
}
const VARIABLE = '
+13 -2
View File
@@ -15,6 +15,7 @@
class Mustache_Context
{
private $stack = array();
private $block_stack = array();
/**
* Mustache rendering Context constructor.
@@ -38,6 +39,11 @@ class Mustache_Context
array_push($this->stack, $value);
}
public function pushBlockContext($value)
{
array_push($this->block_stack, $value);
}
/**
* Pop the last Context frame from the stack.
*
@@ -48,6 +54,11 @@ class Mustache_Context
return array_pop($this->stack);
}
public function popBlockContext()
{
return array_pop($this->block_stack);
}
/**
* Get the last Context frame.
*
@@ -120,9 +131,9 @@ class Mustache_Context
return $value;
}
public function findFromParent($id)
public function findInBlock($id)
{
foreach($this->stack as $context) {
foreach($this->block_stack as $context) {
if (is_array($context) && array_key_exists($id, $context)) {
return $context[$id];
}
+2 -2
View File
@@ -108,9 +108,9 @@ class Mustache_Parser
$nodes[] = $this->buildTree($tokens, $token);
break;
case Mustache_Tokenizer::T_PARENT_VAR:
case Mustache_Tokenizer::T_BLOCK_VAR:
if ($parent[Mustache_Tokenizer::TYPE] == Mustache_Tokenizer::T_PARENT) {
$token[Mustache_Tokenizer::TYPE] = Mustache_Tokenizer::T_PARENT_ARG;
$token[Mustache_Tokenizer::TYPE] = Mustache_Tokenizer::T_BLOCK_ARG;
}
$this->clearStandaloneLines($nodes, $tokens);
$nodes[] = $this->buildTree($tokens, $token);
+4 -1
View File
@@ -61,10 +61,13 @@ abstract class Mustache_Template
* @param mixed $context Array or object rendering context (default: array())
*
* @return string Rendered template
* TODO construct a parent context stack here and pass it in
*/
public function render($context = array())
{
return $this->renderInternal($this->prepareContextStack($context));
return $this->renderInternal(
$this->prepareContextStack($context)
);
}
/**
+3 -3
View File
@@ -35,8 +35,8 @@ class Mustache_Tokenizer
const T_UNESCAPED_2 = '&';
const T_TEXT = '_t';
const T_PRAGMA = '%';
const T_PARENT_VAR = '$';
const T_PARENT_ARG = '$arg';
const T_BLOCK_VAR = '$';
const T_BLOCK_ARG = '$arg';
// Valid token types
private static $tagTypes = array(
@@ -51,7 +51,7 @@ class Mustache_Tokenizer
self::T_UNESCAPED => true,
self::T_UNESCAPED_2 => true,
self::T_PRAGMA => true,
self::T_PARENT_VAR => true,
self::T_BLOCK_VAR => true,
);
// Interpolated tags
@@ -137,6 +137,44 @@ class Mustache_Test_Functional_InheritanceTest extends PHPUnit_Framework_TestCas
$this->assertEquals('test |override1 default| |override2 default|', $tpl->render($data));
}
public function testDataDoesNotOverrideBlock()
{
$partials = array(
'include' => '{{$var}}var in include{{/var}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<include}}{{$var}}var in template{{/var}}{{/include}}'
);
$data = array(
'var' => 'var in data'
);
$this->assertEquals('var in template', $tpl->render($data));
}
public function testDataDoesNotOverrideDefaultBlockValue()
{
$partials = array(
'include' => '{{$var}}var in include{{/var}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<include}}{{/include}}'
);
$data = array(
'var' => 'var in data'
);
$this->assertEquals('var in include', $tpl->render($data));
}
public function testOverridePartialWithNewlines()
{
$partials = array(
+4 -4
View File
@@ -128,7 +128,7 @@ class Mustache_Test_ParserTest extends PHPUnit_Framework_TestCase
Mustache_Tokenizer::INDEX => 8
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_PARENT_VAR,
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_BLOCK_VAR,
Mustache_Tokenizer::NAME => 'bar',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
@@ -168,7 +168,7 @@ class Mustache_Test_ParserTest extends PHPUnit_Framework_TestCase
Mustache_Tokenizer::END => 27,
Mustache_Tokenizer::NODES => array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_PARENT_ARG,
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_BLOCK_ARG,
Mustache_Tokenizer::NAME => 'bar',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
@@ -191,7 +191,7 @@ class Mustache_Test_ParserTest extends PHPUnit_Framework_TestCase
array(
array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_PARENT_VAR,
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_BLOCK_VAR,
Mustache_Tokenizer::NAME => 'foo',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
@@ -213,7 +213,7 @@ class Mustache_Test_ParserTest extends PHPUnit_Framework_TestCase
),
array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_PARENT_VAR,
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_BLOCK_VAR,
Mustache_Tokenizer::NAME => 'foo',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
+1 -1
View File
@@ -195,7 +195,7 @@ class Mustache_Test_TokenizerTest extends PHPUnit_Framework_TestCase
null,
array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_PARENT_VAR,
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_BLOCK_VAR,
Mustache_Tokenizer::NAME => 'arg',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',