Skip to content

Commit

Permalink
Merge branch 'dev' into feature/pragma-dot-notation
Browse files Browse the repository at this point in the history
  • Loading branch information
bobthecow committed Apr 27, 2010
2 parents f5b4c7d + 6350e61 commit f0d171a
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 19 deletions.
35 changes: 24 additions & 11 deletions Mustache.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ protected function _render($template, &$context) {
}

/**
* Render boolean and enumerable sections.
* Render boolean, enumerable and inverted sections.
*
* @access protected
* @param string $template
Expand All @@ -120,23 +120,36 @@ protected function renderSection($template, &$context) {

$otag = $this->prepareRegEx($this->otag);
$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();
while (preg_match($regex, $template, $matches, PREG_OFFSET_CAPTURE)) {
$section = $matches[0][0];
$offset = $matches[0][1];
$tag_name = trim($matches[1][0]);
$content = $matches[2][0];
$type = $matches[1][0];
$tag_name = trim($matches[2][0]);
$content = $matches[3][0];

$replace = '';
$val = $this->getVariable($tag_name, $context);
if (is_array($val)) {
foreach ($val as $local_context) {
$replace .= $this->_render($content, $this->getContext($context, $local_context));
}
} else if ($val) {
$replace .= $content;
switch($type) {
// inverted section
case '^':
if (empty($val)) {
$replace .= $content;
}
break;

// regular section
case '#':
if (is_array($val)) {
foreach ($val as $local_context) {
$replace .= $this->_render($content, $this->getContext($context, $local_context));
}
} else if ($val) {
$replace .= $content;
}
break;
}

$template = substr_replace($template, $replace, $offset, strlen($section));
Expand Down Expand Up @@ -293,7 +306,7 @@ protected function changeDelimiter($tag_name, &$context) {

$otag = $this->prepareRegEx($this->otag);
$ctag = $this->prepareRegEx($this->ctag);
$this->tagRegEx = '/' . $otag . "(#|\/|=|!|>|\\{|&)?([^\/#]+?)\\1?" . $ctag . "+/";
$this->tagRegEx = '/' . $otag . "(#|\/|=|!|>|\\{|&)?([^\/#\^]+?)\\1?" . $ctag . "+/";
return '';
}

Expand Down
1 change: 0 additions & 1 deletion README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ Known Issues

* There's no way to toggle a pragma other than checking out the feature branch for each pragma... Need a clean way to do this.
* Sections don't respect delimiter changes -- `delimiters` example currently fails with an "unclosed section" exception.
* 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).
* Test coverage is incomplete.


Expand Down
4 changes: 2 additions & 2 deletions examples/complex/complex.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
{{#current}}
<li><strong>{{name}}</strong></li>
{{/current}}
{{#isLink}}
{{^current}}
<li><a href="{{url}}">{{name}}</a></li>
{{/isLink}}
{{/current}}
{{/item}}
</ul>
{{/notEmpty}}
Expand Down
5 changes: 0 additions & 5 deletions examples/complex/complex.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ class Complex extends Mustache {
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() {
return !($this->isEmpty());
}
Expand Down
5 changes: 5 additions & 0 deletions examples/inverted_section/InvertedSection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

class InvertedSection extends Mustache {
public $repo = array();
}
2 changes: 2 additions & 0 deletions examples/inverted_section/inverted_section.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{{#repo}}<b>{{name}}</b>{{/repo}}
{{^repo}}No repos :({{/repo}}
1 change: 1 addition & 0 deletions examples/inverted_section/inverted_section.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
No repos :(
110 changes: 110 additions & 0 deletions test/MustacheTest.php
Original file line number Diff line number Diff line change
@@ -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;
}
}

0 comments on commit f0d171a

Please sign in to comment.