From 20ace3e74c79f0af1239cb33f6553166f80dfea4 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Thu, 29 Apr 2010 22:49:50 -0400 Subject: [PATCH 01/13] Implemented implicit iterator pragma. Fixed getPragmaOptions to return empty array if no options are set. Fixed getVariable to return exact variable name matches before dot notation matches (i.e. the default iterator -- '.' -- will match the iterator and not try to do some crazy dot notation parsing. --- Mustache.php | 33 ++++++++++++---- .../implicit_iterator/ImplicitIterator.php | 5 +++ .../implicit_iterator.mustache | 4 ++ .../implicit_iterator/implicit_iterator.txt | 5 +++ test/MustachePragmaImplicitIteratorTest.php | 38 +++++++++++++++++++ 5 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 examples/implicit_iterator/ImplicitIterator.php create mode 100644 examples/implicit_iterator/implicit_iterator.mustache create mode 100644 examples/implicit_iterator/implicit_iterator.txt create mode 100644 test/MustachePragmaImplicitIteratorTest.php diff --git a/Mustache.php b/Mustache.php index e47e532..3f36d5e 100644 --- a/Mustache.php +++ b/Mustache.php @@ -25,7 +25,8 @@ class Mustache { // Override charset passed to htmlentities() and htmlspecialchars(). Defaults to UTF-8. protected $charset = 'UTF-8'; - const PRAGMA_DOT_NOTATION = 'DOT-NOTATION'; + const PRAGMA_DOT_NOTATION = 'DOT-NOTATION'; + const PRAGMA_IMPLICIT_ITERATOR = 'IMPLICIT-ITERATOR'; protected $tagRegEx; @@ -35,7 +36,8 @@ class Mustache { protected $pragmas = array(); protected $pragmasImplemented = array( - self::PRAGMA_DOT_NOTATION + self::PRAGMA_DOT_NOTATION, + self::PRAGMA_IMPLICIT_ITERATOR ); /** @@ -151,8 +153,23 @@ class Mustache { // regular section case '#': if ($this->varIsIterable($val)) { + if ($this->hasPragma(self::PRAGMA_IMPLICIT_ITERATOR)) { + if ($opt = $this->getPragmaOptions(self::PRAGMA_IMPLICIT_ITERATOR)) { + $iterator = $opt['iterator']; + } else { + $iterator = '.'; + } + } else { + $iterator = false; + } + foreach ($val as $local_context) { - $replace .= $this->_render($content, $this->getContext($context, $local_context)); + if ($iterator) { + $c = array($iterator => $local_context); + $replace .= $this->_render($content, $this->getContext($context, $c)); + } else { + $replace .= $this->_render($content, $this->getContext($context, $local_context)); + } } } else if ($val) { if (is_array($val) || is_object($val)) { @@ -231,11 +248,11 @@ class Mustache { } protected function getPragmaOptions($pragma_name) { - if (!$this->hasPragma()) { + if (!$this->hasPragma($pragma_name)) { throw new MustacheException('Unknown pragma: ' . $pragma_name, MustacheException::UNKNOWN_PRAGMA); } - return $this->pragmas[$pragma_name]; + return (is_array($this->pragmas[$pragma_name])) ? $this->pragmas[$pragma_name] : array(); } /** @@ -426,7 +443,9 @@ class Mustache { * @return string */ protected function getVariable($tag_name, &$context) { - if ($this->hasPragma(self::PRAGMA_DOT_NOTATION)) { + if ($ret = $this->_getVariable($tag_name, $context)) { + return $ret; + } else if ($this->hasPragma(self::PRAGMA_DOT_NOTATION)) { $chunks = explode('.', $tag_name); $first = array_shift($chunks); @@ -438,7 +457,7 @@ class Mustache { } return $ret; } else { - return $this->_getVariable($tag_name, $context); + return $ret; } } diff --git a/examples/implicit_iterator/ImplicitIterator.php b/examples/implicit_iterator/ImplicitIterator.php new file mode 100644 index 0000000..c01fef0 --- /dev/null +++ b/examples/implicit_iterator/ImplicitIterator.php @@ -0,0 +1,5 @@ +getMock('Mustache', array('renderPragma'), array('{{%IMPLICIT-ITERATOR}}')); + $m->expects($this->exactly(1)) + ->method('renderPragma') + ->with(array('{{%IMPLICIT-ITERATOR}}', 'IMPLICIT-ITERATOR', null)); + $m->render(); + } + + public function testImplicitIterator() { + $m1 = new Mustache('{{%IMPLICIT-ITERATOR}}{{#items}}{{.}}{{/items}}', array('items' => array('a', 'b', 'c'))); + $this->assertEquals('abc', $m1->render()); + + $m2 = new Mustache('{{%IMPLICIT-ITERATOR}}{{#items}}{{.}}{{/items}}', array('items' => array(1, 2, 3))); + $this->assertEquals('123', $m2->render()); + } + + public function testDotNotationCollision() { + $m = new Mustache(null, array('items' => array('foo', 'bar', 'baz'))); + + $this->assertEquals('foobarbaz', $m->render('{{%IMPLICIT-ITERATOR}}{{%DOT-NOTATION}}{{#items}}{{.}}{{/items}}')); + $this->assertEquals('foobarbaz', $m->render('{{%DOT-NOTATION}}{{%IMPLICIT-ITERATOR}}{{#items}}{{.}}{{/items}}')); + } + + public function testCustomIterator() { + $m = new Mustache(null, array('items' => array('foo', 'bar', 'baz'))); + + $this->assertEquals('foobarbaz', $m->render('{{%IMPLICIT-ITERATOR iterator=item}}{{#items}}{{item}}{{/items}}')); + $this->assertEquals('foobarbaz', $m->render('{{%IMPLICIT-ITERATOR iterator=items}}{{#items}}{{items}}{{/items}}')); + } + +} \ No newline at end of file From 1330cf1d4822b20b6378a1e2edf64f3ddb209c9a Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Sun, 23 May 2010 00:48:43 -0400 Subject: [PATCH 02/13] Updated implicit iterator test to reflect changes in mustache function names. --- test/MustachePragmaImplicitIteratorTest.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/MustachePragmaImplicitIteratorTest.php b/test/MustachePragmaImplicitIteratorTest.php index 20e3c4b..cd4b711 100644 --- a/test/MustachePragmaImplicitIteratorTest.php +++ b/test/MustachePragmaImplicitIteratorTest.php @@ -6,9 +6,9 @@ require_once 'PHPUnit/Framework.php'; class MustachePragmaImplicitIteratorTest extends PHPUnit_Framework_TestCase { public function testEnablePragma() { - $m = $this->getMock('Mustache', array('renderPragma'), array('{{%IMPLICIT-ITERATOR}}')); + $m = $this->getMock('Mustache', array('_renderPragma'), array('{{%IMPLICIT-ITERATOR}}')); $m->expects($this->exactly(1)) - ->method('renderPragma') + ->method('_renderPragma') ->with(array('{{%IMPLICIT-ITERATOR}}', 'IMPLICIT-ITERATOR', null)); $m->render(); } @@ -31,7 +31,8 @@ class MustachePragmaImplicitIteratorTest extends PHPUnit_Framework_TestCase { public function testCustomIterator() { $m = new Mustache(null, array('items' => array('foo', 'bar', 'baz'))); - $this->assertEquals('foobarbaz', $m->render('{{%IMPLICIT-ITERATOR iterator=item}}{{#items}}{{item}}{{/items}}')); + $this->assertEquals('foobarbaz', $m->render('{{%IMPLICIT-ITERATOR}}{{#items}}{{.}}{{/items}}')); + $this->assertEquals('foobarbaz', $m->render('{{%IMPLICIT-ITERATOR iterator=i}}{{#items}}{{i}}{{/items}}')); $this->assertEquals('foobarbaz', $m->render('{{%IMPLICIT-ITERATOR iterator=items}}{{#items}}{{items}}{{/items}}')); } From 20184491842224aab9979ab3caba9055eb45c2cf Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Wed, 2 Jun 2010 02:08:54 -0400 Subject: [PATCH 03/13] added test and known issue for dot notation/implicit iterator woes. --- README.markdown | 2 ++ test/MustachePragmaImplicitIteratorTest.php | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/README.markdown b/README.markdown index 1a029cc..4e843fd 100644 --- a/README.markdown +++ b/README.markdown @@ -85,6 +85,8 @@ Known Issues 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. + * Dot notation and implicit iterators don't really play nice. A non-traversible local context is + passed to the section. * Test coverage is incomplete. diff --git a/test/MustachePragmaImplicitIteratorTest.php b/test/MustachePragmaImplicitIteratorTest.php index cd4b711..f8217ee 100644 --- a/test/MustachePragmaImplicitIteratorTest.php +++ b/test/MustachePragmaImplicitIteratorTest.php @@ -36,4 +36,20 @@ class MustachePragmaImplicitIteratorTest extends PHPUnit_Framework_TestCase { $this->assertEquals('foobarbaz', $m->render('{{%IMPLICIT-ITERATOR iterator=items}}{{#items}}{{items}}{{/items}}')); } + public function testDotNotationContext() { + $m = new Mustache(null, array('items' => array( + array('index' => 1, 'name' => 'foo'), + array('index' => 2, 'name' => 'bar'), + array('index' => 3, 'name' => 'baz'), + ))); + + $this->assertEquals('foobarbaz', $m->render('{{%IMPLICIT-ITERATOR}}{{#items}}{{#.}}{{name}}{{/.}}{{/items}}')); + + // skip the last two tests here, they just break... + $this->markTestSkipped('Implicit iterator not completely compatible with dot notation'); + + $this->assertEquals('123', $m->render('{{%IMPLICIT-ITERATOR iterator=i}}{{#items}}{{i.index}}{{/items}}')); + $this->assertEquals('foobarbaz', $m->render('{{%IMPLICIT-ITERATOR iterator=i}}{{#items}}{{i.name}}{{/items}}')); + } + } \ No newline at end of file From e026d8e7f569581fc1011fd6f1b97683d66eed09 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Mon, 5 Jul 2010 23:29:28 -0400 Subject: [PATCH 04/13] Fix for examples directory iterator in PHP 5.2. Future-proof things a bit by actually checking for file extension before accessing that index. --- test/MustacheTest.php | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/test/MustacheTest.php b/test/MustacheTest.php index c05b15b..bd055f7 100644 --- a/test/MustacheTest.php +++ b/test/MustacheTest.php @@ -262,22 +262,24 @@ class MustacheTest extends PHPUnit_Framework_TestCase { foreach ($children as $file) { if (!$file->isFile()) continue; - $filename = $file->getPathInfo(); + $filename = $file->getPathname(); $info = pathinfo($filename); - switch($info['extension']) { - case 'php': - $class = $info['filename']; - include_once($filename); - break; + if (isset($info['extension'])) { + switch($info['extension']) { + case 'php': + $class = $info['filename']; + include_once($filename); + break; - case 'mustache': - $template = file_get_contents($filename); - break; + case 'mustache': + $template = file_get_contents($filename); + break; - case 'txt': - $output = file_get_contents($filename); - break; + case 'txt': + $output = file_get_contents($filename); + break; + } } } From 6084a37a3ce9e79386b099a34119d6d394dab3e0 Mon Sep 17 00:00:00 2001 From: Jeremy Bush Date: Mon, 5 Jul 2010 17:50:41 -0500 Subject: [PATCH 05/13] Adding examples for object sections --- .../Sections_Iterable_Object.php | 17 +++++++++++ .../sections.mustache | 6 ++++ .../sections_iterable_object/sections.txt | 4 +++ .../Sections_Noniterable_Object.php | 29 +++++++++++++++++++ .../sections.mustache | 6 ++++ .../sections_noniterable_object/sections.txt | 4 +++ 6 files changed, 66 insertions(+) create mode 100644 examples/sections_iterable_object/Sections_Iterable_Object.php create mode 100644 examples/sections_iterable_object/sections.mustache create mode 100644 examples/sections_iterable_object/sections.txt create mode 100644 examples/sections_noniterable_object/Sections_Noniterable_Object.php create mode 100644 examples/sections_noniterable_object/sections.mustache create mode 100644 examples/sections_noniterable_object/sections.txt diff --git a/examples/sections_iterable_object/Sections_Iterable_Object.php b/examples/sections_iterable_object/Sections_Iterable_Object.php new file mode 100644 index 0000000..ee2f661 --- /dev/null +++ b/examples/sections_iterable_object/Sections_Iterable_Object.php @@ -0,0 +1,17 @@ + 'And it worked the second time.', + 'bar' => 'As well as the third.' + ); + + public function __get($key) + { + return isset($this->_data[$key]) ? $this->_data[$key] : NULL; + } + + public function __isset($key) + { + return isset($this->_data[$key]); + } +} \ No newline at end of file diff --git a/examples/sections_noniterable_object/sections.mustache b/examples/sections_noniterable_object/sections.mustache new file mode 100644 index 0000000..9119608 --- /dev/null +++ b/examples/sections_noniterable_object/sections.mustache @@ -0,0 +1,6 @@ +* {{ start }} +{{# middle }} +* {{ foo }} +* {{ bar }} +{{/ middle }} +* {{ final }} \ No newline at end of file diff --git a/examples/sections_noniterable_object/sections.txt b/examples/sections_noniterable_object/sections.txt new file mode 100644 index 0000000..e6b2d7a --- /dev/null +++ b/examples/sections_noniterable_object/sections.txt @@ -0,0 +1,4 @@ +* It worked the first time. +* And it worked the second time. +* As well as the third. +* Then, surprisingly, it worked the final time. \ No newline at end of file From c45550e9e5924da6471781d267a06b26d66cd064 Mon Sep 17 00:00:00 2001 From: Jeremy Bush Date: Mon, 5 Jul 2010 20:20:41 -0500 Subject: [PATCH 06/13] Fixing #3, Transversable objects should be iterated over. --- Mustache.php | 2 +- .../Sections_Iterator_Object.php | 41 +++++++++++++++++++ .../sections.mustache | 5 +++ .../sections_iterator_object/sections.txt | 4 ++ 4 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 examples/sections_iterator_object/Sections_Iterator_Object.php create mode 100644 examples/sections_iterator_object/sections.mustache create mode 100644 examples/sections_iterator_object/sections.txt diff --git a/Mustache.php b/Mustache.php index 88727c5..f06edca 100644 --- a/Mustache.php +++ b/Mustache.php @@ -597,7 +597,7 @@ class Mustache { * @return bool */ protected function _varIsIterable($var) { - return is_object($var) || (is_array($var) && !array_diff_key($var, array_keys(array_keys($var)))); + return $var instanceof Traversable || (is_array($var) && !array_diff_key($var, array_keys(array_keys($var)))); } } diff --git a/examples/sections_iterator_object/Sections_Iterator_Object.php b/examples/sections_iterator_object/Sections_Iterator_Object.php new file mode 100644 index 0000000..e517fe0 --- /dev/null +++ b/examples/sections_iterator_object/Sections_Iterator_Object.php @@ -0,0 +1,41 @@ + 'And it worked the second time.'), + array('item' => 'As well as the third.'), + ); + + public function rewind() { + $this->_position = 0; + } + + public function current() { + return $this->_data[$this->_position]; + } + + public function key() { + return $this->_position; + } + + public function next() { + ++$this->_position; + } + + public function valid() { + return isset($this->_data[$this->_position]); + } +} \ No newline at end of file diff --git a/examples/sections_iterator_object/sections.mustache b/examples/sections_iterator_object/sections.mustache new file mode 100644 index 0000000..44dfce4 --- /dev/null +++ b/examples/sections_iterator_object/sections.mustache @@ -0,0 +1,5 @@ +* {{ start }} +{{# middle }} +* {{ item }} +{{/ middle }} +* {{ final }} \ No newline at end of file diff --git a/examples/sections_iterator_object/sections.txt b/examples/sections_iterator_object/sections.txt new file mode 100644 index 0000000..e6b2d7a --- /dev/null +++ b/examples/sections_iterator_object/sections.txt @@ -0,0 +1,4 @@ +* It worked the first time. +* And it worked the second time. +* As well as the third. +* Then, surprisingly, it worked the final time. \ No newline at end of file From 5186d0bc18dede6ea0c7022046dc7842dc370f5d Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Mon, 5 Jul 2010 21:13:08 -0400 Subject: [PATCH 07/13] Test case for #3 (_varIsIterable issues). --- test/MustacheObjectSectionTest.php | 56 ++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 test/MustacheObjectSectionTest.php diff --git a/test/MustacheObjectSectionTest.php b/test/MustacheObjectSectionTest.php new file mode 100644 index 0000000..58d4286 --- /dev/null +++ b/test/MustacheObjectSectionTest.php @@ -0,0 +1,56 @@ +assertEquals('Foo', $alpha->render('{{#foo}}{{name}}{{/foo}}')); + } + + public function testObjectWithGet() { + $beta = new Beta(); + $this->assertEquals('Foo', $beta->render('{{#foo}}{{name}}{{/foo}}')); + } + + public function testSectionObjectWithGet() { + $gamma = new Gamma(); + $this->assertEquals('Foo', $gamma->render('{{#bar}}{{#foo}}{{name}}{{/foo}}{{/bar}}')); + } +} + +class Alpha extends Mustache { + public $foo; + + public function __construct() { + $this->foo = new StdClass(); + $this->foo->name = 'Foo'; + $this->foo->number = 1; + } +} + +class Beta extends Mustache { + protected $_data = array(); + + public function __construct() { + $this->_data['foo'] = new StdClass(); + $this->_data['foo']->name = 'Foo'; + $this->_data['foo']->number = 1; + } + + public function __isset($name) { + return array_key_exists($name, $this->_data); + } + + public function __get($name) { + return $this->_data[$name]; + } +} + +class Gamma extends Mustache { + public $bar; + + public function __construct() { + $this->bar = new Beta(); + } +} \ No newline at end of file From c2c01cf964536b9c3ffdd30eaf1073980812449f Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Tue, 6 Jul 2010 10:09:00 -0400 Subject: [PATCH 08/13] only test examples which find a php class. --- test/MustacheTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/MustacheTest.php b/test/MustacheTest.php index bd055f7..a877c03 100644 --- a/test/MustacheTest.php +++ b/test/MustacheTest.php @@ -283,7 +283,9 @@ class MustacheTest extends PHPUnit_Framework_TestCase { } } - $ret[$example] = array($class, $template, $output); + if (!empty($class)) { + $ret[$example] = array($class, $template, $output); + } } $files->next(); From 2cfb8aefc107c38293c822a1e2175561254e4cb8 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Tue, 6 Jul 2010 10:17:04 -0400 Subject: [PATCH 09/13] Rename section object tests to work with upcoming autoload-template feature. Clean up code to match style. --- .../SectionIteratorObject.php} | 7 +++---- .../section_iterator_object.mustache} | 0 .../section_iterator_object.txt} | 0 .../SectionMagicObject.php} | 13 +++++-------- .../section_magic_object.mustache} | 0 .../section_magic_object.txt} | 0 .../SectionObjects.php} | 7 +++---- .../section_objects.mustache} | 0 .../section_objects.txt} | 0 9 files changed, 11 insertions(+), 16 deletions(-) rename examples/{sections_iterator_object/Sections_Iterator_Object.php => section_iterator_objects/SectionIteratorObject.php} (83%) rename examples/{sections_iterator_object/sections.mustache => section_iterator_objects/section_iterator_object.mustache} (100%) rename examples/{sections_iterable_object/sections.txt => section_iterator_objects/section_iterator_object.txt} (100%) rename examples/{sections_noniterable_object/Sections_Noniterable_Object.php => section_magic_objects/SectionMagicObject.php} (67%) rename examples/{sections_iterable_object/sections.mustache => section_magic_objects/section_magic_object.mustache} (100%) rename examples/{sections_iterator_object/sections.txt => section_magic_objects/section_magic_object.txt} (100%) rename examples/{sections_iterable_object/Sections_Iterable_Object.php => section_objects/SectionObjects.php} (70%) rename examples/{sections_noniterable_object/sections.mustache => section_objects/section_objects.mustache} (100%) rename examples/{sections_noniterable_object/sections.txt => section_objects/section_objects.txt} (100%) diff --git a/examples/sections_iterator_object/Sections_Iterator_Object.php b/examples/section_iterator_objects/SectionIteratorObject.php similarity index 83% rename from examples/sections_iterator_object/Sections_Iterator_Object.php rename to examples/section_iterator_objects/SectionIteratorObject.php index e517fe0..5a592ab 100644 --- a/examples/sections_iterator_object/Sections_Iterator_Object.php +++ b/examples/section_iterator_objects/SectionIteratorObject.php @@ -1,17 +1,16 @@ 'And it worked the second time.', 'bar' => 'As well as the third.' ); - public function __get($key) - { + public function __get($key) { return isset($this->_data[$key]) ? $this->_data[$key] : NULL; } - public function __isset($key) - { + public function __isset($key) { return isset($this->_data[$key]); } } \ No newline at end of file diff --git a/examples/sections_iterable_object/sections.mustache b/examples/section_magic_objects/section_magic_object.mustache similarity index 100% rename from examples/sections_iterable_object/sections.mustache rename to examples/section_magic_objects/section_magic_object.mustache diff --git a/examples/sections_iterator_object/sections.txt b/examples/section_magic_objects/section_magic_object.txt similarity index 100% rename from examples/sections_iterator_object/sections.txt rename to examples/section_magic_objects/section_magic_object.txt diff --git a/examples/sections_iterable_object/Sections_Iterable_Object.php b/examples/section_objects/SectionObjects.php similarity index 70% rename from examples/sections_iterable_object/Sections_Iterable_Object.php rename to examples/section_objects/SectionObjects.php index ee2f661..41b7d84 100644 --- a/examples/sections_iterable_object/Sections_Iterable_Object.php +++ b/examples/section_objects/SectionObjects.php @@ -1,17 +1,16 @@ Date: Tue, 6 Jul 2010 10:19:49 -0400 Subject: [PATCH 10/13] whitespace cleanup. --- test/MustacheObjectSectionTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/MustacheObjectSectionTest.php b/test/MustacheObjectSectionTest.php index 58d4286..f9ae45b 100644 --- a/test/MustacheObjectSectionTest.php +++ b/test/MustacheObjectSectionTest.php @@ -21,7 +21,7 @@ class MustacheObjectSectionTest extends PHPUnit_Framework_TestCase { class Alpha extends Mustache { public $foo; - + public function __construct() { $this->foo = new StdClass(); $this->foo->name = 'Foo'; @@ -31,17 +31,17 @@ class Alpha extends Mustache { class Beta extends Mustache { protected $_data = array(); - + public function __construct() { $this->_data['foo'] = new StdClass(); $this->_data['foo']->name = 'Foo'; $this->_data['foo']->number = 1; } - + public function __isset($name) { return array_key_exists($name, $this->_data); } - + public function __get($name) { return $this->_data[$name]; } From 93018640d95e365aa3c07d6db50c65c21c1247bb Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Tue, 6 Jul 2010 13:32:37 -0400 Subject: [PATCH 11/13] Fixing test names to match prior art. --- .../{SectionIteratorObject.php => SectionIteratorObjects.php} | 2 +- ...erator_object.mustache => section_iterator_objects.mustache} | 0 ...section_iterator_object.txt => section_iterator_objects.txt} | 0 .../{SectionMagicObject.php => SectionMagicObjects.php} | 2 +- ...ion_magic_object.mustache => section_magic_objects.mustache} | 0 .../{section_magic_object.txt => section_magic_objects.txt} | 0 6 files changed, 2 insertions(+), 2 deletions(-) rename examples/section_iterator_objects/{SectionIteratorObject.php => SectionIteratorObjects.php} (93%) rename examples/section_iterator_objects/{section_iterator_object.mustache => section_iterator_objects.mustache} (100%) rename examples/section_iterator_objects/{section_iterator_object.txt => section_iterator_objects.txt} (100%) rename examples/section_magic_objects/{SectionMagicObject.php => SectionMagicObjects.php} (91%) rename examples/section_magic_objects/{section_magic_object.mustache => section_magic_objects.mustache} (100%) rename examples/section_magic_objects/{section_magic_object.txt => section_magic_objects.txt} (100%) diff --git a/examples/section_iterator_objects/SectionIteratorObject.php b/examples/section_iterator_objects/SectionIteratorObjects.php similarity index 93% rename from examples/section_iterator_objects/SectionIteratorObject.php rename to examples/section_iterator_objects/SectionIteratorObjects.php index 5a592ab..fa5213c 100644 --- a/examples/section_iterator_objects/SectionIteratorObject.php +++ b/examples/section_iterator_objects/SectionIteratorObjects.php @@ -1,6 +1,6 @@ Date: Sun, 11 Jul 2010 22:54:57 -0400 Subject: [PATCH 12/13] Fixed implicit iterator + dot notation tests, this feature is now ready to merge :) --- README.markdown | 2 -- test/MustachePragmaImplicitIteratorTest.php | 8 ++------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/README.markdown b/README.markdown index 3123c6d..ab27846 100644 --- a/README.markdown +++ b/README.markdown @@ -83,8 +83,6 @@ Known Issues * Sections don't respect delimiter changes -- `delimiters` example currently fails with an "unclosed section" exception. - * Dot notation and implicit iterators don't really play nice. A non-traversible local context is - passed to the section. * Test coverage is incomplete. diff --git a/test/MustachePragmaImplicitIteratorTest.php b/test/MustachePragmaImplicitIteratorTest.php index f8217ee..bf39091 100644 --- a/test/MustachePragmaImplicitIteratorTest.php +++ b/test/MustachePragmaImplicitIteratorTest.php @@ -44,12 +44,8 @@ class MustachePragmaImplicitIteratorTest extends PHPUnit_Framework_TestCase { ))); $this->assertEquals('foobarbaz', $m->render('{{%IMPLICIT-ITERATOR}}{{#items}}{{#.}}{{name}}{{/.}}{{/items}}')); - - // skip the last two tests here, they just break... - $this->markTestSkipped('Implicit iterator not completely compatible with dot notation'); - - $this->assertEquals('123', $m->render('{{%IMPLICIT-ITERATOR iterator=i}}{{#items}}{{i.index}}{{/items}}')); - $this->assertEquals('foobarbaz', $m->render('{{%IMPLICIT-ITERATOR iterator=i}}{{#items}}{{i.name}}{{/items}}')); + $this->assertEquals('123', $m->render('{{%IMPLICIT-ITERATOR iterator=i}}{{%DOT-NOTATION}}{{#items}}{{i.index}}{{/items}}')); + $this->assertEquals('foobarbaz', $m->render('{{%IMPLICIT-ITERATOR iterator=i}}{{%DOT-NOTATION}}{{#items}}{{i.name}}{{/items}}')); } } \ No newline at end of file From c1cdea7bc530aaa3f5ab9842651c0890bd141d2e Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Sun, 11 Jul 2010 23:17:14 -0400 Subject: [PATCH 13/13] Added documentation for IMPLICIT-ITERATOR and DOT-NOTATION pragmas. --- Mustache.php | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Mustache.php b/Mustache.php index d24b632..f87696d 100644 --- a/Mustache.php +++ b/Mustache.php @@ -33,7 +33,44 @@ class Mustache { // Override charset passed to htmlentities() and htmlspecialchars(). Defaults to UTF-8. protected $_charset = 'UTF-8'; + /** + * Pragmas are macro-like directives that, when invoked, change the behavior or + * syntax of Mustache. + * + * They should be considered extremely experimental. Most likely their implementation + * will change in the future. + */ + + /** + * The {{%DOT-NOTATION}} pragma allows context traversal via dots. Given the following context: + * + * $context = array('foo' => array('bar' => array('baz' => 'qux'))); + * + * One could access nested properties using dot notation: + * + * {{%DOT-NOTATION}}{{foo.bar.baz}} + * + * Which would render as `qux`. + */ const PRAGMA_DOT_NOTATION = 'DOT-NOTATION'; + + /** + * The {{%IMPLICIT-ITERATOR}} pragma allows access to non-associative array data in an + * iterable section: + * + * $context = array('items' => array('foo', 'bar', 'baz')); + * + * With this template: + * + * {{%IMPLICIT-ITERATOR}}{{#items}}{{.}}{{/items}} + * + * Would render as `foobarbaz`. + * + * {{%IMPLICIT-ITERATOR}} accepts an optional 'iterator' argument which allows implicit + * iterator tags other than {{.}} ... + * + * {{%IMPLICIT-ITERATOR iterator=i}}{{#items}}{{i}}{{/items}} + */ const PRAGMA_IMPLICIT_ITERATOR = 'IMPLICIT-ITERATOR'; /**