Separate stacks are necessary for blocks to be resolved independently of variables. Renamed parent_* to block_*.
This commit is contained in:
+17
-18
@@ -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 = '
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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 => '}}',
|
||||
|
||||
@@ -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 => '}}',
|
||||
|
||||
Reference in New Issue
Block a user