From 367013f01c8c936062684865a8f3c72d321fdb33 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Tue, 13 Mar 2012 23:45:33 -0700 Subject: [PATCH] 2x faster. Who needs a Buffer instance, anyway? --- src/Mustache/Buffer.php | 138 ---------------------------- src/Mustache/Compiler.php | 38 ++++---- src/Mustache/Template.php | 2 +- test/Mustache/Test/BufferTest.php | 99 -------------------- test/Mustache/Test/CompilerTest.php | 16 ++-- test/Mustache/Test/TemplateTest.php | 2 +- 6 files changed, 32 insertions(+), 263 deletions(-) delete mode 100644 src/Mustache/Buffer.php delete mode 100644 test/Mustache/Test/BufferTest.php diff --git a/src/Mustache/Buffer.php b/src/Mustache/Buffer.php deleted file mode 100644 index 7344b10..0000000 --- a/src/Mustache/Buffer.php +++ /dev/null @@ -1,138 +0,0 @@ -setIndent($indent); - } - - if ($charset !== null) { - $this->charset = $charset; - } - } - - /** - * Get the current indent level. - * - * @return string - */ - public function getIndent() { - return $this->indent; - } - - /** - * Set the buffer indent level. - * - * Each line output by this buffer will be prefixed by this whitespace. This is used when rendering - * partials and Lambda sections. - * - * @param string $indent - */ - public function setIndent($indent) { - $this->indent = $indent; - } - - /** - * Get the character set used when escaping values. - * - * @return string - */ - public function getCharset() { - return $this->charset; - } - - /** - * Write a newline to the Buffer. - */ - public function writeLine() { - $this->buffer .= "\n"; - } - - /** - * Output text to the Buffer. - * - * @see \Mustache\Buffer::write - * - * @param string $text - * @param bool $escape Escape this text with `htmlspecialchars()`? (default: false) - */ - public function writeText($text, $escape = false) { - $this->write($text, true, $escape); - } - - /** - * Add output to the Buffer. - * - * @param string $text - * @param bool $indent Indent this line? (default: false) - * @param bool $escape Escape this text with `htmlspecialchars()`? (default: false) - */ - public function write($text, $indent = false, $escape = false) { - $text = (string) $text; - - if ($escape) { - $text = $this->escape($text); - } - - if ($indent) { - $this->buffer .= $this->indent . $text; - } else { - $this->buffer .= $text; - } - } - - /** - * Flush the contents of the Buffer. - * - * Resets the buffer and returns the current contents. - * - * @return string - */ - public function flush() { - $buffer = $this->buffer; - $this->buffer = ''; - - return $buffer; - } - - /** - * Helper function to escape text. - * - * Uses the Buffer's character set (default 'UTF-8', passed as the second argument to `__construct`). - * - * @see htmlspecialchars - * - * @param string $text - * - * @return string Escaped text - */ - private function escape($text) { - return htmlspecialchars($text, ENT_COMPAT, $this->charset); - } -} diff --git a/src/Mustache/Compiler.php b/src/Mustache/Compiler.php index 4817299..bfe53f7 100644 --- a/src/Mustache/Compiler.php +++ b/src/Mustache/Compiler.php @@ -109,11 +109,15 @@ class Compiler { const KLASS = 'mustache->getCharset()); + public function renderInternal(\Mustache\Context $context, $indent = \'\', $escape = false) { + $buffer = \'\'; %s - return $buffer->flush(); + if ($escape) { + return htmlspecialchars($buffer, ENT_COMPAT, $this->mustache->getCharset()); + } + + return $buffer; } %s }'; @@ -135,18 +139,17 @@ class Compiler { const SECTION_CALL = ' // %s section - $this->section%s($buffer, $context, $context->%s(%s)); + $buffer .= $this->section%s($context, $indent, $context->%s(%s)); '; const SECTION = ' - private function section%s(\Mustache\Buffer $buffer, \Mustache\Context $context, $value) { + private function section%s(\Mustache\Context $context, $indent, $value) { + $buffer = \'\'; if (!is_string($value) && is_callable($value)) { $source = %s; - $buffer->write( - $this->mustache - ->loadLambda((string) call_user_func($value, $source)%s) - ->renderInternal($context, $buffer->getIndent()) - ); + $buffer .= $this->mustache + ->loadLambda((string) call_user_func($value, $source)%s) + ->renderInternal($context, $indent); } elseif (!empty($value)) { $values = $this->isIterable($value) ? $value : array($value); foreach ($values as $value) { @@ -154,6 +157,8 @@ class Compiler { $context->pop(); } } + + return $buffer; }'; /** @@ -212,7 +217,7 @@ class Compiler { return sprintf($this->prepare(self::INVERTED_SECTION, $level), $id, $method, $id, $this->walk($nodes, $level)); } - const PARTIAL = '$buffer->write($this->mustache->loadPartial(%s)->renderInternal($context, %s));'; + const PARTIAL = '$buffer .= $this->mustache->loadPartial(%s)->renderInternal($context, %s);'; /** * Generate Mustache Template partial call PHP source. @@ -236,10 +241,11 @@ class Compiler { if (!is_string($value) && is_callable($value)) { $value = $this->mustache ->loadLambda((string) call_user_func($value)) - ->renderInternal($context, $buffer->getIndent()); + ->renderInternal($context, $indent); } - $buffer->writeText($value, %s); + $buffer .= $indent . %s; '; + const VARIABLE_ESCAPED = 'htmlspecialchars($value, ENT_COMPAT, $this->mustache->getCharset())'; /** * Generate Mustache Template variable interpolation PHP source. @@ -253,13 +259,13 @@ class Compiler { private function variable($id, $escape, $level) { $method = $this->getFindMethod($id); $id = ($method !== 'last') ? var_export($id, true) : ''; - $escape = $escape ? 'true' : 'false'; + $escape = $escape ? self::VARIABLE_ESCAPED : '$value'; return sprintf($this->prepare(self::VARIABLE, $level), $method, $id, $escape); } - const LINE = '$buffer->writeLine();'; - const TEXT = '$buffer->writeText(%s);'; + const LINE = '$buffer .= "\n";'; + const TEXT = '$buffer .= $indent . %s;'; /** * Generate Mustache Template output Buffer call PHP source. diff --git a/src/Mustache/Template.php b/src/Mustache/Template.php index c787e47..b3286f8 100644 --- a/src/Mustache/Template.php +++ b/src/Mustache/Template.php @@ -71,7 +71,7 @@ abstract class Template { * * @return string Rendered template */ - abstract public function renderInternal(Context $context); + abstract public function renderInternal(Context $context, $indent = '', $escape = false); /** * Tests whether a value should be iterated over (e.g. in a section context). diff --git a/test/Mustache/Test/BufferTest.php b/test/Mustache/Test/BufferTest.php deleted file mode 100644 index 23feca4..0000000 --- a/test/Mustache/Test/BufferTest.php +++ /dev/null @@ -1,99 +0,0 @@ -assertEquals($indent, $buffer->getIndent()); - $this->assertEquals($charset, $buffer->getCharset()); - } - - public function getConstructorArgs() { - return array( - array('', 'UTF-8'), - array(' ', 'ISO-8859-1'), - array("\t\t\t", 'Shift_JIS'), - ); - } - - public function testWrite() { - $buffer = new Buffer; - $this->assertEquals('', $buffer->flush()); - - $buffer->writeLine(); - $buffer->writeLine(); - $buffer->writeLine(); - $this->assertEquals("\n\n\n", $buffer->flush()); - $this->assertEquals('', $buffer->flush()); - - $buffer->write('foo'); - $buffer->write('bar'); - $buffer->writeLine(); - $buffer->write('baz'); - $this->assertEquals("foobar\nbaz", $buffer->flush()); - $this->assertEquals('', $buffer->flush()); - - $indent = "\t\t"; - $buffer->setIndent($indent); - $buffer->writeText('foo'); - $buffer->writeLine(); - $buffer->writeText('bar'); - $this->assertEquals("\t\tfoo\n\t\tbar", $buffer->flush()); - $this->assertEquals('', $buffer->flush()); - } - - /** - * @dataProvider getEscapeAndIndent - */ - public function testEscapingAndIndenting($text, $escape, $indent, $whitespace, $expected) { - $buffer = new Buffer; - $buffer->setIndent($whitespace); - - $buffer->write($text, $indent, $escape); - $this->assertEquals($expected, $buffer->flush()); - } - - public function getEscapeAndIndent() { - return array( - array('> "fun & games" <', false, false, "\t", '> "fun & games" <'), - array('> "fun & games" <', true, false, "\t", '> "fun & games" <'), - array('> "fun & games" <', true, true, "\t", "\t> "fun & games" <"), - array('> "fun & games" <', false, true, "\t", "\t> \"fun & games\" <"), - ); - } - - public function testChangeIndent() { - $indent = "\t\t"; - $buffer = new Buffer($indent); - $this->assertEquals($indent, $buffer->getIndent()); - - $indent = ""; - $buffer->setIndent($indent); - $this->assertEquals($indent, $buffer->getIndent()); - - $indent = " "; - $buffer->setIndent($indent); - $this->assertEquals($indent, $buffer->getIndent()); - } - -} diff --git a/test/Mustache/Test/CompilerTest.php b/test/Mustache/Test/CompilerTest.php index 4afe7e4..e08fa45 100644 --- a/test/Mustache/Test/CompilerTest.php +++ b/test/Mustache/Test/CompilerTest.php @@ -35,13 +35,13 @@ class CompilerTest extends \PHPUnit_Framework_TestCase { return array( array('', array(), 'Banana', array( "\nclass Banana extends \Mustache\Template", - '$buffer->flush();', + 'return $buffer;', )), array('', array('TEXT'), 'Monkey', array( "\nclass Monkey extends \Mustache\Template", - '$buffer->writeText(\'TEXT\');', - '$buffer->flush();', + '$buffer .= $indent . \'TEXT\';', + 'return $buffer;', )), array( @@ -62,13 +62,13 @@ class CompilerTest extends \PHPUnit_Framework_TestCase { 'Monkey', array( "\nclass Monkey extends \Mustache\Template", - '$buffer->writeText(\'foo\');', - '$buffer->writeLine();', + '$buffer .= $indent . \'foo\'', + '$buffer .= "\n"', '$value = $context->find(\'name\');', - '$buffer->writeText($value, true);', + '$buffer .= $indent . htmlspecialchars($value, ENT_COMPAT, $this->mustache->getCharset());', '$value = $context->last();', - '$buffer->writeText(\'\\\'bar\\\'\');', - '$buffer->flush();', + '$buffer .= $indent . \'\\\'bar\\\'\';', + 'return $buffer;', ) ), ); diff --git a/test/Mustache/Test/TemplateTest.php b/test/Mustache/Test/TemplateTest.php index 42ad2c5..8b24267 100644 --- a/test/Mustache/Test/TemplateTest.php +++ b/test/Mustache/Test/TemplateTest.php @@ -46,7 +46,7 @@ class TemplateStub extends Template { return $this->mustache; } - public function renderInternal(Context $context) { + public function renderInternal(Context $context, $indent = '', $escape = false) { return $this->rendered; } }