diff --git a/composer.json b/composer.json index 388a940..f2ba0f9 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "php": ">=5.2.4" }, "require-dev": { - "phpunit/phpunit": "~3.7|~4.0", + "phpunit/phpunit": "~3.7|~4.0|~5.0", "fabpot/php-cs-fixer": "~1.6" }, "autoload": { diff --git a/src/Mustache/Compiler.php b/src/Mustache/Compiler.php index 7d5c96b..76e580c 100644 --- a/src/Mustache/Compiler.php +++ b/src/Mustache/Compiler.php @@ -328,7 +328,7 @@ class Mustache_Compiler $buffer = \'\'; if (%s) { $source = %s; - $result = call_user_func($value, $source, $this->lambdaHelper); + $result = call_user_func($value, $source, %s); if (strpos($result, \'{{\') === false) { $buffer .= $result; } else { @@ -370,15 +370,18 @@ class Mustache_Compiler $callable = $this->getCallable(); if ($otag !== '{{' || $ctag !== '}}') { - $delims = ', ' . var_export(sprintf('{{= %s %s =}}', $otag, $ctag), true); + $delimTag = var_export(sprintf('{{= %s %s =}}', $otag, $ctag), true); + $helper = sprintf('$this->lambdaHelper->withDelimiters(%s)', $delimTag); + $delims = ', ' . $delimTag; } else { + $helper = '$this->lambdaHelper'; $delims = ''; } $key = ucfirst(md5($delims . "\n" . $source)); if (!isset($this->sections[$key])) { - $this->sections[$key] = sprintf($this->prepare(self::SECTION), $key, $callable, $source, $delims, $this->walk($nodes, 2)); + $this->sections[$key] = sprintf($this->prepare(self::SECTION), $key, $callable, $source, $helper, $delims, $this->walk($nodes, 2)); } if ($arg === true) { @@ -495,7 +498,7 @@ class Mustache_Compiler } const VARIABLE = ' - $value = $this->resolveValue($context->%s(%s), $context, $indent);%s + $value = $this->resolveValue($context->%s(%s), $context);%s $buffer .= %s%s; '; diff --git a/src/Mustache/Engine.php b/src/Mustache/Engine.php index 08bcc81..fe11912 100644 --- a/src/Mustache/Engine.php +++ b/src/Mustache/Engine.php @@ -23,7 +23,7 @@ */ class Mustache_Engine { - const VERSION = '2.9.0'; + const VERSION = '2.10.0'; const SPEC_VERSION = '1.1.2'; const PRAGMA_FILTERS = 'FILTERS'; diff --git a/src/Mustache/LambdaHelper.php b/src/Mustache/LambdaHelper.php index de48fd6..cb8e966 100644 --- a/src/Mustache/LambdaHelper.php +++ b/src/Mustache/LambdaHelper.php @@ -20,17 +20,20 @@ class Mustache_LambdaHelper { private $mustache; private $context; + private $delims; /** * Mustache Lambda Helper constructor. * * @param Mustache_Engine $mustache Mustache engine instance. * @param Mustache_Context $context Rendering context. + * @param string $delims Optional custom delimiters, in the format `{{= <% %> =}}`. (default: null) */ - public function __construct(Mustache_Engine $mustache, Mustache_Context $context) + public function __construct(Mustache_Engine $mustache, Mustache_Context $context, $delims = null) { $this->mustache = $mustache; $this->context = $context; + $this->delims = $delims; } /** @@ -43,7 +46,31 @@ class Mustache_LambdaHelper public function render($string) { return $this->mustache - ->loadLambda((string) $string) + ->loadLambda((string) $string, $this->delims) ->renderInternal($this->context); } + + /** + * Render a string as a Mustache template with the current rendering context. + * + * @param string $string + * + * @return string Rendered template + */ + public function __invoke($string) + { + return $this->render($string); + } + + /** + * Get a Lambda Helper with custom delimiters. + * + * @param string $delims Custom delimiters, in the format `{{= <% %> =}}`. + * + * @return Mustache_LambdaHelper + */ + public function withDelimiters($delims) + { + return new self($this->mustache, $this->context, $delims); + } } diff --git a/src/Mustache/Template.php b/src/Mustache/Template.php index 91074c4..f2d198f 100644 --- a/src/Mustache/Template.php +++ b/src/Mustache/Template.php @@ -164,16 +164,15 @@ abstract class Mustache_Template * * @param mixed $value * @param Mustache_Context $context - * @param string $indent * * @return string */ - protected function resolveValue($value, Mustache_Context $context, $indent = '') + protected function resolveValue($value, Mustache_Context $context) { if (($this->strictCallables ? is_object($value) : !is_string($value)) && is_callable($value)) { return $this->mustache ->loadLambda((string) call_user_func($value)) - ->renderInternal($context, $indent); + ->renderInternal($context); } return $value; diff --git a/test/Mustache/Test/CompilerTest.php b/test/Mustache/Test/CompilerTest.php index d981249..e11bd98 100644 --- a/test/Mustache/Test/CompilerTest.php +++ b/test/Mustache/Test/CompilerTest.php @@ -55,7 +55,7 @@ class Mustache_Test_CompilerTest extends PHPUnit_Framework_TestCase 'ISO-8859-1', array( "\nclass Monkey extends Mustache_Template", - '$value = $this->resolveValue($context->find(\'name\'), $context, $indent);', + '$value = $this->resolveValue($context->find(\'name\'), $context);', '$buffer .= $indent . call_user_func($this->mustache->getEscape(), $value);', 'return $buffer;', ), @@ -75,7 +75,7 @@ class Mustache_Test_CompilerTest extends PHPUnit_Framework_TestCase 'ISO-8859-1', array( "\nclass Monkey extends Mustache_Template", - '$value = $this->resolveValue($context->find(\'name\'), $context, $indent);', + '$value = $this->resolveValue($context->find(\'name\'), $context);', '$buffer .= $indent . htmlspecialchars($value, ' . ENT_COMPAT . ', \'ISO-8859-1\');', 'return $buffer;', ), @@ -95,7 +95,7 @@ class Mustache_Test_CompilerTest extends PHPUnit_Framework_TestCase 'ISO-8859-1', array( "\nclass Monkey extends Mustache_Template", - '$value = $this->resolveValue($context->find(\'name\'), $context, $indent);', + '$value = $this->resolveValue($context->find(\'name\'), $context);', '$buffer .= $indent . htmlspecialchars($value, ' . ENT_QUOTES . ', \'ISO-8859-1\');', 'return $buffer;', ), @@ -122,9 +122,9 @@ class Mustache_Test_CompilerTest extends PHPUnit_Framework_TestCase array( "\nclass Monkey extends Mustache_Template", "\$buffer .= \$indent . 'foo\n';", - '$value = $this->resolveValue($context->find(\'name\'), $context, $indent);', + '$value = $this->resolveValue($context->find(\'name\'), $context);', '$buffer .= htmlspecialchars($value, ' . ENT_COMPAT . ', \'UTF-8\');', - '$value = $this->resolveValue($context->last(), $context, $indent);', + '$value = $this->resolveValue($context->last(), $context);', '$buffer .= \'\\\'bar\\\'\';', 'return $buffer;', ), diff --git a/test/Mustache/Test/FiveThree/Functional/LambdaHelperTest.php b/test/Mustache/Test/FiveThree/Functional/LambdaHelperTest.php index fcc1cd9..48f2465 100644 --- a/test/Mustache/Test/FiveThree/Functional/LambdaHelperTest.php +++ b/test/Mustache/Test/FiveThree/Functional/LambdaHelperTest.php @@ -36,4 +36,32 @@ class Mustache_Test_FiveThree_Functional_LambdaHelperTest extends PHPUnit_Framew $this->assertEquals('Mario', $one->render($foo)); $this->assertEquals('MARIO', $two->render($foo)); } + + public function testSectionLambdaHelperRespectsDelimiterChanges() + { + $tpl = $this->mustache->loadTemplate("{{=<% %>=}}\n<%# bang %><% value %><%/ bang %>"); + + $data = new StdClass(); + $data->value = 'hello world'; + $data->bang = function ($text, $mustache) { + return $mustache->render($text) . '!'; + }; + + $this->assertEquals('hello world!', $tpl->render($data)); + } + + public function testLambdaHelperIsInvokable() + { + $one = $this->mustache->loadTemplate('{{name}}'); + $two = $this->mustache->loadTemplate('{{#lambda}}{{name}}{{/lambda}}'); + + $foo = new StdClass(); + $foo->name = 'Mario'; + $foo->lambda = function ($text, $render) { + return strtoupper($render($text)); + }; + + $this->assertEquals('Mario', $one->render($foo)); + $this->assertEquals('MARIO', $two->render($foo)); + } } diff --git a/test/Mustache/Test/FiveThree/Functional/PartialLambdaIndentTest.php b/test/Mustache/Test/FiveThree/Functional/PartialLambdaIndentTest.php index 1ed93b6..8fcfc04 100644 --- a/test/Mustache/Test/FiveThree/Functional/PartialLambdaIndentTest.php +++ b/test/Mustache/Test/FiveThree/Functional/PartialLambdaIndentTest.php @@ -33,6 +33,36 @@ EOS; +EOS; + + $m = new Mustache_Engine(array( + 'partials' => array('input' => $partial), + )); + + $tpl = $m->loadTemplate($src); + + $data = new Mustache_Test_FiveThree_Functional_ClassWithLambda(); + $this->assertEquals($expected, $tpl->render($data)); + } + + public function testLambdaInterpolationsInsidePartialsAreIndentedProperly() + { + $src = << + {{> input }} + + +EOS; + $partial = << + +EOS; + + $expected = << + + + EOS; $m = new Mustache_Engine(array( @@ -54,4 +84,11 @@ class Mustache_Test_FiveThree_Functional_ClassWithLambda return strtoupper($val); }; } + + public function placeholder() + { + return function () { + return 'Enter your name'; + }; + } }