瀏覽代碼

Higher order functions, see: http://bit.ly/9s0dO4

Justin Hileman 15 年之前
父節點
當前提交
60d593dcab
共有 2 個文件被更改,包括 134 次插入11 次删除
  1. 17 11
      Mustache.php
  2. 117 0
      test/MustacheHigherOrderSectionsTest.php

+ 17 - 11
Mustache.php

@@ -188,19 +188,25 @@ class Mustache {
 
 				// regular section
 				case '#':
-					if ($this->_varIsIterable($val)) {
-						foreach ($val as $local_context) {
-							$this->_pushContext($local_context);
+					if ($val) {
+						// higher order sections
+						if (is_callable($val)) {
+							$content = call_user_func($val, $content);
 							$replace .= $this->_renderTemplate($content);
-							$this->_popContext();
-						}
-					} else if ($val) {
-						if (is_array($val) || is_object($val)) {
-							$this->_pushContext($val);
-							$replace .= $this->_renderTemplate($content);
-							$this->_popContext();
+						} else if ($this->_varIsIterable($val)) {
+							foreach ($val as $local_context) {
+								$this->_pushContext($local_context);
+								$replace .= $this->_renderTemplate($content);
+								$this->_popContext();
+							}
 						} else {
-							$replace .= $content;
+							if (is_array($val) || is_object($val)) {
+								$this->_pushContext($val);
+								$replace .= $this->_renderTemplate($content);
+								$this->_popContext();
+							} else {
+								$replace .= $content;
+							}
 						}
 					}
 					break;

+ 117 - 0
test/MustacheHigherOrderSectionsTest.php

@@ -0,0 +1,117 @@
+<?php
+
+require_once '../Mustache.php';
+
+class MustacheHigherOrderSectionsTest extends PHPUnit_Framework_TestCase {
+
+	public function setUp() {
+		$this->foo = new Foo();
+	}
+
+	public function testAnonymousFunctionSectionCallback() {
+		if (version_compare(PHP_VERSION, '5.3.0', '<')) {
+			$this->markTestSkipped('Unable to test anonymous function section callbacks in PHP < 5.3');
+			return;
+		}
+
+		$this->foo->wrapper = function($text) {
+			return sprintf('<div class="anonymous">%s</div>', $text);
+		};
+
+		$this->assertEquals(
+			sprintf('<div class="anonymous">%s</div>', $this->foo->name),
+			$this->foo->render('{{#wrapper}}{{name}}{{/wrapper}}')
+		);
+	}
+
+	public function testSectionCallback() {
+		$this->assertEquals(sprintf('%s', $this->foo->name), $this->foo->render('{{name}}'));
+		$this->assertEquals(sprintf('<em>%s</em>', $this->foo->name), $this->foo->render('{{#wrap}}{{name}}{{/wrap}}'));
+	}
+
+	public function testRuntimeSectionCallback() {
+		$this->foo->double_wrap = array($this->foo, 'wrapWithBoth');
+		$this->assertEquals(
+			sprintf('<strong><em>%s</em></strong>', $this->foo->name),
+			$this->foo->render('{{#double_wrap}}{{name}}{{/double_wrap}}')
+		);
+	}
+
+	public function testFunctionSectionCallback() {
+		$this->foo->wrapper = 'make_my_logo_bigger';
+		$this->assertEquals(
+			sprintf('<h1>%s</h1>', $this->foo->name),
+			$this->foo->render('{{#wrapper}}{{name}}{{/wrapper}}')
+		);
+	}
+
+	public function testStaticSectionCallback() {
+		$this->foo->trimmer = array(get_class($this->foo), 'staticTrim');
+		$this->assertEquals($this->foo->name, $this->foo->render('{{#trimmer}}    {{name}}    {{/trimmer}}'));
+
+		$this->foo->trimmer = 'Foo::staticTrim';
+		$this->assertEquals($this->foo->lorem, $this->foo->render('{{#trimmer}}    {{lorem}}    {{/trimmer}}'));
+	}
+
+	public function testViewArraySectionCallback() {
+		$data = array(
+			'name' => 'Bob',
+			'wrap' => 'make_my_logo_bigger',
+			'trim' => array(get_class($this->foo), 'staticTrim'),
+		);
+		$this->assertEquals(
+			sprintf('<h1>%s</h1>', $data['name']),
+			$this->foo->render('{{#wrap}}{{name}}{{/wrap}}', $data)
+		);
+		$this->assertEquals($data['name'], $this->foo->render('{{#trim}}    {{name}}    {{/trim}}', $data));
+	}
+
+	public function testViewArrayAnonymousSectionCallback() {
+		if (version_compare(PHP_VERSION, '5.3.0', '<')) {
+			$this->markTestSkipped('Unable to test anonymous function section callbacks in PHP < 5.3');
+			return;
+		}
+		$data = array(
+			'name' => 'Bob',
+			'wrap' => 'make_my_logo_bigger',
+			'anonywrap' => function($text) {
+				return array('[[%s]]', $text);
+			}
+		);
+		$this->assertEquals(
+			sprintf('<h1>%s</h1>', $data['name']),
+			$this->foo->render('{{#wrap}}{{name}}{{/wrap}}', $data)
+		);
+	}
+}
+
+class Foo extends Mustache {
+	public $name = 'Justin';
+	public $lorem = 'Lorem ipsum dolor sit amet,';
+	public $wrap;
+
+	public function __construct($template = null, $view = null, $partials = null) {
+		$this->wrap = array($this, 'wrapWithEm');
+		parent::__construct($template, $view, $partials);
+	}
+
+	public function wrapWithEm($text) {
+		return sprintf('<em>%s</em>', $text);
+	}
+
+	public function wrapWithStrong($text) {
+		return sprintf('<strong>%s</strong>', $text);
+	}
+
+	public function wrapWithBoth($text) {
+		return self::wrapWithStrong(self::wrapWithEm($text));
+	}
+	
+	public static function staticTrim($text) {
+		return trim($text);
+	}
+}
+
+function make_my_logo_bigger($text) {
+	return sprintf('<h1>%s</h1>', $text);
+}