Merge branch 'release/0.1'
Conflicts: examples/complex/complex.php
This commit is contained in:
+18
-5
@@ -106,7 +106,7 @@ class Mustache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render boolean and enumerable sections.
|
* Render boolean, enumerable and inverted sections.
|
||||||
*
|
*
|
||||||
* @access protected
|
* @access protected
|
||||||
* @param string $template
|
* @param string $template
|
||||||
@@ -120,17 +120,28 @@ class Mustache {
|
|||||||
|
|
||||||
$otag = $this->prepareRegEx($this->otag);
|
$otag = $this->prepareRegEx($this->otag);
|
||||||
$ctag = $this->prepareRegEx($this->ctag);
|
$ctag = $this->prepareRegEx($this->ctag);
|
||||||
$regex = '/' . $otag . '\\#(.+?)' . $ctag . '\\s*([\\s\\S]+?)' . $otag . '\\/\\1' . $ctag . '\\s*/m';
|
$regex = '/' . $otag . '(\\^|\\#)(.+?)' . $ctag . '\\s*([\\s\\S]+?)' . $otag . '\\/\\2' . $ctag . '\\s*/m';
|
||||||
|
|
||||||
$matches = array();
|
$matches = array();
|
||||||
while (preg_match($regex, $template, $matches, PREG_OFFSET_CAPTURE)) {
|
while (preg_match($regex, $template, $matches, PREG_OFFSET_CAPTURE)) {
|
||||||
$section = $matches[0][0];
|
$section = $matches[0][0];
|
||||||
$offset = $matches[0][1];
|
$offset = $matches[0][1];
|
||||||
$tag_name = trim($matches[1][0]);
|
$type = $matches[1][0];
|
||||||
$content = $matches[2][0];
|
$tag_name = trim($matches[2][0]);
|
||||||
|
$content = $matches[3][0];
|
||||||
|
|
||||||
$replace = '';
|
$replace = '';
|
||||||
$val = $this->getVariable($tag_name, $context);
|
$val = $this->getVariable($tag_name, $context);
|
||||||
|
switch($type) {
|
||||||
|
// inverted section
|
||||||
|
case '^':
|
||||||
|
if (empty($val)) {
|
||||||
|
$replace .= $content;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// regular section
|
||||||
|
case '#':
|
||||||
if (is_array($val)) {
|
if (is_array($val)) {
|
||||||
foreach ($val as $local_context) {
|
foreach ($val as $local_context) {
|
||||||
$replace .= $this->_render($content, $this->getContext($context, $local_context));
|
$replace .= $this->_render($content, $this->getContext($context, $local_context));
|
||||||
@@ -138,6 +149,8 @@ class Mustache {
|
|||||||
} else if ($val) {
|
} else if ($val) {
|
||||||
$replace .= $content;
|
$replace .= $content;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
$template = substr_replace($template, $replace, $offset, strlen($section));
|
$template = substr_replace($template, $replace, $offset, strlen($section));
|
||||||
}
|
}
|
||||||
@@ -293,7 +306,7 @@ class Mustache {
|
|||||||
|
|
||||||
$otag = $this->prepareRegEx($this->otag);
|
$otag = $this->prepareRegEx($this->otag);
|
||||||
$ctag = $this->prepareRegEx($this->ctag);
|
$ctag = $this->prepareRegEx($this->ctag);
|
||||||
$this->tagRegEx = '/' . $otag . "(#|\/|=|!|>|\\{|&)?([^\/#]+?)\\1?" . $ctag . "+/";
|
$this->tagRegEx = '/' . $otag . "(#|\/|=|!|>|\\{|&)?([^\/#\^]+?)\\1?" . $ctag . "+/";
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -81,8 +81,10 @@ And render it:
|
|||||||
Known Issues
|
Known Issues
|
||||||
------------
|
------------
|
||||||
|
|
||||||
* Sections don't respect delimiter changes -- `delimiters` example currently fails with an "unclosed section" exception.
|
* Sections don't respect delimiter changes -- `delimiters` example currently fails with an
|
||||||
* Since `complex` example emulates some fancy swizzling available in Ruby, it fails. Need to convert example to PHPisms (In PHP, Mustache class doesn't maintain current context stack -- available context is passed to methods via params).
|
"unclosed section" exception.
|
||||||
|
* Sections don't have access to child context, i.e. `{{#foo}}{{bar}}{{/foo}}` fails if the context
|
||||||
|
is `array('foo' => array('bar' => 'baz'));`
|
||||||
* Test coverage is incomplete.
|
* Test coverage is incomplete.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
{{#current}}
|
{{#current}}
|
||||||
<li><strong>{{name}}</strong></li>
|
<li><strong>{{name}}</strong></li>
|
||||||
{{/current}}
|
{{/current}}
|
||||||
{{#isLink}}
|
{{^current}}
|
||||||
<li><a href="{{url}}">{{name}}</a></li>
|
<li><a href="{{url}}">{{name}}</a></li>
|
||||||
{{/isLink}}
|
{{/current}}
|
||||||
{{/item}}
|
{{/item}}
|
||||||
</ul>
|
</ul>
|
||||||
{{/notEmpty}}
|
{{/notEmpty}}
|
||||||
|
|||||||
@@ -9,11 +9,6 @@ class Complex extends Mustache {
|
|||||||
array('name' => 'blue', 'current' => false, 'url' => '#Blue'),
|
array('name' => 'blue', 'current' => false, 'url' => '#Blue'),
|
||||||
);
|
);
|
||||||
|
|
||||||
public function isLink() {
|
|
||||||
// Exploit the fact that the current iteration item is at the top of the context stack.
|
|
||||||
return $this->getVariable('current', $this->context) != true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function notEmpty() {
|
public function notEmpty() {
|
||||||
return !($this->isEmpty());
|
return !($this->isEmpty());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class InvertedSection extends Mustache {
|
||||||
|
public $repo = array();
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
{{#repo}}<b>{{name}}</b>{{/repo}}
|
||||||
|
{{^repo}}No repos :({{/repo}}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
No repos :(
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once '../Mustache.php';
|
||||||
|
require_once 'PHPUnit/Framework.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A PHPUnit test case for Mustache.php.
|
||||||
|
*
|
||||||
|
* This is a very basic, very rudimentary unit test case. It's probably more important to have tests
|
||||||
|
* than to have elegant tests, so let's bear with it for a bit.
|
||||||
|
*
|
||||||
|
* This class assumes an example directory exists at `../examples` with the following structure:
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* examples
|
||||||
|
* foo
|
||||||
|
* Foo.php
|
||||||
|
* foo.mustache
|
||||||
|
* foo.txt
|
||||||
|
* bar
|
||||||
|
* Bar.php
|
||||||
|
* bar.mustache
|
||||||
|
* bar.txt
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* To use this test:
|
||||||
|
*
|
||||||
|
* 1. {@link http://www.phpunit.de/manual/current/en/installation.html Install PHPUnit}
|
||||||
|
* 2. run phpunit from the `test` directory:
|
||||||
|
* `phpunit MustacheTest`
|
||||||
|
* 3. Fix bugs. Lather, rinse, repeat.
|
||||||
|
*
|
||||||
|
* @extends PHPUnit_Framework_TestCase
|
||||||
|
*/
|
||||||
|
class MustacheTest extends PHPUnit_Framework_TestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test everything in the `examples` directory.
|
||||||
|
*
|
||||||
|
* @dataProvider getExamples
|
||||||
|
* @access public
|
||||||
|
* @param mixed $class
|
||||||
|
* @param mixed $template
|
||||||
|
* @param mixed $output
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testExamples($class, $template, $output) {
|
||||||
|
$m = new $class;
|
||||||
|
$this->assertEquals($output, $m->render($template));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data provider for testExamples method.
|
||||||
|
*
|
||||||
|
* Assumes that an `examples` directory exists inside parent directory.
|
||||||
|
* This examples directory should contain any number of subdirectories, each of which contains
|
||||||
|
* three files: one Mustache class (.php), one Mustache template (.mustache), and one output file
|
||||||
|
* (.txt).
|
||||||
|
*
|
||||||
|
* This whole mess will be refined later to be more intuitive and less prescriptive, but it'll
|
||||||
|
* do for now. Especially since it means we can have unit tests :)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getExamples() {
|
||||||
|
$basedir = dirname(__FILE__) . '/../examples/';
|
||||||
|
|
||||||
|
$ret = array();
|
||||||
|
|
||||||
|
$files = new RecursiveDirectoryIterator($basedir);
|
||||||
|
while ($files->valid()) {
|
||||||
|
|
||||||
|
if ($files->hasChildren() && $children = $files->getChildren()) {
|
||||||
|
$example = $files->getSubPathname();
|
||||||
|
$class = null;
|
||||||
|
$template = null;
|
||||||
|
$output = null;
|
||||||
|
|
||||||
|
foreach ($children as $file) {
|
||||||
|
if (!$file->isFile()) continue;
|
||||||
|
|
||||||
|
$filename = $file->getPathInfo();
|
||||||
|
$info = pathinfo($filename);
|
||||||
|
|
||||||
|
switch($info['extension']) {
|
||||||
|
case 'php':
|
||||||
|
$class = $info['filename'];
|
||||||
|
include_once($filename);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'mustache':
|
||||||
|
$template = file_get_contents($filename);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'txt':
|
||||||
|
$output = file_get_contents($filename);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$ret[$example] = array($class, $template, $output);
|
||||||
|
}
|
||||||
|
|
||||||
|
$files->next();
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user