diff --git a/Mustache.php b/Mustache.php index b1c0e54..88727c5 100644 --- a/Mustache.php +++ b/Mustache.php @@ -164,8 +164,8 @@ class Mustache { * @return string */ protected function _renderSection($template) { - $otag = $this->_prepareRegEx($this->_otag); - $ctag = $this->_prepareRegEx($this->_ctag); + $otag = preg_quote($this->_otag, '/'); + $ctag = preg_quote($this->_ctag, '/'); $regex = '/' . $otag . '(\\^|\\#)\\s*(.+?)\\s*' . $ctag . '\\s*([\\s\\S]+?)' . $otag . '\\/\\s*\\2\\s*' . $ctag . '\\s*/m'; $matches = array(); @@ -227,8 +227,8 @@ class Mustache { return $template; } - $otag = $this->_prepareRegEx($this->_otag); - $ctag = $this->_prepareRegEx($this->_ctag); + $otag = preg_quote($this->_otag, '/'); + $ctag = preg_quote($this->_ctag, '/'); $regex = '/' . $otag . '%\\s*([\\w_-]+)((?: [\\w]+=[\\w]+)*)\\s*' . $ctag . '\\n?/'; return preg_replace_callback($regex, array($this, '_renderPragma'), $template); } @@ -324,8 +324,11 @@ class Mustache { return $template; } - $otag = $this->_prepareRegEx($this->_otag); - $ctag = $this->_prepareRegEx($this->_ctag); + $otag_orig = $this->_otag; + $ctag_orig = $this->_ctag; + + $otag = preg_quote($this->_otag, '/'); + $ctag = preg_quote($this->_ctag, '/'); $this->_tagRegEx = '/' . $otag . "([#\^\/=!>\\{&])?(.+?)\\1?" . $ctag . "+/"; @@ -342,6 +345,9 @@ class Mustache { $template = substr($template, $offset + strlen($tag)); } + $this->_otag = $otag_orig; + $this->_ctag = $ctag_orig; + return $html . $template; } @@ -460,8 +466,8 @@ class Mustache { $this->_otag = $tags[0]; $this->_ctag = $tags[1]; - $otag = $this->_prepareRegEx($this->_otag); - $ctag = $this->_prepareRegEx($this->_ctag); + $otag = preg_quote($this->_otag, '/'); + $ctag = preg_quote($this->_ctag, '/'); $this->_tagRegEx = '/' . $otag . "([#\^\/=!>\\{&])?(.+?)\\1?" . $ctag . "+/"; return ''; } @@ -470,8 +476,8 @@ class Mustache { * Push a local context onto the stack. * * @access protected - * @param array $local_context - * @return array + * @param array &$local_context + * @return void */ protected function _pushContext(&$local_context) { $new = array(); @@ -537,11 +543,11 @@ class Mustache { * * @access protected * @param string $tag_name - * @param array &$context + * @param array $context * @throws MustacheException Unknown variable name. * @return string */ - protected function _findVariableInContext($tag_name, &$context) { + protected function _findVariableInContext($tag_name, $context) { foreach ($context as $view) { if (is_object($view)) { if (isset($view->$tag_name)) { @@ -593,22 +599,6 @@ class Mustache { protected function _varIsIterable($var) { return is_object($var) || (is_array($var) && !array_diff_key($var, array_keys(array_keys($var)))); } - - /** - * Prepare a string to be used in a regular expression. - * - * @access protected - * @param string $str - * @return string - */ - protected function _prepareRegEx($str) { - $replace = array( - '\\' => '\\\\', '^' => '\^', '.' => '\.', '$' => '\$', '|' => '\|', '(' => '\(', - ')' => '\)', '[' => '\[', ']' => '\]', '*' => '\*', '+' => '\+', '?' => '\?', - '{' => '\{', '}' => '\}', ',' => '\,' - ); - return strtr($str, $replace); - } } diff --git a/examples/grand_parent_context/GrandParentContext.php b/examples/grand_parent_context/GrandParentContext.php new file mode 100644 index 0000000..5a59ed9 --- /dev/null +++ b/examples/grand_parent_context/GrandParentContext.php @@ -0,0 +1,24 @@ +parent_contexts[] = array('parent_id' => 'parent1', 'child_contexts' => array( + array('child_id' => 'parent1-child1'), + array('child_id' => 'parent1-child2') + )); + + $parent2 = new stdClass(); + $parent2->parent_id = 'parent2'; + $parent2->child_contexts = array( + array('child_id' => 'parent2-child1'), + array('child_id' => 'parent2-child2') + ); + + $this->parent_contexts[] = $parent2; + } +} \ No newline at end of file diff --git a/examples/grand_parent_context/grand_parent_context.mustache b/examples/grand_parent_context/grand_parent_context.mustache new file mode 100644 index 0000000..e6c07a2 --- /dev/null +++ b/examples/grand_parent_context/grand_parent_context.mustache @@ -0,0 +1,10 @@ +{{grand_parent_id}} +{{#parent_contexts}} +{{grand_parent_id}} +{{parent_id}} +{{#child_contexts}} +{{grand_parent_id}} +{{parent_id}} +{{child_id}} +{{/child_contexts}} +{{/parent_contexts}} diff --git a/examples/grand_parent_context/grand_parent_context.txt b/examples/grand_parent_context/grand_parent_context.txt new file mode 100644 index 0000000..64996ad --- /dev/null +++ b/examples/grand_parent_context/grand_parent_context.txt @@ -0,0 +1,17 @@ +grand_parent1 +grand_parent1 +parent1 +grand_parent1 +parent1 +parent1-child1 +grand_parent1 +parent1 +parent1-child2 +grand_parent1 +parent2 +grand_parent1 +parent2 +parent2-child1 +grand_parent1 +parent2 +parent2-child2 diff --git a/test/MustachePragmaDotNotationTest.php b/test/MustachePragmaDotNotationTest.php index d6d31b7..65195b6 100644 --- a/test/MustachePragmaDotNotationTest.php +++ b/test/MustachePragmaDotNotationTest.php @@ -31,4 +31,31 @@ class MustachePragmaDotNotationTest extends PHPUnit_Framework_TestCase { $this->assertEquals($m->render('{{%DOT-NOTATION}}{{one.one}}|{{one.two}}|{{one.three}}'), 'one-one|one-two|one-three'); } + public function testDotNotationContext() { + $data = array('parent' => array('items' => array( + array('item' => array('index' => 1)), + array('item' => array('index' => 2)), + array('item' => array('index' => 3)), + array('item' => array('index' => 4)), + array('item' => array('index' => 5)), + ))); + + $m = new Mustache('', $data); + $this->assertEquals('12345', $m->render('{{%DOT-NOTATION}}{{#parent}}{{#items}}{{item.index}}{{/items}}{{/parent}}')); + } + + public function testDotNotationSectionNames() { + $data = array('parent' => array('items' => array( + array('item' => array('index' => 1)), + array('item' => array('index' => 2)), + array('item' => array('index' => 3)), + array('item' => array('index' => 4)), + array('item' => array('index' => 5)), + ))); + + $m = new Mustache('', $data); + $this->assertEquals('.....', $m->render('{{%DOT-NOTATION}}{{#parent.items}}.{{/parent.items}}')); + $this->assertEquals('12345', $m->render('{{%DOT-NOTATION}}{{#parent.items}}{{item.index}}{{/parent.items}}')); + $this->assertEquals('12345', $m->render('{{%DOT-NOTATION}}{{#parent.items}}{{#item}}{{index}}{{/item}}{{/parent.items}}')); + } } \ No newline at end of file diff --git a/test/MustachePragmaUnescapedTest.php b/test/MustachePragmaUnescapedTest.php index 559eeab..4c0d83b 100644 --- a/test/MustachePragmaUnescapedTest.php +++ b/test/MustachePragmaUnescapedTest.php @@ -9,7 +9,9 @@ class MustachePragmaUnescapedTest extends PHPUnit_Framework_TestCase { $m = new Mustache(null, array('title' => 'Bear > Shark')); $this->assertEquals('Bear > Shark', $m->render('{{%UNESCAPED}}{{title}}')); + $this->assertEquals('Bear > Shark', $m->render('{{title}}')); $this->assertEquals('Bear > Shark', $m->render('{{%UNESCAPED}}{{{title}}}')); + $this->assertEquals('Bear > Shark', $m->render('{{{title}}}')); } } \ No newline at end of file diff --git a/test/MustacheTest.php b/test/MustacheTest.php index 3a3d049..6486224 100644 --- a/test/MustacheTest.php +++ b/test/MustacheTest.php @@ -176,11 +176,11 @@ class MustacheTest extends PHPUnit_Framework_TestCase { */ public function testResetTemplateForMultipleInvocations() { $m = new Mustache('Sirve.'); - $m->render('No sirve.'); + $this->assertEquals('No sirve.', $m->render('No sirve.')); $this->assertEquals('Sirve.', $m->render()); $m2 = new Mustache(); - $m2->render('No sirve.'); + $this->assertEquals('No sirve.', $m2->render('No sirve.')); $this->assertEquals('', $m2->render()); } @@ -193,7 +193,7 @@ class MustacheTest extends PHPUnit_Framework_TestCase { */ public function test__clone($class, $template, $output) { if ($class == 'Delimiters') { - $this->markTestSkipped("Known issue: sections don't respect delimeter changes"); + $this->markTestSkipped("Known issue: sections don't respect delimiter changes"); return; } @@ -224,7 +224,7 @@ class MustacheTest extends PHPUnit_Framework_TestCase { */ public function testExamples($class, $template, $output) { if ($class == 'Delimiters') { - $this->markTestSkipped("Known issue: sections don't respect delimeter changes"); + $this->markTestSkipped("Known issue: sections don't respect delimiter changes"); return; } @@ -289,4 +289,21 @@ class MustacheTest extends PHPUnit_Framework_TestCase { } return $ret; } + + public function testCrazyDelimiters() { + $m = new Mustache(null, array('result' => 'success')); + $this->assertEquals('success', $m->render('{{=[[ ]]=}}[[ result ]]')); + $this->assertEquals('success', $m->render('{{=(( ))=}}(( result ))')); + $this->assertEquals('success', $m->render('{{={$ $}=}}{$ result $}')); + $this->assertEquals('success', $m->render('{{=<.. ..>=}}<.. result ..>')); + $this->assertEquals('success', $m->render('{{=^^ ^^}}^^ result ^^')); + $this->assertEquals('success', $m->render('{{=// \\\\}}// result \\\\')); + } + + public function testResetDelimiters() { + $m = new Mustache(null, array('result' => 'success')); + $this->assertEquals('success', $m->render('{{=[[ ]]=}}[[ result ]]')); + $this->assertEquals('success', $m->render('{{=<< >>=}}<< result >>')); + $this->assertEquals('success', $m->render('{{=<% %>=}}<% result %>')); + } } \ No newline at end of file diff --git a/test/phpunit.xml b/test/phpunit.xml new file mode 100644 index 0000000..c70e6b0 --- /dev/null +++ b/test/phpunit.xml @@ -0,0 +1,6 @@ + + + + ./ + + \ No newline at end of file