Template sections as functions.

This creates DRYer output and shallower nested blocks in compiled templates.
This commit is contained in:
Justin Hileman
2012-03-05 17:56:43 -08:00
parent a196ac8dab
commit 628aa02f05
+39 -21
View File
@@ -18,6 +18,9 @@ namespace Mustache;
*/ */
class Compiler { class Compiler {
private $sections;
private $source;
/** /**
* Compile a Mustache token parse tree into PHP source code. * Compile a Mustache token parse tree into PHP source code.
* *
@@ -28,7 +31,8 @@ class Compiler {
* @return string Generated PHP source code * @return string Generated PHP source code
*/ */
public function compile($source, array $tree, $name) { public function compile($source, array $tree, $name) {
$this->source = $source; $this->sections = array();
$this->source = $source;
return $this->writeCode($tree, $name); return $this->writeCode($tree, $name);
} }
@@ -106,12 +110,12 @@ class Compiler {
class %s extends \Mustache\Template { class %s extends \Mustache\Template {
public function renderInternal(\Mustache\Context $context, $indent = \'\') { public function renderInternal(\Mustache\Context $context, $indent = \'\') {
$mustache = $this->mustache; $buffer = new \Mustache\Buffer($indent, $this->mustache->getCharset());
$buffer = new \Mustache\Buffer($indent, $mustache->getCharset());
%s %s
return $buffer->flush(); return $buffer->flush();
} }
%s
}'; }';
/** /**
@@ -123,24 +127,32 @@ class Compiler {
* @return string Generated PHP source code * @return string Generated PHP source code
*/ */
private function writeCode($tree, $name) { private function writeCode($tree, $name) {
return sprintf($this->prepare(self::KLASS, 0, false), $name, $this->walk($tree), $name); $code = $this->walk($tree);
$sections = implode("\n", $this->sections);
return sprintf($this->prepare(self::KLASS, 0, false), $name, $code, $sections);
} }
const SECTION = ' const SECTION_CALL = '
// %s section // %s section
$value = $context->%s(%s); $this->section%s($buffer, $context, $context->%s(%s));
if ($context->isCallable($value)) { ';
$source = %s;
$buffer->write( const SECTION = '
$mustache private function section%s(\Mustache\Buffer $buffer, \Mustache\Context $context, $value) {
->loadLambda((string) call_user_func($value, $source)%s) if ($context->isCallable($value)) {
->renderInternal($context, $buffer->getIndent()) $source = %s;
); $buffer->write(
} elseif ($context->isTruthy($value)) { $this->mustache
$values = $context->isIterable($value) ? $value : array($value); ->loadLambda((string) call_user_func($value, $source)%s)
foreach ($values as $value) { ->renderInternal($context, $buffer->getIndent())
$context->push($value);%s );
$context->pop(); } elseif ($context->isTruthy($value)) {
$values = $context->isIterable($value) ? $value : array($value);
foreach ($values as $value) {
$context->push($value);%s
$context->pop();
}
} }
}'; }';
@@ -168,7 +180,13 @@ class Compiler {
$delims = ''; $delims = '';
} }
return sprintf($this->prepare(self::SECTION, $level), $id, $method, $id, $source, $delims, $this->walk($nodes, $level + 1)); $key = ucfirst(md5($delims."\n".$source));
if (!isset($this->sections[$key])) {
$this->sections[$key] = sprintf($this->prepare(self::SECTION), $key, $source, $delims, $this->walk($nodes, 2));
}
return sprintf($this->prepare(self::SECTION_CALL, $level), $id, $key, $method, $id);
} }
const INVERTED_SECTION = ' const INVERTED_SECTION = '
@@ -193,7 +211,7 @@ class Compiler {
return sprintf($this->prepare(self::INVERTED_SECTION, $level), $id, $method, $id, $this->walk($nodes, $level)); return sprintf($this->prepare(self::INVERTED_SECTION, $level), $id, $method, $id, $this->walk($nodes, $level));
} }
const PARTIAL = '$buffer->write($mustache->loadPartial(%s)->renderInternal($context, %s));'; const PARTIAL = '$buffer->write($this->mustache->loadPartial(%s)->renderInternal($context, %s));';
/** /**
* Generate Mustache Template partial call PHP source. * Generate Mustache Template partial call PHP source.
@@ -215,7 +233,7 @@ class Compiler {
const VARIABLE = ' const VARIABLE = '
$value = $context->%s(%s); $value = $context->%s(%s);
if ($context->isCallable($value)) { if ($context->isCallable($value)) {
$value = $mustache $value = $this->mustache
->loadLambda((string) call_user_func($value)) ->loadLambda((string) call_user_func($value))
->renderInternal($context, $buffer->getIndent()); ->renderInternal($context, $buffer->getIndent());
} }