From f4ef3ba30e15661c35a40149956a5bdfda262e56 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Sun, 16 May 2010 15:08:21 -0400 Subject: [PATCH 01/16] Added test case for multiple (trivial) invocations of Mustache::render --- test/MustacheTest.php | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/MustacheTest.php b/test/MustacheTest.php index f4d9672..06e1874 100644 --- a/test/MustacheTest.php +++ b/test/MustacheTest.php @@ -137,6 +137,36 @@ class MustacheTest extends PHPUnit_Framework_TestCase { $this->assertEquals('Zappa, Frank', $m->render('{{last_name}}, {{first_name}}', array('first_name' => 'Frank', 'last_name' => 'Zappa'))); } + /** + * Mustache should return the same thing when invoked multiple times. + * + * @access public + * @return void + */ + public function testMultipleInvocations() { + $m = new Mustache('x'); + $first = $m->render(); + $second = $m->render(); + + $this->assertEquals('x', $first); + $this->assertEquals($first, $second); + } + + /** + * Mustache should return the same thing when invoked multiple times. + * + * @access public + * @return void + */ + public function testMultipleInvocationsWithTags() { + $m = new Mustache('{{one}} {{two}}', array('one' => 'foo', 'two' => 'bar')); + $first = $m->render(); + $second = $m->render(); + + $this->assertEquals('foo bar', $first); + $this->assertEquals($first, $second); + } + /** * Test everything in the `examples` directory. * From 9e803ed03336f0873f4d75ca320c5a52d8c51814 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Tue, 18 May 2010 10:28:01 -0400 Subject: [PATCH 02/16] Fix for stripping leading/trailing whitespace from partial names, per http://github.com/janl/mustache.js/issues/issue/34/#comment_244396 --- Mustache.php | 2 +- examples/whitespace/Whitespace.php | 37 +++++++++++++++++++++++++ examples/whitespace/whitespace.mustache | 10 +++++++ examples/whitespace/whitespace.txt | 12 ++++++++ 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 examples/whitespace/Whitespace.php create mode 100644 examples/whitespace/whitespace.mustache create mode 100644 examples/whitespace/whitespace.txt diff --git a/Mustache.php b/Mustache.php index 85dae70..36c0a87 100644 --- a/Mustache.php +++ b/Mustache.php @@ -144,7 +144,7 @@ class Mustache { protected function _renderSection($template, &$context) { $otag = $this->_prepareRegEx($this->_otag); $ctag = $this->_prepareRegEx($this->_ctag); - $regex = '/' . $otag . '(\\^|\\#)(.+?)' . $ctag . '\\s*([\\s\\S]+?)' . $otag . '\\/\\2' . $ctag . '\\s*/m'; + $regex = '/' . $otag . '(\\^|\\#)\\s*(.+?)\\s*' . $ctag . '\\s*([\\s\\S]+?)' . $otag . '\\/\\s*\\2\\s*' . $ctag . '\\s*/m'; $matches = array(); while (preg_match($regex, $template, $matches, PREG_OFFSET_CAPTURE)) { diff --git a/examples/whitespace/Whitespace.php b/examples/whitespace/Whitespace.php new file mode 100644 index 0000000..3be9689 --- /dev/null +++ b/examples/whitespace/Whitespace.php @@ -0,0 +1,37 @@ + tag }}` and `{{> tag}}` and `{{>tag}}` should all be equivalent. + * + * @extends Mustache + */ +class Whitespace extends Mustache { + public $foo = 'alpha'; + + public $bar = 'beta'; + + public function baz() { + return 'gamma'; + } + + public function qux() { + return array( + array('key with space' => 'A'), + array('key with space' => 'B'), + array('key with space' => 'C'), + array('key with space' => 'D'), + array('key with space' => 'E'), + array('key with space' => 'F'), + array('key with space' => 'G'), + ); + } + + protected $_partials = array( + 'alphabet' => " * {{.}}\n", + ); +} \ No newline at end of file diff --git a/examples/whitespace/whitespace.mustache b/examples/whitespace/whitespace.mustache new file mode 100644 index 0000000..0b3ba00 --- /dev/null +++ b/examples/whitespace/whitespace.mustache @@ -0,0 +1,10 @@ +{{^ inverted section test }} +These are some things: +{{/inverted section test }} +* {{ foo }} +* {{ bar}} +* {{ baz }} +{{# qux }} +* {{ key with space }} +{{/ qux }} +{{#qux}}.{{/qux}} \ No newline at end of file diff --git a/examples/whitespace/whitespace.txt b/examples/whitespace/whitespace.txt new file mode 100644 index 0000000..5226c69 --- /dev/null +++ b/examples/whitespace/whitespace.txt @@ -0,0 +1,12 @@ +These are some things: +* alpha +* beta +* gamma +* A +* B +* C +* D +* E +* F +* G +....... \ No newline at end of file From eeb5b245d13341f567c9b9dcebe2b2814083b4b4 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Sat, 22 May 2010 18:34:24 -0400 Subject: [PATCH 03/16] Possible fix for #1 - ability to use partials with an arbitrary (non-Mustache) view class. --- Mustache.php | 48 ++----------------- .../PartialsWithViewClass.php | 19 ++++++++ .../partials_with_view_class.mustache | 2 + .../partials_with_view_class.txt | 3 ++ 4 files changed, 28 insertions(+), 44 deletions(-) create mode 100644 examples/partials_with_view_class/PartialsWithViewClass.php create mode 100644 examples/partials_with_view_class/partials_with_view_class.mustache create mode 100644 examples/partials_with_view_class/partials_with_view_class.txt diff --git a/Mustache.php b/Mustache.php index e15438a..19229af 100644 --- a/Mustache.php +++ b/Mustache.php @@ -424,10 +424,10 @@ class Mustache { * @return string */ protected function _renderPartial($tag_name, &$context) { - $view = new self($this->_getPartial($tag_name), $this->_flattenContext($context), $this->_partials); - $view->_otag = $this->_otag; - $view->_ctag = $this->_ctag; - return $view->render(); + $view = clone($this); + $view->_otag = '{{'; + $view->_ctag = '}}'; + return $view->render($this->_getPartial($tag_name)); } /** @@ -450,7 +450,6 @@ class Mustache { return ''; } - /** * Prepare a new context reference array. * @@ -470,45 +469,6 @@ class Mustache { return $ret; } - - /** - * Prepare a new (flattened) context. - * - * This is used to create a view object or array for rendering partials. - * - * @access protected - * @param array &$context - * @return array - * @throws MustacheException - */ - protected function _flattenContext(&$context) { - $keys = array_keys($context); - $first = $context[$keys[0]]; - - if ($first instanceof Mustache) { - $ret = clone $first; - unset($keys[0]); - - foreach ($keys as $name) { - foreach ($context[$name] as $key => $val) { - $ret->$key =& $val; - } - } - } else if (is_array($first)) { - $ret = array(); - - foreach ($keys as $name) { - foreach ($context[$name] as $key => $val) { - $ret[$key] =& $val; - } - } - } else { - throw new MustacheException('Unknown root context type.'); - } - - return $ret; - } - /** * Get a variable from the context array. * diff --git a/examples/partials_with_view_class/PartialsWithViewClass.php b/examples/partials_with_view_class/PartialsWithViewClass.php new file mode 100644 index 0000000..56e0d86 --- /dev/null +++ b/examples/partials_with_view_class/PartialsWithViewClass.php @@ -0,0 +1,19 @@ +name = 'ilmich'; + $view->data = array( + array('name' => 'federica', 'age' => 27, 'gender' => 'female'), + array('name' => 'marco', 'age' => 32, 'gender' => 'male'), + ); + + $partials = array( + 'children' => "{{#data}}{{name}} - {{age}} - {{gender}}\n{{/data}}", + ); + + parent::__construct($template, $view, $partials); + } +} \ No newline at end of file diff --git a/examples/partials_with_view_class/partials_with_view_class.mustache b/examples/partials_with_view_class/partials_with_view_class.mustache new file mode 100644 index 0000000..037e1b3 --- /dev/null +++ b/examples/partials_with_view_class/partials_with_view_class.mustache @@ -0,0 +1,2 @@ +Children of {{name}}: +{{>children}} \ No newline at end of file diff --git a/examples/partials_with_view_class/partials_with_view_class.txt b/examples/partials_with_view_class/partials_with_view_class.txt new file mode 100644 index 0000000..d967e15 --- /dev/null +++ b/examples/partials_with_view_class/partials_with_view_class.txt @@ -0,0 +1,3 @@ +Children of ilmich: +federica - 27 - female +marco - 32 - male From 7f5f7a73fc26faa72aa07199ceb7dd655de3dd7a Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Sat, 22 May 2010 19:24:49 -0400 Subject: [PATCH 04/16] Stop passing context arrays around like a madman. --- Mustache.php | 144 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 86 insertions(+), 58 deletions(-) diff --git a/Mustache.php b/Mustache.php index 19229af..09a3cf1 100644 --- a/Mustache.php +++ b/Mustache.php @@ -59,6 +59,8 @@ class Mustache { self::PRAGMA_UNESCAPED ); + protected $_localPragmas; + /** * Mustache class constructor. * @@ -77,6 +79,27 @@ class Mustache { if ($view !== null) $this->_context = array($view); } + /** + * Mustache class clone method. + * + * A cloned Mustache instance should have pragmas, delimeters and root context + * reset to default values. + * + * @access public + * @return void + */ + public function __clone() { + $this->_otag = '{{'; + $this->_ctag = '}}'; + $this->_localPragmas = null; + + if ($keys = array_keys($this->_context)) { + if ($this->_context[$keys[0]] instanceof Mustache) { + $this->_context[$keys[0]] =& $this; + } + } + } + /** * Render the given template and view object. * @@ -124,13 +147,12 @@ class Mustache { * * @access protected * @param string $template - * @param array &$context * @return string Rendered Mustache template. */ - protected function _renderTemplate($template, &$context) { - $template = $this->_renderPragmas($template, $context); - $template = $this->_renderSection($template, $context); - return $this->_renderTags($template, $context); + protected function _renderTemplate($template) { + $template = $this->_renderPragmas($template); + $template = $this->_renderSection($template); + return $this->_renderTags($template); } /** @@ -138,10 +160,9 @@ class Mustache { * * @access protected * @param string $template - * @param array $context * @return string */ - protected function _renderSection($template, &$context) { + protected function _renderSection($template) { $otag = $this->_prepareRegEx($this->_otag); $ctag = $this->_prepareRegEx($this->_ctag); $regex = '/' . $otag . '(\\^|\\#)\\s*(.+?)\\s*' . $ctag . '\\s*([\\s\\S]+?)' . $otag . '\\/\\s*\\2\\s*' . $ctag . '\\s*/m'; @@ -155,7 +176,7 @@ class Mustache { $content = $matches[3][0]; $replace = ''; - $val = $this->_getVariable($tag_name, $context); + $val = $this->_getVariable($tag_name); switch($type) { // inverted section case '^': @@ -168,13 +189,15 @@ class Mustache { case '#': if ($this->_varIsIterable($val)) { foreach ($val as $local_context) { - $c = $this->_getContext($context, $local_context); - $replace .= $this->_renderTemplate($content, $c); + $this->_pushContext($local_context); + $replace .= $this->_renderTemplate($content); + $this->_popContext(); } } else if ($val) { if (is_array($val) || is_object($val)) { - $c = $this->_getContext($context, $val); - $replace .= $this->_renderTemplate($content, $c); + $this->_pushContext($val); + $replace .= $this->_renderTemplate($content); + $this->_popContext(); } else { $replace .= $content; } @@ -193,10 +216,11 @@ class Mustache { * * @access protected * @param string $template - * @param array &$context * @return string */ - protected function _renderPragmas($template, &$context) { + protected function _renderPragmas($template) { + $this->_localPragmas = $this->_pragmas; + // no pragmas if (strpos($template, $this->_otag . '%') === false) { return $template; @@ -234,9 +258,9 @@ class Mustache { } if (empty($options)) { - $this->_pragmas[$pragma_name] = true; + $this->_localPragmas[$pragma_name] = true; } else { - $this->_pragmas[$pragma_name] = $options; + $this->_localPragmas[$pragma_name] = $options; } return ''; @@ -250,7 +274,7 @@ class Mustache { * @return bool */ protected function _hasPragma($pragma_name) { - if (array_key_exists($pragma_name, $this->_pragmas) && $this->_pragmas[$pragma_name]) { + if (array_key_exists($pragma_name, $this->_localPragmas) && $this->_localPragmas[$pragma_name]) { return true; } else { return false; @@ -270,7 +294,7 @@ class Mustache { throw new MustacheException('Unknown pragma: ' . $pragma_name, MustacheException::UNKNOWN_PRAGMA); } - return $this->_pragmas[$pragma_name]; + return $this->_localPragmas[$pragma_name]; } @@ -292,10 +316,9 @@ class Mustache { * * @access protected * @param string $template - * @param array $context * @return void */ - protected function _renderTags($template, &$context) { + protected function _renderTags($template) { if (strpos($template, $this->_otag) === false) { return $template; } @@ -314,7 +337,7 @@ class Mustache { $tag_name = trim($matches[2][0]); $html .= substr($template, 0, $offset); - $html .= $this->_renderTag($modifier, $tag_name, $context); + $html .= $this->_renderTag($modifier, $tag_name); $template = substr($template, $offset + strlen($tag)); } @@ -330,11 +353,10 @@ class Mustache { * @access protected * @param string $modifier * @param string $tag_name - * @param array $context * @throws MustacheException Unmatched section tag encountered. * @return string */ - protected function _renderTag($modifier, $tag_name, &$context) { + protected function _renderTag($modifier, $tag_name) { switch ($modifier) { case '#': case '^': @@ -352,28 +374,28 @@ class Mustache { } break; case '=': - return $this->_changeDelimiter($tag_name, $context); + return $this->_changeDelimiter($tag_name); break; case '!': - return $this->_renderComment($tag_name, $context); + return $this->_renderComment($tag_name); break; case '>': - return $this->_renderPartial($tag_name, $context); + return $this->_renderPartial($tag_name); break; case '{': case '&': if ($this->_hasPragma(self::PRAGMA_UNESCAPED)) { - return $this->_renderEscaped($tag_name, $context); + return $this->_renderEscaped($tag_name); } else { - return $this->_renderUnescaped($tag_name, $context); + return $this->_renderUnescaped($tag_name); } break; case '': default: if ($this->_hasPragma(self::PRAGMA_UNESCAPED)) { - return $this->_renderUnescaped($tag_name, $context); + return $this->_renderUnescaped($tag_name); } else { - return $this->_renderEscaped($tag_name, $context); + return $this->_renderEscaped($tag_name); } break; } @@ -384,11 +406,10 @@ class Mustache { * * @access protected * @param string $tag_name - * @param array $context * @return string */ - protected function _renderEscaped($tag_name, &$context) { - return htmlentities($this->_getVariable($tag_name, $context), null, $this->_charset); + protected function _renderEscaped($tag_name) { + return htmlentities($this->_getVariable($tag_name), null, $this->_charset); } /** @@ -396,10 +417,9 @@ class Mustache { * * @access protected * @param string $tag_name - * @param array $context * @return string */ - protected function _renderComment($tag_name, &$context) { + protected function _renderComment($tag_name) { return ''; } @@ -408,11 +428,10 @@ class Mustache { * * @access protected * @param string $tag_name - * @param array $context * @return string */ - protected function _renderUnescaped($tag_name, &$context) { - return $this->_getVariable($tag_name, $context); + protected function _renderUnescaped($tag_name) { + return $this->_getVariable($tag_name); } /** @@ -420,13 +439,10 @@ class Mustache { * * @access protected * @param string $tag_name - * @param array $context * @return string */ - protected function _renderPartial($tag_name, &$context) { + protected function _renderPartial($tag_name) { $view = clone($this); - $view->_otag = '{{'; - $view->_ctag = '}}'; return $view->render($this->_getPartial($tag_name)); } @@ -436,10 +452,9 @@ class Mustache { * * @access protected * @param string $tag_name - * @param array $context * @return string */ - protected function _changeDelimiter($tag_name, &$context) { + protected function _changeDelimiter($tag_name) { $tags = explode(' ', $tag_name); $this->_otag = $tags[0]; $this->_ctag = $tags[1]; @@ -451,22 +466,36 @@ class Mustache { } /** - * Prepare a new context reference array. - * - * This is used to create context arrays for iterable blocks. + * Push a local context onto the stack. * * @access protected - * @param array $context * @param array $local_context * @return array */ - protected function _getContext(&$context, &$local_context) { - $ret = array(); - $ret[] =& $local_context; - foreach ($context as $view) { - $ret[] =& $view; + protected function _pushContext(&$local_context) { + $new = array(); + $new[] =& $local_context; + foreach ($this->_context as $view) { + $new[] =& $view; } - return $ret; + $this->_context = $new; + } + + + /** + * Remove the latest context from the stack. + * + * @access protected + * @return void + */ + protected function _popContext() { + $new = array(); + + array_shift($this->_context); + foreach ($this->_context as $view) { + $new[] =& $view; + } + $this->_context = $new; } /** @@ -480,16 +509,15 @@ class Mustache { * * @access protected * @param string $tag_name - * @param array $context * @throws MustacheException Unknown variable name. * @return string */ - protected function _getVariable($tag_name, &$context) { + protected function _getVariable($tag_name) { if ($this->_hasPragma(self::PRAGMA_DOT_NOTATION)) { $chunks = explode('.', $tag_name); $first = array_shift($chunks); - $ret = $this->_findVariableInContext($first, $context); + $ret = $this->_findVariableInContext($first, $this->_context); while ($next = array_shift($chunks)) { // Slice off a chunk of context for dot notation traversal. $c = array($ret); @@ -497,7 +525,7 @@ class Mustache { } return $ret; } else { - return $this->_findVariableInContext($tag_name, $context); + return $this->_findVariableInContext($tag_name, $this->_context); } } From dff530093281edcee8286785489448312360b211 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Sat, 22 May 2010 19:25:27 -0400 Subject: [PATCH 05/16] Added [currently failing] test case for recursive partials. --- examples/recursive_partials/RecursivePartials.php | 15 +++++++++++++++ .../recursive_partials.mustache | 4 ++++ .../recursive_partials/recursive_partials.txt | 3 +++ 3 files changed, 22 insertions(+) create mode 100644 examples/recursive_partials/RecursivePartials.php create mode 100644 examples/recursive_partials/recursive_partials.mustache create mode 100644 examples/recursive_partials/recursive_partials.txt diff --git a/examples/recursive_partials/RecursivePartials.php b/examples/recursive_partials/RecursivePartials.php new file mode 100644 index 0000000..d1b820f --- /dev/null +++ b/examples/recursive_partials/RecursivePartials.php @@ -0,0 +1,15 @@ + "* {{ name }}", + ); + + public $name = 'George'; + public $child = array( + 'name' => 'Dan', + 'child' => array( + 'name' => 'Justin', + ) + ); +} \ No newline at end of file diff --git a/examples/recursive_partials/recursive_partials.mustache b/examples/recursive_partials/recursive_partials.mustache new file mode 100644 index 0000000..2b29188 --- /dev/null +++ b/examples/recursive_partials/recursive_partials.mustache @@ -0,0 +1,4 @@ +* {{name}} +{{#child}} +{{>child}} +{{/child}} \ No newline at end of file diff --git a/examples/recursive_partials/recursive_partials.txt b/examples/recursive_partials/recursive_partials.txt new file mode 100644 index 0000000..89c81c3 --- /dev/null +++ b/examples/recursive_partials/recursive_partials.txt @@ -0,0 +1,3 @@ +* George +* Dan +* Justin From 605dea1f79562f6eb652d8fda748b793e8fe7928 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Sat, 22 May 2010 19:59:15 -0400 Subject: [PATCH 06/16] Fix for infinite recursion in recursive partials example. --- examples/recursive_partials/RecursivePartials.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/recursive_partials/RecursivePartials.php b/examples/recursive_partials/RecursivePartials.php index d1b820f..5d239c1 100644 --- a/examples/recursive_partials/RecursivePartials.php +++ b/examples/recursive_partials/RecursivePartials.php @@ -2,14 +2,15 @@ class RecursivePartials extends Mustache { protected $_partials = array( - 'child' => "* {{ name }}", + 'child' => "* {{ name }}\n{{#child}}{{>child}}\n{{/child}}", ); public $name = 'George'; public $child = array( - 'name' => 'Dan', + 'name' => 'Dan', 'child' => array( - 'name' => 'Justin', + 'name' => 'Justin', + 'child' => false, ) ); } \ No newline at end of file From c79501b4ad4af630578a13e7c9ceb4bae0da2439 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Sat, 22 May 2010 20:27:31 -0400 Subject: [PATCH 07/16] Pragmas don't need to be re-rendered for all sub-templates (i.e. sections). Moving call to _renderPragmas into main render() method. --- Mustache.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mustache.php b/Mustache.php index 36c0a87..e5567c9 100644 --- a/Mustache.php +++ b/Mustache.php @@ -99,6 +99,7 @@ class Mustache { $this->_context = array($this); } + $template = $this->_renderPragmas($template, $context); return $this->_renderTemplate($template, $this->_context); } @@ -128,7 +129,6 @@ class Mustache { * @return string Rendered Mustache template. */ protected function _renderTemplate($template, &$context) { - $template = $this->_renderPragmas($template, $context); $template = $this->_renderSection($template, $context); return $this->_renderTags($template, $context); } From 0893a7d39d9ba4d009e01cd36e26ba71e3750667 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Sat, 22 May 2010 20:40:01 -0400 Subject: [PATCH 08/16] using array keys instead of iteration over context for creating subcontext arrays. this fixes incorrect context stacks in recursive partials. --- Mustache.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Mustache.php b/Mustache.php index 149fa11..bd81967 100644 --- a/Mustache.php +++ b/Mustache.php @@ -92,7 +92,6 @@ class Mustache { $this->_otag = '{{'; $this->_ctag = '}}'; $this->_localPragmas = null; - if ($keys = array_keys($this->_context)) { if ($this->_context[$keys[0]] instanceof Mustache) { $this->_context[$keys[0]] =& $this; @@ -475,8 +474,8 @@ class Mustache { protected function _pushContext(&$local_context) { $new = array(); $new[] =& $local_context; - foreach ($this->_context as $view) { - $new[] =& $view; + foreach (array_keys($this->_context) as $key) { + $new[] =& $this->_context[$key]; } $this->_context = $new; } @@ -491,9 +490,10 @@ class Mustache { protected function _popContext() { $new = array(); - array_shift($this->_context); - foreach ($this->_context as $view) { - $new[] =& $view; + $keys = array_keys($this->_context); + array_shift($keys); + foreach ($keys as $key) { + $new[] =& $this->_context[$key]; } $this->_context = $new; } From e2374d645ba73bf3380401eb8b397b35909ba89d Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Sat, 22 May 2010 20:40:47 -0400 Subject: [PATCH 09/16] [punting] fixing whitespace in recursive partials template since mustache kinda sucks at whitespace :) --- examples/recursive_partials/RecursivePartials.php | 2 +- examples/recursive_partials/recursive_partials.mustache | 5 +---- examples/recursive_partials/recursive_partials.txt | 4 +--- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/examples/recursive_partials/RecursivePartials.php b/examples/recursive_partials/RecursivePartials.php index 5d239c1..04e8af8 100644 --- a/examples/recursive_partials/RecursivePartials.php +++ b/examples/recursive_partials/RecursivePartials.php @@ -2,7 +2,7 @@ class RecursivePartials extends Mustache { protected $_partials = array( - 'child' => "* {{ name }}\n{{#child}}{{>child}}\n{{/child}}", + 'child' => " > {{ name }}{{#child}}{{>child}}{{/child}}", ); public $name = 'George'; diff --git a/examples/recursive_partials/recursive_partials.mustache b/examples/recursive_partials/recursive_partials.mustache index 2b29188..0bc5d03 100644 --- a/examples/recursive_partials/recursive_partials.mustache +++ b/examples/recursive_partials/recursive_partials.mustache @@ -1,4 +1 @@ -* {{name}} -{{#child}} -{{>child}} -{{/child}} \ No newline at end of file +{{name}}{{#child}}{{>child}}{{/child}} \ No newline at end of file diff --git a/examples/recursive_partials/recursive_partials.txt b/examples/recursive_partials/recursive_partials.txt index 89c81c3..681cdef 100644 --- a/examples/recursive_partials/recursive_partials.txt +++ b/examples/recursive_partials/recursive_partials.txt @@ -1,3 +1 @@ -* George -* Dan -* Justin +George > Dan > Justin \ No newline at end of file From 5ade8a5ee3686894f0df2a5acdcef69fb1269d99 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Sat, 22 May 2010 20:41:12 -0400 Subject: [PATCH 10/16] Added unit test for Mustache clone method. --- test/MustacheTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/MustacheTest.php b/test/MustacheTest.php index 06e1874..1936c4a 100644 --- a/test/MustacheTest.php +++ b/test/MustacheTest.php @@ -167,6 +167,25 @@ class MustacheTest extends PHPUnit_Framework_TestCase { $this->assertEquals($first, $second); } + /** + * testClone function. + * + * @dataProvider getExamples + * @access public + * @return void + */ + public function testClone($class, $template, $output) { + $m = new $class; + $n = clone $m; + + $n_output = $n->render($template); + + $o = clone $n; + + $this->assertEquals($m->render($template), $n_output); + $this->assertEquals($n_output, $o->render($template)); + } + /** * Test everything in the `examples` directory. * From df1b3c8e7dfc5206115d0eb240ff6d7be170125d Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Sat, 22 May 2010 20:50:05 -0400 Subject: [PATCH 11/16] Pragmas in parent templates no longer apply to partials (as of a few commits ago). Added test case, removed known issue from readme. --- README.markdown | 2 -- examples/pragmas_in_partials/PragmasInPartials.php | 8 ++++++++ examples/pragmas_in_partials/pragmas_in_partials.mustache | 3 +++ examples/pragmas_in_partials/pragmas_in_partials.txt | 2 ++ 4 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 examples/pragmas_in_partials/PragmasInPartials.php create mode 100644 examples/pragmas_in_partials/pragmas_in_partials.mustache create mode 100644 examples/pragmas_in_partials/pragmas_in_partials.txt diff --git a/README.markdown b/README.markdown index 1a029cc..ab27846 100644 --- a/README.markdown +++ b/README.markdown @@ -81,8 +81,6 @@ And render it: Known Issues ------------ - * Pragmas don't un-apply... Instead of applying only to a specific template, pragmas are applied - to all subsequent templates and partials rendered by this Mustache instance. * Sections don't respect delimiter changes -- `delimiters` example currently fails with an "unclosed section" exception. * Test coverage is incomplete. diff --git a/examples/pragmas_in_partials/PragmasInPartials.php b/examples/pragmas_in_partials/PragmasInPartials.php new file mode 100644 index 0000000..7458289 --- /dev/null +++ b/examples/pragmas_in_partials/PragmasInPartials.php @@ -0,0 +1,8 @@ +'; + protected $_partials = array( + 'dinosaur' => '{{say}}' + ); +} \ No newline at end of file diff --git a/examples/pragmas_in_partials/pragmas_in_partials.mustache b/examples/pragmas_in_partials/pragmas_in_partials.mustache new file mode 100644 index 0000000..abd6ef4 --- /dev/null +++ b/examples/pragmas_in_partials/pragmas_in_partials.mustache @@ -0,0 +1,3 @@ +{{%UNESCAPED}} +{{say}} +{{>dinosaur}} \ No newline at end of file diff --git a/examples/pragmas_in_partials/pragmas_in_partials.txt b/examples/pragmas_in_partials/pragmas_in_partials.txt new file mode 100644 index 0000000..c8e77e3 --- /dev/null +++ b/examples/pragmas_in_partials/pragmas_in_partials.txt @@ -0,0 +1,2 @@ +< RAWR!! > +< RAWR!! > \ No newline at end of file From 619a48674bcf80518cbac15ac7b7b05647d23d94 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Sat, 22 May 2010 22:41:50 -0400 Subject: [PATCH 12/16] fixed name of clone test, added more assertions. --- test/MustacheTest.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/MustacheTest.php b/test/MustacheTest.php index 1936c4a..22013c7 100644 --- a/test/MustacheTest.php +++ b/test/MustacheTest.php @@ -174,7 +174,7 @@ class MustacheTest extends PHPUnit_Framework_TestCase { * @access public * @return void */ - public function testClone($class, $template, $output) { + public function test__clone($class, $template, $output) { $m = new $class; $n = clone $m; @@ -184,6 +184,10 @@ class MustacheTest extends PHPUnit_Framework_TestCase { $this->assertEquals($m->render($template), $n_output); $this->assertEquals($n_output, $o->render($template)); + + $this->assertNotSame($m, $n); + $this->assertNotSame($n, $o); + $this->assertNotSame($m, $o); } /** From eb1a8965695dc942c17bd114e46647ea53f877b1 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Sat, 22 May 2010 22:42:54 -0400 Subject: [PATCH 13/16] Fixed root context swap in clone (was checking context[0], should have checked last element in context stack). --- Mustache.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Mustache.php b/Mustache.php index bd81967..79b101d 100644 --- a/Mustache.php +++ b/Mustache.php @@ -92,9 +92,11 @@ class Mustache { $this->_otag = '{{'; $this->_ctag = '}}'; $this->_localPragmas = null; + if ($keys = array_keys($this->_context)) { - if ($this->_context[$keys[0]] instanceof Mustache) { - $this->_context[$keys[0]] =& $this; + $last = array_pop($keys); + if ($this->_context[$last] instanceof Mustache) { + $this->_context[$last] =& $this; } } } From 11c2b04d8e7290344b9ffa81a5452c87a555a5d1 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Sat, 22 May 2010 22:44:28 -0400 Subject: [PATCH 14/16] fixed typo in comment --- Mustache.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mustache.php b/Mustache.php index a4b4bbe..ca78b76 100644 --- a/Mustache.php +++ b/Mustache.php @@ -43,7 +43,7 @@ class Mustache { * Pragmas apply only to the current template. Partials, even those included after the * {{%UNESCAPED}} call, will need their own pragma declaration. * - * his may be useful in non-HTML Mustache situations. + * This may be useful in non-HTML Mustache situations. */ const PRAGMA_UNESCAPED = 'UNESCAPED'; From 2fc242a6ae62df961109644759c50db7578a79dd Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Sat, 22 May 2010 22:51:26 -0400 Subject: [PATCH 15/16] Added test case for resetting pragmas when reusing a single Mustache instance to render multiple templates. --- test/MustachePragmaTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/MustachePragmaTest.php b/test/MustachePragmaTest.php index 58f380e..39e1dbd 100644 --- a/test/MustachePragmaTest.php +++ b/test/MustachePragmaTest.php @@ -39,4 +39,10 @@ class MustachePragmaTest extends PHPUnit_Framework_TestCase { $this->assertEquals("1\n23", $m->render("1\n2{{%DOT-NOTATION}}\n3"), 'Wrong newline removed with pragma tag'); } + public function testPragmaReset() { + $m = new Mustache('', array('symbol' => '>>>')); + $this->assertEquals('>>>', $m->render('{{{symbol}}}')); + $this->assertEquals('>>>', $m->render('{{%UNESCAPED}}{{symbol}}')); + $this->assertEquals('>>>', $m->render('{{{symbol}}}')); + } } \ No newline at end of file From f0ed2ad49951b06a331b9c275c55070660e1f4d1 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Mon, 24 May 2010 10:29:43 -0400 Subject: [PATCH 16/16] Added test for template retention in subsequent render invocations. --- test/MustacheTest.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/MustacheTest.php b/test/MustacheTest.php index 06e1874..8758a66 100644 --- a/test/MustacheTest.php +++ b/test/MustacheTest.php @@ -167,6 +167,23 @@ class MustacheTest extends PHPUnit_Framework_TestCase { $this->assertEquals($first, $second); } + + /** + * Mustache should not use templates passed to the render() method for subsequent invocations. + * + * @access public + * @return void + */ + public function testResetTemplateForMultipleInvocations() { + $m = new Mustache('Sirve.'); + $m->render('No sirve.'); + $this->assertEquals('Sirve.', $m->render()); + + $m2 = new Mustache(); + $m2->render('No sirve.'); + $this->assertEquals('', $m2->render()); + } + /** * Test everything in the `examples` directory. *