diff --git a/src/Mustache/Compiler.php b/src/Mustache/Compiler.php index b0c49cb..7d5c96b 100644 --- a/src/Mustache/Compiler.php +++ b/src/Mustache/Compiler.php @@ -631,6 +631,12 @@ class Mustache_Compiler return 'last'; } + if (isset($this->pragmas[Mustache_Engine::PRAGMA_ANCHORED_DOT]) && $this->pragmas[Mustache_Engine::PRAGMA_ANCHORED_DOT]) { + if (substr($id, 0, 1) === '.') { + return 'findAnchoredDot'; + } + } + if (strpos($id, '.') === false) { return 'find'; } diff --git a/src/Mustache/Context.php b/src/Mustache/Context.php index 9243239..e660b54 100644 --- a/src/Mustache/Context.php +++ b/src/Mustache/Context.php @@ -128,13 +128,44 @@ class Mustache_Context { $chunks = explode('.', $id); $first = array_shift($chunks); + $value = $this->findVariableInStack($first, $this->stack); - if ($first === '') { - $value = $this->last(); - } else { - $value = $this->findVariableInStack($first, $this->stack); + foreach ($chunks as $chunk) { + if ($value === '') { + return $value; + } + + $value = $this->findVariableInStack($chunk, array($value)); } + return $value; + } + + /** + * Find an 'anchored dot notation' variable in the Context stack. + * + * This is the same as findDot(), except it looks in the top of the context + * stack for the first value, rather than searching the whole context stack + * and starting from there. + * + * @see Mustache_Context::findDot + * + * @throws Mustache_Exception_InvalidArgumentException if given an invalid anchored dot $id. + * + * @param string $id Dotted variable selector + * + * @return mixed Variable value, or '' if not found + */ + public function findAnchoredDot($id) + { + $chunks = explode('.', $id); + $first = array_shift($chunks); + if ($first !== '') { + throw new Mustache_Exception_InvalidArgumentException(sprintf('Unexpected id for findAnchoredDot: %s', $id)); + } + + $value = $this->last(); + foreach ($chunks as $chunk) { if ($value === '') { return $value; diff --git a/src/Mustache/Engine.php b/src/Mustache/Engine.php index 20ef798..d40a3af 100644 --- a/src/Mustache/Engine.php +++ b/src/Mustache/Engine.php @@ -26,13 +26,15 @@ class Mustache_Engine const VERSION = '2.8.0'; const SPEC_VERSION = '1.1.2'; - const PRAGMA_FILTERS = 'FILTERS'; - const PRAGMA_BLOCKS = 'BLOCKS'; + const PRAGMA_FILTERS = 'FILTERS'; + const PRAGMA_BLOCKS = 'BLOCKS'; + const PRAGMA_ANCHORED_DOT = 'ANCHORED-DOT'; // Known pragmas private static $knownPragmas = array( - self::PRAGMA_FILTERS => true, - self::PRAGMA_BLOCKS => true, + self::PRAGMA_FILTERS => true, + self::PRAGMA_BLOCKS => true, + self::PRAGMA_ANCHORED_DOT => true, ); // Template cache diff --git a/test/Mustache/Test/ContextTest.php b/test/Mustache/Test/ContextTest.php index 7145d40..5d700fd 100644 --- a/test/Mustache/Test/ContextTest.php +++ b/test/Mustache/Test/ContextTest.php @@ -142,25 +142,43 @@ class Mustache_Test_ContextTest extends PHPUnit_Framework_TestCase $context->push($a); $this->assertEquals('a', $context->find('name')); - $this->assertEquals('a', $context->findDot('.name')); + $this->assertEquals('', $context->findDot('.name')); + $this->assertEquals('a', $context->findAnchoredDot('.name')); $this->assertEquals(1, $context->find('number')); - $this->assertEquals(1, $context->findDot('.number')); + $this->assertEquals('', $context->findDot('.number')); + $this->assertEquals(1, $context->findAnchoredDot('.number')); $context->push($b); $this->assertEquals('a', $context->find('name')); $this->assertEquals(2, $context->find('number')); $this->assertEquals('', $context->findDot('.name')); - $this->assertEquals(2, $context->findDot('.number')); + $this->assertEquals('', $context->findDot('.number')); + $this->assertEquals('', $context->findAnchoredDot('.name')); + $this->assertEquals(2, $context->findAnchoredDot('.number')); $this->assertEquals('baby bee', $context->findDot('child.name')); - $this->assertEquals('baby bee', $context->findDot('.child.name')); + $this->assertEquals('', $context->findDot('.child.name')); + $this->assertEquals('baby bee', $context->findAnchoredDot('.child.name')); $context->push($c); $this->assertEquals('cee', $context->find('name')); - $this->assertEquals('cee', $context->findDot('.name')); + $this->assertEquals('', $context->findDot('.name')); + $this->assertEquals('cee', $context->findAnchoredDot('.name')); $this->assertEquals(2, $context->find('number')); $this->assertEquals('', $context->findDot('.number')); + $this->assertEquals('', $context->findAnchoredDot('.number')); $this->assertEquals('baby bee', $context->findDot('child.name')); $this->assertEquals('', $context->findDot('.child.name')); + $this->assertEquals('', $context->findAnchoredDot('.child.name')); + } + + /** + * @expectedException Mustache_Exception_InvalidArgumentException + */ + public function testAnchoredDotNotationThrowsExceptions() + { + $context = new Mustache_Context(); + $context->push(array('a' => 1)); + $context->findAnchoredDot('a'); } }