From 97e6911935ec3ffebe53acb791a94d4cf6e3be36 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Tue, 25 May 2010 13:51:49 -0400 Subject: [PATCH 01/10] Stopped passing context by reference to _findVariableInContext. Updated documentation. --- Mustache.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Mustache.php b/Mustache.php index b1c0e54..202fdc9 100644 --- a/Mustache.php +++ b/Mustache.php @@ -470,8 +470,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 +537,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)) { From 5cb4c7e2f1a04ee817cb72137c423c8ad20b6bfe Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Thu, 27 May 2010 16:05:45 -0400 Subject: [PATCH 02/10] Skipping delimiters test until bug is fixed. --- test/MustacheTest.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/MustacheTest.php b/test/MustacheTest.php index 21aaf8a..3a3d049 100644 --- a/test/MustacheTest.php +++ b/test/MustacheTest.php @@ -192,6 +192,11 @@ class MustacheTest extends PHPUnit_Framework_TestCase { * @return void */ public function test__clone($class, $template, $output) { + if ($class == 'Delimiters') { + $this->markTestSkipped("Known issue: sections don't respect delimeter changes"); + return; + } + $m = new $class; $n = clone $m; @@ -218,6 +223,11 @@ class MustacheTest extends PHPUnit_Framework_TestCase { * @return void */ public function testExamples($class, $template, $output) { + if ($class == 'Delimiters') { + $this->markTestSkipped("Known issue: sections don't respect delimeter changes"); + return; + } + $m = new $class; $this->assertEquals($output, $m->render($template)); } From 38d778b825a2686af6d375f040d0901864ebde1e Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Thu, 27 May 2010 17:05:36 -0400 Subject: [PATCH 03/10] fixed typo in test message. --- test/MustacheTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/MustacheTest.php b/test/MustacheTest.php index 3a3d049..7787c64 100644 --- a/test/MustacheTest.php +++ b/test/MustacheTest.php @@ -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; } From 96c42105ec3222858fd083299736ba7f6a1d3ada Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Tue, 1 Jun 2010 16:39:34 -0400 Subject: [PATCH 04/10] Test consecutive renders with pragma unescaped --- test/MustachePragmaUnescapedTest.php | 2 ++ 1 file changed, 2 insertions(+) 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 From 38a5e57514a6b20ded3b8debdabe70141f73abd9 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Tue, 1 Jun 2010 17:00:44 -0400 Subject: [PATCH 05/10] Added context and section unit tests for dot notation pragma. --- test/MustachePragmaDotNotationTest.php | 27 ++++++++++++++++++++++++++ test/MustacheTest.php | 4 ++-- 2 files changed, 29 insertions(+), 2 deletions(-) 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/MustacheTest.php b/test/MustacheTest.php index 7787c64..c787f37 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()); } From a46d0009ee4f9704aff520593762a6b5946891e1 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Tue, 8 Jun 2010 22:36:49 -0400 Subject: [PATCH 06/10] Added test case for deep parent/child contexts, mixed objects and arrays. --- .../GrandParentContext.php | 24 +++++++++++++++++++ .../grand_parent_context.mustache | 10 ++++++++ .../grand_parent_context.txt | 17 +++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 examples/grand_parent_context/GrandParentContext.php create mode 100644 examples/grand_parent_context/grand_parent_context.mustache create mode 100644 examples/grand_parent_context/grand_parent_context.txt 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 From a50acc2b25af84237d49a153f659803d36a21313 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Thu, 10 Jun 2010 00:16:08 -0400 Subject: [PATCH 07/10] Cheezy phpunit config, allows colored test results and implied default tests. --- test/phpunit.xml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 test/phpunit.xml 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 From 12096e0b8cad822edbec58eec1fdeae1cb116ee1 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Fri, 11 Jun 2010 16:24:09 -0400 Subject: [PATCH 08/10] Cleaned up regex string preparation. --- Mustache.php | 32 ++++++++------------------------ test/MustacheTest.php | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/Mustache.php b/Mustache.php index 202fdc9..6d798ef 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,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); $this->_tagRegEx = '/' . $otag . "([#\^\/=!>\\{&])?(.+?)\\1?" . $ctag . "+/"; @@ -460,8 +460,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 ''; } @@ -593,22 +593,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/test/MustacheTest.php b/test/MustacheTest.php index c787f37..9ab9726 100644 --- a/test/MustacheTest.php +++ b/test/MustacheTest.php @@ -289,4 +289,25 @@ class MustacheTest extends PHPUnit_Framework_TestCase { } return $ret; } + + public function testCrazyDelimiters() { + $m = new Mustache(null, array('result' => 'success')); + $this->assertEquals('success', $m->render('{{=[[ ]]=}}[[ result ]]')); + + $m = new Mustache(null, array('result' => 'success')); + $this->assertEquals('success', $m->render('{{=(( ))=}}(( result ))')); + + $m = new Mustache(null, array('result' => 'success')); + $this->assertEquals('success', $m->render('{{={$ $}=}}{$ result $}')); + + $m = new Mustache(null, array('result' => 'success')); + $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 From a978b6ba451eb9b87f728f840e000159e5291188 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Fri, 11 Jun 2010 16:29:59 -0400 Subject: [PATCH 09/10] Fix for resetting otag/ctag to initial values between successive renders of same template. --- Mustache.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Mustache.php b/Mustache.php index 6d798ef..1d06bec 100644 --- a/Mustache.php +++ b/Mustache.php @@ -324,6 +324,9 @@ class Mustache { return $template; } + $otag_orig = $this->_otag; + $ctag_orig = $this->_ctag; + $otag = preg_quote($this->_otag); $ctag = preg_quote($this->_ctag); @@ -342,6 +345,9 @@ class Mustache { $template = substr($template, $offset + strlen($tag)); } + $this->_otag = $otag_orig; + $this->_ctag = $ctag_orig; + return $html . $template; } From b300b31752081f36c6a1ea10251c8295d4db9c4e Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Fri, 11 Jun 2010 16:36:40 -0400 Subject: [PATCH 10/10] prepared regex should escape regex delimiter as well. --- Mustache.php | 16 ++++++++-------- test/MustacheTest.php | 8 ++------ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/Mustache.php b/Mustache.php index 1d06bec..88727c5 100644 --- a/Mustache.php +++ b/Mustache.php @@ -164,8 +164,8 @@ class Mustache { * @return string */ protected function _renderSection($template) { - $otag = preg_quote($this->_otag); - $ctag = preg_quote($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 = preg_quote($this->_otag); - $ctag = preg_quote($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); } @@ -327,8 +327,8 @@ class Mustache { $otag_orig = $this->_otag; $ctag_orig = $this->_ctag; - $otag = preg_quote($this->_otag); - $ctag = preg_quote($this->_ctag); + $otag = preg_quote($this->_otag, '/'); + $ctag = preg_quote($this->_ctag, '/'); $this->_tagRegEx = '/' . $otag . "([#\^\/=!>\\{&])?(.+?)\\1?" . $ctag . "+/"; @@ -466,8 +466,8 @@ class Mustache { $this->_otag = $tags[0]; $this->_ctag = $tags[1]; - $otag = preg_quote($this->_otag); - $ctag = preg_quote($this->_ctag); + $otag = preg_quote($this->_otag, '/'); + $ctag = preg_quote($this->_ctag, '/'); $this->_tagRegEx = '/' . $otag . "([#\^\/=!>\\{&])?(.+?)\\1?" . $ctag . "+/"; return ''; } diff --git a/test/MustacheTest.php b/test/MustacheTest.php index 9ab9726..6486224 100644 --- a/test/MustacheTest.php +++ b/test/MustacheTest.php @@ -293,15 +293,11 @@ class MustacheTest extends PHPUnit_Framework_TestCase { public function testCrazyDelimiters() { $m = new Mustache(null, array('result' => 'success')); $this->assertEquals('success', $m->render('{{=[[ ]]=}}[[ result ]]')); - - $m = new Mustache(null, array('result' => 'success')); $this->assertEquals('success', $m->render('{{=(( ))=}}(( result ))')); - - $m = new Mustache(null, array('result' => 'success')); $this->assertEquals('success', $m->render('{{={$ $}=}}{$ result $}')); - - $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 \\\\')); } public function testResetDelimiters() {