Merge pull request #91 from bobthecow/feature/psr-1

Update 2.0-dev to match the (proposed) PSR-1 coding style
This commit is contained in:
Justin Hileman
2012-05-01 22:20:54 -07:00
57 changed files with 3283 additions and 3009 deletions
+33 -33
View File
@@ -38,10 +38,10 @@ define('EXAMPLE_PATH', realpath(dirname(__FILE__) . '/../test/fixtures/examples'
* @return string * @return string
*/ */
function getLowerCaseName($name) { function getLowerCaseName($name) {
return preg_replace_callback("/([A-Z])/", create_function ( return preg_replace_callback("/([A-Z])/", create_function (
'$match', '$match',
'return "_" . strtolower($match[1]);' 'return "_" . strtolower($match[1]);'
), lcfirst($name)); ), lcfirst($name));
} }
/** /**
@@ -57,10 +57,10 @@ function getLowerCaseName($name) {
* @return string * @return string
*/ */
function getUpperCaseName($name) { function getUpperCaseName($name) {
return preg_replace_callback("/_([a-z])/", create_function ( return preg_replace_callback("/_([a-z])/", create_function (
'$match', '$match',
'return strtoupper($match{1});' 'return strtoupper($match{1});'
), ucfirst($name)); ), ucfirst($name));
} }
@@ -72,8 +72,8 @@ function getUpperCaseName($name) {
* @return mixed * @return mixed
*/ */
function out($value) { function out($value) {
echo $value . "\n"; echo $value . "\n";
return $value; return $value;
} }
/** /**
@@ -89,8 +89,8 @@ function out($value) {
* @return string * @return string
*/ */
function buildPath($directory, $filename = null, $extension = null) { function buildPath($directory, $filename = null, $extension = null) {
return out(EXAMPLE_PATH . '/' . $directory. return out(EXAMPLE_PATH . '/' . $directory.
($extension !== null && $filename !== null ? '/' . $filename. "." . $extension : "")); ($extension !== null && $filename !== null ? '/' . $filename. "." . $extension : ""));
} }
/** /**
@@ -102,9 +102,9 @@ function buildPath($directory, $filename = null, $extension = null) {
* @return void * @return void
*/ */
function createDirectory($directory) { function createDirectory($directory) {
if(!@mkdir(buildPath($directory))) { if(!@mkdir(buildPath($directory))) {
die("FAILED to create directory\n"); die("FAILED to create directory\n");
} }
} }
/** /**
@@ -119,13 +119,13 @@ function createDirectory($directory) {
* @return void * @return void
*/ */
function createFile($directory, $filename, $extension, $content = "") { function createFile($directory, $filename, $extension, $content = "") {
$handle = @fopen(buildPath($directory, $filename, $extension), "w"); $handle = @fopen(buildPath($directory, $filename, $extension), "w");
if($handle) { if($handle) {
fwrite($handle, $content); fwrite($handle, $content);
fclose($handle); fclose($handle);
} else { } else {
die("FAILED to create file\n"); die("FAILED to create file\n");
} }
} }
@@ -143,12 +143,12 @@ function createFile($directory, $filename, $extension, $content = "") {
* @return void * @return void
*/ */
function main($example_name) { function main($example_name) {
$lowercase = getLowerCaseName($example_name); $lowercase = getLowerCaseName($example_name);
$uppercase = getUpperCaseName($example_name); $uppercase = getUpperCaseName($example_name);
createDirectory($lowercase); createDirectory($lowercase);
createFile($lowercase, $lowercase, "mustache"); createFile($lowercase, $lowercase, "mustache");
createFile($lowercase, $lowercase, "txt"); createFile($lowercase, $lowercase, "txt");
createFile($lowercase, $uppercase, "php", <<<CONTENT createFile($lowercase, $uppercase, "php", <<<CONTENT
<?php <?php
class {$uppercase} { class {$uppercase} {
@@ -156,16 +156,16 @@ class {$uppercase} {
} }
CONTENT CONTENT
); );
} }
// check if enougth arguments are given // check if enougth arguments are given
if(count($argv) > 1) { if(count($argv) > 1) {
// get the name of the example // get the name of the example
$example_name = $argv[1]; $example_name = $argv[1];
main($example_name); main($example_name);
} else { } else {
echo USAGE; echo USAGE;
} }
+47 -43
View File
@@ -12,54 +12,58 @@
/** /**
* Mustache class autoloader. * Mustache class autoloader.
*/ */
class Mustache_Autoloader { class Mustache_Autoloader
{
private $baseDir; private $baseDir;
/** /**
* Autoloader constructor. * Autoloader constructor.
* *
* @param string $baseDir Mustache library base directory (default: dirname(__FILE__).'/..') * @param string $baseDir Mustache library base directory (default: dirname(__FILE__).'/..')
*/ */
public function __construct($baseDir = null) { public function __construct($baseDir = null)
if ($baseDir === null) { {
$this->baseDir = dirname(__FILE__).'/..'; if ($baseDir === null) {
} else { $this->baseDir = dirname(__FILE__).'/..';
$this->baseDir = rtrim($baseDir, '/'); } else {
} $this->baseDir = rtrim($baseDir, '/');
} }
}
/** /**
* Register a new instance as an SPL autoloader. * Register a new instance as an SPL autoloader.
* *
* @param string $baseDir Mustache library base directory (default: dirname(__FILE__).'/..') * @param string $baseDir Mustache library base directory (default: dirname(__FILE__).'/..')
* *
* @return Mustache_Autoloader Registered Autoloader instance * @return Mustache_Autoloader Registered Autoloader instance
*/ */
static public function register($baseDir = null) { static public function register($baseDir = null)
$loader = new self($baseDir); {
spl_autoload_register(array($loader, 'autoload')); $loader = new self($baseDir);
spl_autoload_register(array($loader, 'autoload'));
return $loader; return $loader;
} }
/** /**
* Autoload Mustache classes. * Autoload Mustache classes.
* *
* @param string $class * @param string $class
*/ */
public function autoload($class) { public function autoload($class)
if ($class[0] === '\\') { {
$class = substr($class, 1); if ($class[0] === '\\') {
} $class = substr($class, 1);
}
if (strpos($class, 'Mustache') !== 0) { if (strpos($class, 'Mustache') !== 0) {
return; return;
} }
$file = sprintf('%s/%s.php', $this->baseDir, str_replace('_', '/', $class)); $file = sprintf('%s/%s.php', $this->baseDir, str_replace('_', '/', $class));
if (is_file($file)) { if (is_file($file)) {
require $file; require $file;
} }
} }
} }
+321 -306
View File
@@ -14,355 +14,370 @@
* *
* This class is responsible for turning a Mustache token parse tree into normal PHP source code. * This class is responsible for turning a Mustache token parse tree into normal PHP source code.
*/ */
class Mustache_Compiler { class Mustache_Compiler
{
private $sections; private $sections;
private $source; private $source;
private $indentNextLine; private $indentNextLine;
private $customEscape; private $customEscape;
private $charset; private $charset;
/** /**
* Compile a Mustache token parse tree into PHP source code. * Compile a Mustache token parse tree into PHP source code.
* *
* @param string $source Mustache Template source code * @param string $source Mustache Template source code
* @param string $tree Parse tree of Mustache tokens * @param string $tree Parse tree of Mustache tokens
* @param string $name Mustache Template class name * @param string $name Mustache Template class name
* *
* @return string Generated PHP source code * @return string Generated PHP source code
*/ */
public function compile($source, array $tree, $name, $customEscape = false, $charset = 'UTF-8') { public function compile($source, array $tree, $name, $customEscape = false, $charset = 'UTF-8')
$this->sections = array(); {
$this->source = $source; $this->sections = array();
$this->indentNextLine = true; $this->source = $source;
$this->customEscape = $customEscape; $this->indentNextLine = true;
$this->charset = $charset; $this->customEscape = $customEscape;
$this->charset = $charset;
return $this->writeCode($tree, $name); return $this->writeCode($tree, $name);
} }
/** /**
* Helper function for walking the Mustache token parse tree. * Helper function for walking the Mustache token parse tree.
* *
* @throws InvalidArgumentException upon encountering unknown token types. * @throws InvalidArgumentException upon encountering unknown token types.
* *
* @param array $tree Parse tree of Mustache tokens * @param array $tree Parse tree of Mustache tokens
* @param int $level (default: 0) * @param int $level (default: 0)
* *
* @return string Generated PHP source code; * @return string Generated PHP source code;
*/ */
private function walk(array $tree, $level = 0) { private function walk(array $tree, $level = 0)
$code = ''; {
$level++; $code = '';
foreach ($tree as $node) { $level++;
switch ($node[Mustache_Tokenizer::TYPE]) { foreach ($tree as $node) {
case Mustache_Tokenizer::T_SECTION: switch ($node[Mustache_Tokenizer::TYPE]) {
$code .= $this->section( case Mustache_Tokenizer::T_SECTION:
$node[Mustache_Tokenizer::NODES], $code .= $this->section(
$node[Mustache_Tokenizer::NAME], $node[Mustache_Tokenizer::NODES],
$node[Mustache_Tokenizer::INDEX], $node[Mustache_Tokenizer::NAME],
$node[Mustache_Tokenizer::END], $node[Mustache_Tokenizer::INDEX],
$node[Mustache_Tokenizer::OTAG], $node[Mustache_Tokenizer::END],
$node[Mustache_Tokenizer::CTAG], $node[Mustache_Tokenizer::OTAG],
$level $node[Mustache_Tokenizer::CTAG],
); $level
break; );
break;
case Mustache_Tokenizer::T_INVERTED: case Mustache_Tokenizer::T_INVERTED:
$code .= $this->invertedSection( $code .= $this->invertedSection(
$node[Mustache_Tokenizer::NODES], $node[Mustache_Tokenizer::NODES],
$node[Mustache_Tokenizer::NAME], $node[Mustache_Tokenizer::NAME],
$level $level
); );
break; break;
case Mustache_Tokenizer::T_PARTIAL: case Mustache_Tokenizer::T_PARTIAL:
case Mustache_Tokenizer::T_PARTIAL_2: case Mustache_Tokenizer::T_PARTIAL_2:
$code .= $this->partial( $code .= $this->partial(
$node[Mustache_Tokenizer::NAME], $node[Mustache_Tokenizer::NAME],
isset($node[Mustache_Tokenizer::INDENT]) ? $node[Mustache_Tokenizer::INDENT] : '', isset($node[Mustache_Tokenizer::INDENT]) ? $node[Mustache_Tokenizer::INDENT] : '',
$level $level
); );
break; break;
case Mustache_Tokenizer::T_UNESCAPED: case Mustache_Tokenizer::T_UNESCAPED:
case Mustache_Tokenizer::T_UNESCAPED_2: case Mustache_Tokenizer::T_UNESCAPED_2:
$code .= $this->variable($node[Mustache_Tokenizer::NAME], false, $level); $code .= $this->variable($node[Mustache_Tokenizer::NAME], false, $level);
break; break;
case Mustache_Tokenizer::T_COMMENT: case Mustache_Tokenizer::T_COMMENT:
break; break;
case Mustache_Tokenizer::T_ESCAPED: case Mustache_Tokenizer::T_ESCAPED:
$code .= $this->variable($node[Mustache_Tokenizer::NAME], true, $level); $code .= $this->variable($node[Mustache_Tokenizer::NAME], true, $level);
break; break;
case Mustache_Tokenizer::T_TEXT: case Mustache_Tokenizer::T_TEXT:
$code .= $this->text($node[Mustache_Tokenizer::VALUE], $level); $code .= $this->text($node[Mustache_Tokenizer::VALUE], $level);
break; break;
default: default:
throw new InvalidArgumentException('Unknown node type: '.json_encode($node)); throw new InvalidArgumentException('Unknown node type: '.json_encode($node));
} }
} }
return $code; return $code;
} }
const KLASS = '<?php const KLASS = '<?php
class %s extends Mustache_Template { class %s extends Mustache_Template
public function renderInternal(Mustache_Context $context, $indent = \'\', $escape = false) { {
$buffer = \'\'; public function renderInternal(Mustache_Context $context, $indent = \'\', $escape = false)
%s {
$buffer = \'\';
%s
if ($escape) { if ($escape) {
return %s; return %s;
} else { } else {
return $buffer; return $buffer;
} }
} }
%s %s
}'; }';
/** /**
* Generate Mustache Template class PHP source. * Generate Mustache Template class PHP source.
* *
* @param array $tree Parse tree of Mustache tokens * @param array $tree Parse tree of Mustache tokens
* @param string $name Mustache Template class name * @param string $name Mustache Template class name
* *
* @return string Generated PHP source code * @return string Generated PHP source code
*/ */
private function writeCode($tree, $name) { private function writeCode($tree, $name)
$code = $this->walk($tree); {
$sections = implode("\n", $this->sections); $code = $this->walk($tree);
$sections = implode("\n", $this->sections);
return sprintf($this->prepare(self::KLASS, 0, false), $name, $code, $this->getEscape('$buffer'), $sections); return sprintf($this->prepare(self::KLASS, 0, false), $name, $code, $this->getEscape('$buffer'), $sections);
} }
const SECTION_CALL = ' const SECTION_CALL = '
// %s section // %s section
$buffer .= $this->section%s($context, $indent, $context->%s(%s)); $buffer .= $this->section%s($context, $indent, $context->%s(%s));
'; ';
const SECTION = ' const SECTION = '
private function section%s(Mustache_Context $context, $indent, $value) { private function section%s(Mustache_Context $context, $indent, $value) {
$buffer = \'\'; $buffer = \'\';
if (!is_string($value) && is_callable($value)) { if (!is_string($value) && is_callable($value)) {
$source = %s; $source = %s;
$buffer .= $this->mustache $buffer .= $this->mustache
->loadLambda((string) call_user_func($value, $source)%s) ->loadLambda((string) call_user_func($value, $source)%s)
->renderInternal($context, $indent); ->renderInternal($context, $indent);
} elseif (!empty($value)) { } elseif (!empty($value)) {
$values = $this->isIterable($value) ? $value : array($value); $values = $this->isIterable($value) ? $value : array($value);
foreach ($values as $value) { foreach ($values as $value) {
$context->push($value);%s $context->push($value);%s
$context->pop(); $context->pop();
} }
} }
return $buffer; return $buffer;
}'; }';
/** /**
* Generate Mustache Template section PHP source. * Generate Mustache Template section PHP source.
* *
* @param array $nodes Array of child tokens * @param array $nodes Array of child tokens
* @param string $id Section name * @param string $id Section name
* @param int $start Section start offset * @param int $start Section start offset
* @param int $end Section end offset * @param int $end Section end offset
* @param string $otag Current Mustache opening tag * @param string $otag Current Mustache opening tag
* @param string $ctag Current Mustache closing tag * @param string $ctag Current Mustache closing tag
* @param int $level * @param int $level
* *
* @return string Generated section PHP source code * @return string Generated section PHP source code
*/ */
private function section($nodes, $id, $start, $end, $otag, $ctag, $level) { private function section($nodes, $id, $start, $end, $otag, $ctag, $level)
$method = $this->getFindMethod($id); {
$id = var_export($id, true); $method = $this->getFindMethod($id);
$source = var_export(substr($this->source, $start, $end - $start), true); $id = var_export($id, true);
$source = var_export(substr($this->source, $start, $end - $start), true);
if ($otag !== '{{' || $ctag !== '}}') { if ($otag !== '{{' || $ctag !== '}}') {
$delims = ', '.var_export(sprintf('{{= %s %s =}}', $otag, $ctag), true); $delims = ', '.var_export(sprintf('{{= %s %s =}}', $otag, $ctag), true);
} else { } else {
$delims = ''; $delims = '';
} }
$key = ucfirst(md5($delims."\n".$source)); $key = ucfirst(md5($delims."\n".$source));
if (!isset($this->sections[$key])) { if (!isset($this->sections[$key])) {
$this->sections[$key] = sprintf($this->prepare(self::SECTION), $key, $source, $delims, $this->walk($nodes, 2)); $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); return sprintf($this->prepare(self::SECTION_CALL, $level), $id, $key, $method, $id);
} }
const INVERTED_SECTION = ' const INVERTED_SECTION = '
// %s inverted section // %s inverted section
$value = $context->%s(%s); $value = $context->%s(%s);
if (empty($value)) { if (empty($value)) {
%s %s
}'; }';
/** /**
* Generate Mustache Template inverted section PHP source. * Generate Mustache Template inverted section PHP source.
* *
* @param array $nodes Array of child tokens * @param array $nodes Array of child tokens
* @param string $id Section name * @param string $id Section name
* @param int $level * @param int $level
* *
* @return string Generated inverted section PHP source code * @return string Generated inverted section PHP source code
*/ */
private function invertedSection($nodes, $id, $level) { private function invertedSection($nodes, $id, $level)
$method = $this->getFindMethod($id); {
$id = var_export($id, true); $method = $this->getFindMethod($id);
$id = var_export($id, true);
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 = ' const PARTIAL = '
if ($partial = $this->mustache->loadPartial(%s)) { if ($partial = $this->mustache->loadPartial(%s)) {
$buffer .= $partial->renderInternal($context, %s); $buffer .= $partial->renderInternal($context, %s);
} }
'; ';
/** /**
* Generate Mustache Template partial call PHP source. * Generate Mustache Template partial call PHP source.
* *
* @param string $id Partial name * @param string $id Partial name
* @param string $indent Whitespace indent to apply to partial * @param string $indent Whitespace indent to apply to partial
* @param int $level * @param int $level
* *
* @return string Generated partial call PHP source code * @return string Generated partial call PHP source code
*/ */
private function partial($id, $indent, $level) { private function partial($id, $indent, $level)
return sprintf( {
$this->prepare(self::PARTIAL, $level), return sprintf(
var_export($id, true), $this->prepare(self::PARTIAL, $level),
var_export($indent, true) var_export($id, true),
); var_export($indent, true)
} );
}
const VARIABLE = ' const VARIABLE = '
$value = $context->%s(%s); $value = $context->%s(%s);
if (!is_string($value) && is_callable($value)) { if (!is_string($value) && is_callable($value)) {
$value = $this->mustache $value = $this->mustache
->loadLambda((string) call_user_func($value)) ->loadLambda((string) call_user_func($value))
->renderInternal($context, $indent); ->renderInternal($context, $indent);
} }
$buffer .= %s%s; $buffer .= %s%s;
'; ';
/** /**
* Generate Mustache Template variable interpolation PHP source. * Generate Mustache Template variable interpolation PHP source.
* *
* @param string $id Variable name * @param string $id Variable name
* @param boolean $escape Escape the variable value for output? * @param boolean $escape Escape the variable value for output?
* @param int $level * @param int $level
* *
* @return string Generated variable interpolation PHP source * @return string Generated variable interpolation PHP source
*/ */
private function variable($id, $escape, $level) { private function variable($id, $escape, $level)
$method = $this->getFindMethod($id); {
$id = ($method !== 'last') ? var_export($id, true) : ''; $method = $this->getFindMethod($id);
$value = $escape ? $this->getEscape() : '$value'; $id = ($method !== 'last') ? var_export($id, true) : '';
$value = $escape ? $this->getEscape() : '$value';
return sprintf($this->prepare(self::VARIABLE, $level), $method, $id, $this->flushIndent(), $value); return sprintf($this->prepare(self::VARIABLE, $level), $method, $id, $this->flushIndent(), $value);
} }
const LINE = '$buffer .= "\n";'; const LINE = '$buffer .= "\n";';
const TEXT = '$buffer .= %s%s;'; const TEXT = '$buffer .= %s%s;';
/** /**
* Generate Mustache Template output Buffer call PHP source. * Generate Mustache Template output Buffer call PHP source.
* *
* @param string $text * @param string $text
* @param int $level * @param int $level
* *
* @return string Generated output Buffer call PHP source * @return string Generated output Buffer call PHP source
*/ */
private function text($text, $level) { private function text($text, $level)
if ($text === "\n") { {
$this->indentNextLine = true; if ($text === "\n") {
$this->indentNextLine = true;
return $this->prepare(self::LINE, $level); return $this->prepare(self::LINE, $level);
} else { } else {
return sprintf($this->prepare(self::TEXT, $level), $this->flushIndent(), var_export($text, true)); return sprintf($this->prepare(self::TEXT, $level), $this->flushIndent(), var_export($text, true));
} }
} }
/** /**
* Prepare PHP source code snippet for output. * Prepare PHP source code snippet for output.
* *
* @param string $text * @param string $text
* @param int $bonus Additional indent level (default: 0) * @param int $bonus Additional indent level (default: 0)
* @param boolean $prependNewline Prepend a newline to the snippet? (default: true) * @param boolean $prependNewline Prepend a newline to the snippet? (default: true)
* *
* @return string PHP source code snippet * @return string PHP source code snippet
*/ */
private function prepare($text, $bonus = 0, $prependNewline = true) { private function prepare($text, $bonus = 0, $prependNewline = true)
$text = ($prependNewline ? "\n" : '').trim($text); {
if ($prependNewline) { $text = ($prependNewline ? "\n" : '').trim($text);
$bonus++; if ($prependNewline) {
} $bonus++;
}
return preg_replace("/\n(\t\t)?/", "\n".str_repeat("\t", $bonus), $text); return preg_replace("/\n( {8})?/", "\n".str_repeat(" ", $bonus * 4), $text);
} }
const DEFAULT_ESCAPE = 'htmlspecialchars(%s, ENT_COMPAT, %s)'; const DEFAULT_ESCAPE = 'htmlspecialchars(%s, ENT_COMPAT, %s)';
const CUSTOM_ESCAPE = 'call_user_func($this->mustache->getEscape(), %s)'; const CUSTOM_ESCAPE = 'call_user_func($this->mustache->getEscape(), %s)';
/** /**
* Get the current escaper. * Get the current escaper.
* *
* @return string Either a custom callback, or an inline call to `htmlspecialchars` * @return string Either a custom callback, or an inline call to `htmlspecialchars`
*/ */
private function getEscape($value = '$value') { private function getEscape($value = '$value')
if ($this->customEscape) { {
return sprintf(self::CUSTOM_ESCAPE, $value); if ($this->customEscape) {
} else { return sprintf(self::CUSTOM_ESCAPE, $value);
return sprintf(self::DEFAULT_ESCAPE, $value, var_export($this->charset, true)); } else {
} return sprintf(self::DEFAULT_ESCAPE, $value, var_export($this->charset, true));
} }
}
/** /**
* Select the appropriate Context `find` method for a given $id. * Select the appropriate Context `find` method for a given $id.
* *
* The return value will be one of `find`, `findDot` or `last`. * The return value will be one of `find`, `findDot` or `last`.
* *
* @see Mustache_Context::find * @see Mustache_Context::find
* @see Mustache_Context::findDot * @see Mustache_Context::findDot
* @see Mustache_Context::last * @see Mustache_Context::last
* *
* @param string $id Variable name * @param string $id Variable name
* *
* @return string `find` method name * @return string `find` method name
*/ */
private function getFindMethod($id) { private function getFindMethod($id)
if ($id === '.') { {
return 'last'; if ($id === '.') {
} elseif (strpos($id, '.') === false) { return 'last';
return 'find'; } elseif (strpos($id, '.') === false) {
} else { return 'find';
return 'findDot'; } else {
} return 'findDot';
} }
}
const LINE_INDENT = '$indent . '; const LINE_INDENT = '$indent . ';
/** /**
* Get the current $indent prefix to write to the buffer. * Get the current $indent prefix to write to the buffer.
* *
* @return string "$indent . " or "" * @return string "$indent . " or ""
*/ */
private function flushIndent() { private function flushIndent()
if ($this->indentNextLine) { {
$this->indentNextLine = false; if ($this->indentNextLine) {
$this->indentNextLine = false;
return self::LINE_INDENT; return self::LINE_INDENT;
} else { } else {
return ''; return '';
} }
} }
} }
+123 -115
View File
@@ -12,130 +12,138 @@
/** /**
* Mustache Template rendering Context. * Mustache Template rendering Context.
*/ */
class Mustache_Context { class Mustache_Context
private $stack = array(); {
private $stack = array();
/** /**
* Mustache rendering Context constructor. * Mustache rendering Context constructor.
* *
* @param mixed $context Default rendering context (default: null) * @param mixed $context Default rendering context (default: null)
*/ */
public function __construct($context = null) { public function __construct($context = null)
if ($context !== null) { {
$this->stack = array($context); if ($context !== null) {
} $this->stack = array($context);
} }
}
/** /**
* Push a new Context frame onto the stack. * Push a new Context frame onto the stack.
* *
* @param mixed $value Object or array to use for context * @param mixed $value Object or array to use for context
*/ */
public function push($value) { public function push($value)
array_push($this->stack, $value); {
} array_push($this->stack, $value);
}
/** /**
* Pop the last Context frame from the stack. * Pop the last Context frame from the stack.
* *
* @return mixed Last Context frame (object or array) * @return mixed Last Context frame (object or array)
*/ */
public function pop() { public function pop()
return array_pop($this->stack); {
} return array_pop($this->stack);
}
/** /**
* Get the last Context frame. * Get the last Context frame.
* *
* @return mixed Last Context frame (object or array) * @return mixed Last Context frame (object or array)
*/ */
public function last() { public function last()
return end($this->stack); {
} return end($this->stack);
}
/** /**
* Find a variable in the Context stack. * Find a variable in the Context stack.
* *
* Starting with the last Context frame (the context of the innermost section), and working back to the top-level * Starting with the last Context frame (the context of the innermost section), and working back to the top-level
* rendering context, look for a variable with the given name: * rendering context, look for a variable with the given name:
* *
* * If the Context frame is an associative array which contains the key $id, returns the value of that element. * * If the Context frame is an associative array which contains the key $id, returns the value of that element.
* * If the Context frame is an object, this will check first for a public method, then a public property named * * If the Context frame is an object, this will check first for a public method, then a public property named
* $id. Failing both of these, it will try `__isset` and `__get` magic methods. * $id. Failing both of these, it will try `__isset` and `__get` magic methods.
* * If a value named $id is not found in any Context frame, returns an empty string. * * If a value named $id is not found in any Context frame, returns an empty string.
* *
* @param string $id Variable name * @param string $id Variable name
* *
* @return mixed Variable value, or '' if not found * @return mixed Variable value, or '' if not found
*/ */
public function find($id) { public function find($id)
return $this->findVariableInStack($id, $this->stack); {
} return $this->findVariableInStack($id, $this->stack);
}
/** /**
* Find a 'dot notation' variable in the Context stack. * Find a 'dot notation' variable in the Context stack.
* *
* Note that dot notation traversal bubbles through scope differently than the regular find method. After finding * Note that dot notation traversal bubbles through scope differently than the regular find method. After finding
* the initial chunk of the dotted name, each subsequent chunk is searched for only within the value of the previous * the initial chunk of the dotted name, each subsequent chunk is searched for only within the value of the previous
* result. For example, given the following context stack: * result. For example, given the following context stack:
* *
* $data = array( * $data = array(
* 'name' => 'Fred', * 'name' => 'Fred',
* 'child' => array( * 'child' => array(
* 'name' => 'Bob' * 'name' => 'Bob'
* ), * ),
* ); * );
* *
* ... and the Mustache following template: * ... and the Mustache following template:
* *
* {{ child.name }} * {{ child.name }}
* *
* ... the `name` value is only searched for within the `child` value of the global Context, not within parent * ... the `name` value is only searched for within the `child` value of the global Context, not within parent
* Context frames. * Context frames.
* *
* @param string $id Dotted variable selector * @param string $id Dotted variable selector
* *
* @return mixed Variable value, or '' if not found * @return mixed Variable value, or '' if not found
*/ */
public function findDot($id) { public function findDot($id)
$chunks = explode('.', $id); {
$first = array_shift($chunks); $chunks = explode('.', $id);
$value = $this->findVariableInStack($first, $this->stack); $first = array_shift($chunks);
$value = $this->findVariableInStack($first, $this->stack);
foreach ($chunks as $chunk) { foreach ($chunks as $chunk) {
if ($value === '') { if ($value === '') {
return $value; return $value;
} }
$value = $this->findVariableInStack($chunk, array($value)); $value = $this->findVariableInStack($chunk, array($value));
} }
return $value; return $value;
} }
/** /**
* Helper function to find a variable in the Context stack. * Helper function to find a variable in the Context stack.
* *
* @see Mustache_Context::find * @see Mustache_Context::find
* *
* @param string $id Variable name * @param string $id Variable name
* @param array $stack Context stack * @param array $stack Context stack
* *
* @return mixed Variable value, or '' if not found * @return mixed Variable value, or '' if not found
*/ */
private function findVariableInStack($id, array $stack) { private function findVariableInStack($id, array $stack)
for ($i = count($stack) - 1; $i >= 0; $i--) { {
if (is_object($stack[$i])) { for ($i = count($stack) - 1; $i >= 0; $i--) {
if (method_exists($stack[$i], $id)) { if (is_object($stack[$i])) {
return $stack[$i]->$id(); if (method_exists($stack[$i], $id)) {
} elseif (isset($stack[$i]->$id)) { return $stack[$i]->$id();
return $stack[$i]->$id; } elseif (isset($stack[$i]->$id)) {
} return $stack[$i]->$id;
} elseif (is_array($stack[$i]) && array_key_exists($id, $stack[$i])) { }
return $stack[$i][$id]; } elseif (is_array($stack[$i]) && array_key_exists($id, $stack[$i])) {
} return $stack[$i][$id];
} }
}
return ''; return '';
} }
} }
+504 -472
View File
File diff suppressed because it is too large Load Diff
+139 -127
View File
@@ -12,145 +12,157 @@
/** /**
* A collection of helpers for a Mustache instance. * A collection of helpers for a Mustache instance.
*/ */
class Mustache_HelperCollection { class Mustache_HelperCollection
private $helpers = array(); {
private $helpers = array();
/** /**
* Helper Collection constructor. * Helper Collection constructor.
* *
* Optionally accepts an array (or Traversable) of `$name => $helper` pairs. * Optionally accepts an array (or Traversable) of `$name => $helper` pairs.
* *
* @throws InvalidArgumentException if the $helpers argument isn't an array or Traversable * @throws InvalidArgumentException if the $helpers argument isn't an array or Traversable
* *
* @param array|Traversable $helpers (default: null) * @param array|Traversable $helpers (default: null)
*/ */
public function __construct($helpers = null) { public function __construct($helpers = null)
if ($helpers !== null) { {
if (!is_array($helpers) && !$helpers instanceof Traversable) { if ($helpers !== null) {
throw new InvalidArgumentException('HelperCollection constructor expects an array of helpers'); if (!is_array($helpers) && !$helpers instanceof Traversable) {
} throw new InvalidArgumentException('HelperCollection constructor expects an array of helpers');
}
foreach ($helpers as $name => $helper) { foreach ($helpers as $name => $helper) {
$this->add($name, $helper); $this->add($name, $helper);
} }
} }
} }
/** /**
* Magic mutator. * Magic mutator.
* *
* @see Mustache_HelperCollection::add * @see Mustache_HelperCollection::add
* *
* @param string $name * @param string $name
* @param mixed $helper * @param mixed $helper
*/ */
public function __set($name, $helper) { public function __set($name, $helper)
$this->add($name, $helper); {
} $this->add($name, $helper);
}
/** /**
* Add a helper to this collection. * Add a helper to this collection.
* *
* @param string $name * @param string $name
* @param mixed $helper * @param mixed $helper
*/ */
public function add($name, $helper) { public function add($name, $helper)
$this->helpers[$name] = $helper; {
} $this->helpers[$name] = $helper;
}
/** /**
* Magic accessor. * Magic accessor.
* *
* @see Mustache_HelperCollection::get * @see Mustache_HelperCollection::get
* *
* @param string $name * @param string $name
* *
* @return mixed Helper * @return mixed Helper
*/ */
public function __get($name) { public function __get($name)
return $this->get($name); {
} return $this->get($name);
}
/** /**
* Get a helper by name. * Get a helper by name.
* *
* @param string $name * @param string $name
* *
* @return mixed Helper * @return mixed Helper
*/ */
public function get($name) { public function get($name)
if (!$this->has($name)) { {
throw new InvalidArgumentException('Unknown helper: '.$name); if (!$this->has($name)) {
} throw new InvalidArgumentException('Unknown helper: '.$name);
}
return $this->helpers[$name]; return $this->helpers[$name];
} }
/** /**
* Magic isset(). * Magic isset().
* *
* @see Mustache_HelperCollection::has * @see Mustache_HelperCollection::has
* *
* @param string $name * @param string $name
* *
* @return boolean True if helper is present * @return boolean True if helper is present
*/ */
public function __isset($name) { public function __isset($name)
return $this->has($name); {
} return $this->has($name);
}
/** /**
* Check whether a given helper is present in the collection. * Check whether a given helper is present in the collection.
* *
* @param string $name * @param string $name
* *
* @return boolean True if helper is present * @return boolean True if helper is present
*/ */
public function has($name) { public function has($name)
return array_key_exists($name, $this->helpers); {
} return array_key_exists($name, $this->helpers);
}
/** /**
* Magic unset(). * Magic unset().
* *
* @see Mustache_HelperCollection::remove * @see Mustache_HelperCollection::remove
* *
* @param string $name * @param string $name
*/ */
public function __unset($name) { public function __unset($name)
$this->remove($name); {
} $this->remove($name);
}
/** /**
* Check whether a given helper is present in the collection. * Check whether a given helper is present in the collection.
* *
* @throws InvalidArgumentException if the requested helper is not present. * @throws InvalidArgumentException if the requested helper is not present.
* *
* @param string $name * @param string $name
*/ */
public function remove($name) { public function remove($name)
if (!$this->has($name)) { {
throw new InvalidArgumentException('Unknown helper: '.$name); if (!$this->has($name)) {
} throw new InvalidArgumentException('Unknown helper: '.$name);
}
unset($this->helpers[$name]); unset($this->helpers[$name]);
} }
/** /**
* Clear the helper collection. * Clear the helper collection.
* *
* Removes all helpers from this collection * Removes all helpers from this collection
*/ */
public function clear() { public function clear()
$this->helpers = array(); {
} $this->helpers = array();
}
/** /**
* Check whether the helper collection is empty. * Check whether the helper collection is empty.
* *
* @return boolean True if the collection is empty * @return boolean True if the collection is empty
*/ */
public function isEmpty() { public function isEmpty()
return empty($this->helpers); {
} return empty($this->helpers);
}
} }
+10 -9
View File
@@ -12,14 +12,15 @@
/** /**
* Mustache Template Loader interface. * Mustache Template Loader interface.
*/ */
interface Mustache_Loader { interface Mustache_Loader
{
/** /**
* Load a Template by name. * Load a Template by name.
* *
* @param string $name * @param string $name
* *
* @return string Mustache Template source * @return string Mustache Template source
*/ */
function load($name); public function load($name);
} }
+44 -39
View File
@@ -27,48 +27,53 @@
* @implements Loader * @implements Loader
* @implements MutableLoader * @implements MutableLoader
*/ */
class Mustache_Loader_ArrayLoader implements Mustache_Loader, Mustache_Loader_MutableLoader { class Mustache_Loader_ArrayLoader implements Mustache_Loader, Mustache_Loader_MutableLoader
{
/** /**
* ArrayLoader constructor. * ArrayLoader constructor.
* *
* @param array $templates Associative array of Template source (default: array()) * @param array $templates Associative array of Template source (default: array())
*/ */
public function __construct(array $templates = array()) { public function __construct(array $templates = array())
$this->templates = $templates; {
} $this->templates = $templates;
}
/** /**
* Load a Template. * Load a Template.
* *
* @param string $name * @param string $name
* *
* @return string Mustache Template source * @return string Mustache Template source
*/ */
public function load($name) { public function load($name)
if (!isset($this->templates[$name])) { {
throw new InvalidArgumentException('Template '.$name.' not found.'); if (!isset($this->templates[$name])) {
} throw new InvalidArgumentException('Template '.$name.' not found.');
}
return $this->templates[$name]; return $this->templates[$name];
} }
/** /**
* Set an associative array of Template sources for this loader. * Set an associative array of Template sources for this loader.
* *
* @param array $templates * @param array $templates
*/ */
public function setTemplates(array $templates) { public function setTemplates(array $templates)
$this->templates = $templates; {
} $this->templates = $templates;
}
/** /**
* Set a Template source by name. * Set a Template source by name.
* *
* @param string $name * @param string $name
* @param string $template Mustache Template source * @param string $template Mustache Template source
*/ */
public function setTemplate($name, $template) { public function setTemplate($name, $template)
$this->templates[$name] = $template; {
} $this->templates[$name] = $template;
}
} }
+79 -74
View File
@@ -26,88 +26,93 @@
* *
* @implements Loader * @implements Loader
*/ */
class Mustache_Loader_FilesystemLoader implements Mustache_Loader { class Mustache_Loader_FilesystemLoader implements Mustache_Loader
private $baseDir; {
private $extension = '.mustache'; private $baseDir;
private $templates = array(); private $extension = '.mustache';
private $templates = array();
/** /**
* Mustache filesystem Loader constructor. * Mustache filesystem Loader constructor.
* *
* Passing an $options array allows overriding certain Loader options during instantiation: * Passing an $options array allows overriding certain Loader options during instantiation:
* *
* $options = array( * $options = array(
* // The filename extension used for Mustache templates. Defaults to '.mustache' * // The filename extension used for Mustache templates. Defaults to '.mustache'
* 'extension' => '.ms', * 'extension' => '.ms',
* ); * );
* *
* @throws RuntimeException if $baseDir does not exist. * @throws RuntimeException if $baseDir does not exist.
* *
* @param string $baseDir Base directory containing Mustache template files. * @param string $baseDir Base directory containing Mustache template files.
* @param array $options Array of Loader options (default: array()) * @param array $options Array of Loader options (default: array())
*/ */
public function __construct($baseDir, array $options = array()) { public function __construct($baseDir, array $options = array())
$this->baseDir = rtrim(realpath($baseDir), '/'); {
$this->baseDir = rtrim(realpath($baseDir), '/');
if (!is_dir($this->baseDir)) { if (!is_dir($this->baseDir)) {
throw new RuntimeException('FilesystemLoader baseDir must be a directory: '.$baseDir); throw new RuntimeException('FilesystemLoader baseDir must be a directory: '.$baseDir);
} }
if (isset($options['extension'])) { if (isset($options['extension'])) {
$this->extension = '.' . ltrim($options['extension'], '.'); $this->extension = '.' . ltrim($options['extension'], '.');
} }
} }
/** /**
* Load a Template by name. * Load a Template by name.
* *
* $loader = new FilesystemLoader(dirname(__FILE__).'/views'); * $loader = new FilesystemLoader(dirname(__FILE__).'/views');
* $loader->load('admin/dashboard'); // loads "./views/admin/dashboard.mustache"; * $loader->load('admin/dashboard'); // loads "./views/admin/dashboard.mustache";
* *
* @param string $name * @param string $name
* *
* @return string Mustache Template source * @return string Mustache Template source
*/ */
public function load($name) { public function load($name)
if (!isset($this->templates[$name])) { {
$this->templates[$name] = $this->loadFile($name); if (!isset($this->templates[$name])) {
} $this->templates[$name] = $this->loadFile($name);
}
return $this->templates[$name]; return $this->templates[$name];
} }
/** /**
* Helper function for loading a Mustache file by name. * Helper function for loading a Mustache file by name.
* *
* @throws InvalidArgumentException if a template file is not found. * @throws InvalidArgumentException if a template file is not found.
* *
* @param string $name * @param string $name
* *
* @return string Mustache Template source * @return string Mustache Template source
*/ */
private function loadFile($name) { private function loadFile($name)
$fileName = $this->getFileName($name); {
$fileName = $this->getFileName($name);
if (!file_exists($fileName)) { if (!file_exists($fileName)) {
throw new InvalidArgumentException('Template '.$name.' not found.'); throw new InvalidArgumentException('Template '.$name.' not found.');
} }
return file_get_contents($fileName); return file_get_contents($fileName);
} }
/** /**
* Helper function for getting a Mustache template file name. * Helper function for getting a Mustache template file name.
* *
* @param string $name * @param string $name
* *
* @return string Template file name * @return string Template file name
*/ */
private function getFileName($name) { private function getFileName($name)
$fileName = $this->baseDir . '/' . $name; {
if (substr($fileName, 0 - strlen($this->extension)) !== $this->extension) { $fileName = $this->baseDir . '/' . $name;
$fileName .= $this->extension; if (substr($fileName, 0 - strlen($this->extension)) !== $this->extension) {
} $fileName .= $this->extension;
}
return $fileName; return $fileName;
} }
} }
+15 -14
View File
@@ -12,20 +12,21 @@
/** /**
* Mustache Template mutable Loader interface. * Mustache Template mutable Loader interface.
*/ */
interface Mustache_Loader_MutableLoader { interface Mustache_Loader_MutableLoader
{
/** /**
* Set an associative array of Template sources for this loader. * Set an associative array of Template sources for this loader.
* *
* @param array $templates * @param array $templates
*/ */
function setTemplates(array $templates); public function setTemplates(array $templates);
/** /**
* Set a Template source by name. * Set a Template source by name.
* *
* @param string $name * @param string $name
* @param string $template Mustache Template source * @param string $template Mustache Template source
*/ */
function setTemplate($name, $template); public function setTemplate($name, $template);
} }
+13 -11
View File
@@ -25,16 +25,18 @@
* *
* @implements Loader * @implements Loader
*/ */
class Mustache_Loader_StringLoader implements Mustache_Loader { class Mustache_Loader_StringLoader implements Mustache_Loader
{
/** /**
* Load a Template by source. * Load a Template by source.
* *
* @param string $name Mustache Template source * @param string $name Mustache Template source
* *
* @return string Mustache Template source * @return string Mustache Template source
*/ */
public function load($name) { public function load($name)
return $name; {
} return $name;
}
} }
+59 -56
View File
@@ -14,72 +14,75 @@
* *
* This class is responsible for turning a set of Mustache tokens into a parse tree. * This class is responsible for turning a set of Mustache tokens into a parse tree.
*/ */
class Mustache_Parser { class Mustache_Parser
{
/** /**
* Process an array of Mustache tokens and convert them into a parse tree. * Process an array of Mustache tokens and convert them into a parse tree.
* *
* @param array $tokens Set of Mustache tokens * @param array $tokens Set of Mustache tokens
* *
* @return array Mustache token parse tree * @return array Mustache token parse tree
*/ */
public function parse(array $tokens = array()) { public function parse(array $tokens = array())
return $this->buildTree(new ArrayIterator($tokens)); {
} return $this->buildTree(new ArrayIterator($tokens));
}
/** /**
* Helper method for recursively building a parse tree. * Helper method for recursively building a parse tree.
* *
* @throws LogicException when nesting errors or mismatched section tags are encountered. * @throws LogicException when nesting errors or mismatched section tags are encountered.
* *
* @param ArrayIterator $tokens Stream of Mustache tokens * @param ArrayIterator $tokens Stream of Mustache tokens
* @param array $parent Parent token (default: null) * @param array $parent Parent token (default: null)
* *
* @return array Mustache Token parse tree * @return array Mustache Token parse tree
*/ */
private function buildTree(ArrayIterator $tokens, array $parent = null) { private function buildTree(ArrayIterator $tokens, array $parent = null)
$nodes = array(); {
$nodes = array();
do { do {
$token = $tokens->current(); $token = $tokens->current();
$tokens->next(); $tokens->next();
if ($token === null) { if ($token === null) {
continue; continue;
} else { } else {
switch ($token[Mustache_Tokenizer::TYPE]) { switch ($token[Mustache_Tokenizer::TYPE]) {
case Mustache_Tokenizer::T_SECTION: case Mustache_Tokenizer::T_SECTION:
case Mustache_Tokenizer::T_INVERTED: case Mustache_Tokenizer::T_INVERTED:
$nodes[] = $this->buildTree($tokens, $token); $nodes[] = $this->buildTree($tokens, $token);
break; break;
case Mustache_Tokenizer::T_END_SECTION: case Mustache_Tokenizer::T_END_SECTION:
if (!isset($parent)) { if (!isset($parent)) {
throw new LogicException('Unexpected closing tag: /'. $token[Mustache_Tokenizer::NAME]); throw new LogicException('Unexpected closing tag: /'. $token[Mustache_Tokenizer::NAME]);
} }
if ($token[Mustache_Tokenizer::NAME] !== $parent[Mustache_Tokenizer::NAME]) { if ($token[Mustache_Tokenizer::NAME] !== $parent[Mustache_Tokenizer::NAME]) {
throw new LogicException('Nesting error: ' . $parent[Mustache_Tokenizer::NAME] . ' vs. ' . $token[Mustache_Tokenizer::NAME]); throw new LogicException('Nesting error: ' . $parent[Mustache_Tokenizer::NAME] . ' vs. ' . $token[Mustache_Tokenizer::NAME]);
} }
$parent[Mustache_Tokenizer::END] = $token[Mustache_Tokenizer::INDEX]; $parent[Mustache_Tokenizer::END] = $token[Mustache_Tokenizer::INDEX];
$parent[Mustache_Tokenizer::NODES] = $nodes; $parent[Mustache_Tokenizer::NODES] = $nodes;
return $parent; return $parent;
break; break;
default: default:
$nodes[] = $token; $nodes[] = $token;
break; break;
} }
} }
} while ($tokens->valid()); } while ($tokens->valid());
if (isset($parent)) { if (isset($parent)) {
throw new LogicException('Missing closing tag: ' . $parent[Mustache_Tokenizer::NAME]); throw new LogicException('Missing closing tag: ' . $parent[Mustache_Tokenizer::NAME]);
} }
return $nodes; return $nodes;
} }
} }
+121 -115
View File
@@ -14,130 +14,136 @@
* *
* @abstract * @abstract
*/ */
abstract class Mustache_Template { abstract class Mustache_Template
{
/** /**
* @var Mustache_Engine * @var Mustache_Engine
*/ */
protected $mustache; protected $mustache;
/** /**
* Mustache Template constructor. * Mustache Template constructor.
* *
* @param Mustache_Engine $mustache * @param Mustache_Engine $mustache
*/ */
public function __construct(Mustache_Engine $mustache) { public function __construct(Mustache_Engine $mustache)
$this->mustache = $mustache; {
} $this->mustache = $mustache;
}
/** /**
* Mustache Template instances can be treated as a function and rendered by simply calling them: * Mustache Template instances can be treated as a function and rendered by simply calling them:
* *
* $m = new Mustache_Engine; * $m = new Mustache_Engine;
* $tpl = $m->loadTemplate('Hello, {{ name }}!'); * $tpl = $m->loadTemplate('Hello, {{ name }}!');
* echo $tpl(array('name' => 'World')); // "Hello, World!" * echo $tpl(array('name' => 'World')); // "Hello, World!"
* *
* @see Mustache_Template::render * @see Mustache_Template::render
* *
* @param mixed $context Array or object rendering context (default: array()) * @param mixed $context Array or object rendering context (default: array())
* *
* @return string Rendered template * @return string Rendered template
*/ */
public function __invoke($context = array()) { public function __invoke($context = array())
return $this->render($context); {
} return $this->render($context);
}
/** /**
* Render this template given the rendering context. * Render this template given the rendering context.
* *
* @param mixed $context Array or object rendering context (default: array()) * @param mixed $context Array or object rendering context (default: array())
* *
* @return string Rendered template * @return string Rendered template
*/ */
public function render($context = array()) { public function render($context = array())
return $this->renderInternal($this->prepareContextStack($context)); {
} return $this->renderInternal($this->prepareContextStack($context));
}
/** /**
* Internal rendering method implemented by Mustache Template concrete subclasses. * Internal rendering method implemented by Mustache Template concrete subclasses.
* *
* This is where the magic happens :) * This is where the magic happens :)
* *
* @abstract * @abstract
* *
* @param Mustache_Context $context * @param Mustache_Context $context
* *
* @return string Rendered template * @return string Rendered template
*/ */
abstract public function renderInternal(Mustache_Context $context, $indent = '', $escape = false); abstract public function renderInternal(Mustache_Context $context, $indent = '', $escape = false);
/** /**
* Tests whether a value should be iterated over (e.g. in a section context). * Tests whether a value should be iterated over (e.g. in a section context).
* *
* In most languages there are two distinct array types: list and hash (or whatever you want to call them). Lists * In most languages there are two distinct array types: list and hash (or whatever you want to call them). Lists
* should be iterated, hashes should be treated as objects. Mustache follows this paradigm for Ruby, Javascript, * should be iterated, hashes should be treated as objects. Mustache follows this paradigm for Ruby, Javascript,
* Java, Python, etc. * Java, Python, etc.
* *
* PHP, however, treats lists and hashes as one primitive type: array. So Mustache.php needs a way to distinguish * PHP, however, treats lists and hashes as one primitive type: array. So Mustache.php needs a way to distinguish
* between between a list of things (numeric, normalized array) and a set of variables to be used as section context * between between a list of things (numeric, normalized array) and a set of variables to be used as section context
* (associative array). In other words, this will be iterated over: * (associative array). In other words, this will be iterated over:
* *
* $items = array( * $items = array(
* array('name' => 'foo'), * array('name' => 'foo'),
* array('name' => 'bar'), * array('name' => 'bar'),
* array('name' => 'baz'), * array('name' => 'baz'),
* ); * );
* *
* ... but this will be used as a section context block: * ... but this will be used as a section context block:
* *
* $items = array( * $items = array(
* 1 => array('name' => 'foo'), * 1 => array('name' => 'foo'),
* 'banana' => array('name' => 'bar'), * 'banana' => array('name' => 'bar'),
* 42 => array('name' => 'baz'), * 42 => array('name' => 'baz'),
* ); * );
* *
* @param mixed $value * @param mixed $value
* *
* @return boolean True if the value is 'iterable' * @return boolean True if the value is 'iterable'
*/ */
protected function isIterable($value) { protected function isIterable($value)
if (is_object($value)) { {
return $value instanceof Traversable; if (is_object($value)) {
} elseif (is_array($value)) { return $value instanceof Traversable;
$i = 0; } elseif (is_array($value)) {
foreach ($value as $k => $v) { $i = 0;
if ($k !== $i++) { foreach ($value as $k => $v) {
return false; if ($k !== $i++) {
} return false;
} }
}
return true; return true;
} else { } else {
return false; return false;
} }
} }
/** /**
* Helper method to prepare the Context stack. * Helper method to prepare the Context stack.
* *
* Adds the Mustache HelperCollection to the stack's top context frame if helpers are present. * Adds the Mustache HelperCollection to the stack's top context frame if helpers are present.
* *
* @param mixed $context Optional first context frame (default: null) * @param mixed $context Optional first context frame (default: null)
* *
* @return Mustache_Context * @return Mustache_Context
*/ */
protected function prepareContextStack($context = null) { protected function prepareContextStack($context = null)
$stack = new Mustache_Context; {
$stack = new Mustache_Context;
$helpers = $this->mustache->getHelpers(); $helpers = $this->mustache->getHelpers();
if (!$helpers->isEmpty()) { if (!$helpers->isEmpty()) {
$stack->push($helpers); $stack->push($helpers);
} }
if (!empty($context)) { if (!empty($context)) {
$stack->push($context); $stack->push($context);
} }
return $stack; return $stack;
} }
} }
+240 -233
View File
@@ -16,263 +16,270 @@
*/ */
class Mustache_Tokenizer { class Mustache_Tokenizer {
// Finite state machine states // Finite state machine states
const IN_TEXT = 0; const IN_TEXT = 0;
const IN_TAG_TYPE = 1; const IN_TAG_TYPE = 1;
const IN_TAG = 2; const IN_TAG = 2;
// Token types // Token types
const T_SECTION = '#'; const T_SECTION = '#';
const T_INVERTED = '^'; const T_INVERTED = '^';
const T_END_SECTION = '/'; const T_END_SECTION = '/';
const T_COMMENT = '!'; const T_COMMENT = '!';
const T_PARTIAL = '>'; const T_PARTIAL = '>';
const T_PARTIAL_2 = '<'; const T_PARTIAL_2 = '<';
const T_DELIM_CHANGE = '='; const T_DELIM_CHANGE = '=';
const T_ESCAPED = '_v'; const T_ESCAPED = '_v';
const T_UNESCAPED = '{'; const T_UNESCAPED = '{';
const T_UNESCAPED_2 = '&'; const T_UNESCAPED_2 = '&';
const T_TEXT = '_t'; const T_TEXT = '_t';
// Valid token types // Valid token types
private static $tagTypes = array( private static $tagTypes = array(
self::T_SECTION => true, self::T_SECTION => true,
self::T_INVERTED => true, self::T_INVERTED => true,
self::T_END_SECTION => true, self::T_END_SECTION => true,
self::T_COMMENT => true, self::T_COMMENT => true,
self::T_PARTIAL => true, self::T_PARTIAL => true,
self::T_PARTIAL_2 => true, self::T_PARTIAL_2 => true,
self::T_DELIM_CHANGE => true, self::T_DELIM_CHANGE => true,
self::T_ESCAPED => true, self::T_ESCAPED => true,
self::T_UNESCAPED => true, self::T_UNESCAPED => true,
self::T_UNESCAPED_2 => true, self::T_UNESCAPED_2 => true,
); );
// Interpolated tags // Interpolated tags
private static $interpolatedTags = array( private static $interpolatedTags = array(
self::T_ESCAPED => true, self::T_ESCAPED => true,
self::T_UNESCAPED => true, self::T_UNESCAPED => true,
self::T_UNESCAPED_2 => true, self::T_UNESCAPED_2 => true,
); );
// Token properties // Token properties
const TYPE = 'type'; const TYPE = 'type';
const NAME = 'name'; const NAME = 'name';
const OTAG = 'otag'; const OTAG = 'otag';
const CTAG = 'ctag'; const CTAG = 'ctag';
const INDEX = 'index'; const INDEX = 'index';
const END = 'end'; const END = 'end';
const INDENT = 'indent'; const INDENT = 'indent';
const NODES = 'nodes'; const NODES = 'nodes';
const VALUE = 'value'; const VALUE = 'value';
private $state; private $state;
private $tagType; private $tagType;
private $tag; private $tag;
private $buffer; private $buffer;
private $tokens; private $tokens;
private $seenTag; private $seenTag;
private $lineStart; private $lineStart;
private $otag; private $otag;
private $ctag; private $ctag;
/** /**
* Scan and tokenize template source. * Scan and tokenize template source.
* *
* @param string $text Mustache template source to tokenize * @param string $text Mustache template source to tokenize
* @param string $delimiters Optionally, pass initial opening and closing delimiters (default: null) * @param string $delimiters Optionally, pass initial opening and closing delimiters (default: null)
* *
* @return array Set of Mustache tokens * @return array Set of Mustache tokens
*/ */
public function scan($text, $delimiters = null) { public function scan($text, $delimiters = null)
$this->reset(); {
$this->reset();
if ($delimiters = trim($delimiters)) { if ($delimiters = trim($delimiters)) {
list($otag, $ctag) = explode(' ', $delimiters); list($otag, $ctag) = explode(' ', $delimiters);
$this->otag = $otag; $this->otag = $otag;
$this->ctag = $ctag; $this->ctag = $ctag;
} }
$len = strlen($text); $len = strlen($text);
for ($i = 0; $i < $len; $i++) { for ($i = 0; $i < $len; $i++) {
switch ($this->state) { switch ($this->state) {
case self::IN_TEXT: case self::IN_TEXT:
if ($this->tagChange($this->otag, $text, $i)) { if ($this->tagChange($this->otag, $text, $i)) {
$i--; $i--;
$this->flushBuffer(); $this->flushBuffer();
$this->state = self::IN_TAG_TYPE; $this->state = self::IN_TAG_TYPE;
} else { } else {
if ($text[$i] == "\n") { if ($text[$i] == "\n") {
$this->filterLine(); $this->filterLine();
} else { } else {
$this->buffer .= $text[$i]; $this->buffer .= $text[$i];
} }
} }
break; break;
case self::IN_TAG_TYPE: case self::IN_TAG_TYPE:
$i += strlen($this->otag) - 1; $i += strlen($this->otag) - 1;
if (isset(self::$tagTypes[$text[$i + 1]])) { if (isset(self::$tagTypes[$text[$i + 1]])) {
$tag = $text[$i + 1]; $tag = $text[$i + 1];
$this->tagType = $tag; $this->tagType = $tag;
} else { } else {
$tag = null; $tag = null;
$this->tagType = self::T_ESCAPED; $this->tagType = self::T_ESCAPED;
} }
if ($this->tagType === self::T_DELIM_CHANGE) { if ($this->tagType === self::T_DELIM_CHANGE) {
$i = $this->changeDelimiters($text, $i); $i = $this->changeDelimiters($text, $i);
$this->state = self::IN_TEXT; $this->state = self::IN_TEXT;
} else { } else {
if ($tag !== null) { if ($tag !== null) {
$i++; $i++;
} }
$this->state = self::IN_TAG; $this->state = self::IN_TAG;
} }
$this->seenTag = $i; $this->seenTag = $i;
break; break;
default: default:
if ($this->tagChange($this->ctag, $text, $i)) { if ($this->tagChange($this->ctag, $text, $i)) {
$this->tokens[] = array( $this->tokens[] = array(
self::TYPE => $this->tagType, self::TYPE => $this->tagType,
self::NAME => trim($this->buffer), self::NAME => trim($this->buffer),
self::OTAG => $this->otag, self::OTAG => $this->otag,
self::CTAG => $this->ctag, self::CTAG => $this->ctag,
self::INDEX => ($this->tagType == self::T_END_SECTION) ? $this->seenTag - strlen($this->otag) : $i + strlen($this->ctag) self::INDEX => ($this->tagType == self::T_END_SECTION) ? $this->seenTag - strlen($this->otag) : $i + strlen($this->ctag)
); );
$this->buffer = ''; $this->buffer = '';
$i += strlen($this->ctag) - 1; $i += strlen($this->ctag) - 1;
$this->state = self::IN_TEXT; $this->state = self::IN_TEXT;
if ($this->tagType == self::T_UNESCAPED) { if ($this->tagType == self::T_UNESCAPED) {
if ($this->ctag == '}}') { if ($this->ctag == '}}') {
$i++; $i++;
} else { } else {
// Clean up `{{{ tripleStache }}}` style tokens. // Clean up `{{{ tripleStache }}}` style tokens.
$lastName = $this->tokens[count($this->tokens) - 1][self::NAME]; $lastName = $this->tokens[count($this->tokens) - 1][self::NAME];
if (substr($lastName, -1) === '}') { if (substr($lastName, -1) === '}') {
$this->tokens[count($this->tokens) - 1][self::NAME] = trim(substr($lastName, 0, -1)); $this->tokens[count($this->tokens) - 1][self::NAME] = trim(substr($lastName, 0, -1));
} }
} }
} }
} else { } else {
$this->buffer .= $text[$i]; $this->buffer .= $text[$i];
} }
break; break;
} }
} }
$this->filterLine(true); $this->filterLine(true);
return $this->tokens; return $this->tokens;
} }
/** /**
* Helper function to reset tokenizer internal state. * Helper function to reset tokenizer internal state.
*/ */
private function reset() { private function reset()
$this->state = self::IN_TEXT; {
$this->tagType = null; $this->state = self::IN_TEXT;
$this->tag = null; $this->tagType = null;
$this->buffer = ''; $this->tag = null;
$this->tokens = array(); $this->buffer = '';
$this->seenTag = false; $this->tokens = array();
$this->lineStart = 0; $this->seenTag = false;
$this->otag = '{{'; $this->lineStart = 0;
$this->ctag = '}}'; $this->otag = '{{';
} $this->ctag = '}}';
}
/** /**
* Flush the current buffer to a token. * Flush the current buffer to a token.
*/ */
private function flushBuffer() { private function flushBuffer()
if (!empty($this->buffer)) { {
$this->tokens[] = array(self::TYPE => self::T_TEXT, self::VALUE => $this->buffer); if (!empty($this->buffer)) {
$this->buffer = ''; $this->tokens[] = array(self::TYPE => self::T_TEXT, self::VALUE => $this->buffer);
} $this->buffer = '';
} }
}
/** /**
* Test whether the current line is entirely made up of whitespace. * Test whether the current line is entirely made up of whitespace.
* *
* @return boolean True if the current line is all whitespace * @return boolean True if the current line is all whitespace
*/ */
private function lineIsWhitespace() { private function lineIsWhitespace()
$tokensCount = count($this->tokens); {
for ($j = $this->lineStart; $j < $tokensCount; $j++) { $tokensCount = count($this->tokens);
$token = $this->tokens[$j]; for ($j = $this->lineStart; $j < $tokensCount; $j++) {
if (isset(self::$tagTypes[$token[self::TYPE]])) { $token = $this->tokens[$j];
if (isset(self::$interpolatedTags[$token[self::TYPE]])) { if (isset(self::$tagTypes[$token[self::TYPE]])) {
return false; if (isset(self::$interpolatedTags[$token[self::TYPE]])) {
} return false;
} elseif ($token[self::TYPE] == self::T_TEXT) { }
if (preg_match('/\S/', $token[self::VALUE])) { } elseif ($token[self::TYPE] == self::T_TEXT) {
return false; if (preg_match('/\S/', $token[self::VALUE])) {
} return false;
} }
} }
}
return true; return true;
} }
/** /**
* Filter out whitespace-only lines and store indent levels for partials. * Filter out whitespace-only lines and store indent levels for partials.
* *
* @param bool $noNewLine Suppress the newline? (default: false) * @param bool $noNewLine Suppress the newline? (default: false)
*/ */
private function filterLine($noNewLine = false) { private function filterLine($noNewLine = false)
$this->flushBuffer(); {
if ($this->seenTag && $this->lineIsWhitespace()) { $this->flushBuffer();
$tokensCount = count($this->tokens); if ($this->seenTag && $this->lineIsWhitespace()) {
for ($j = $this->lineStart; $j < $tokensCount; $j++) { $tokensCount = count($this->tokens);
if ($this->tokens[$j][self::TYPE] == self::T_TEXT) { for ($j = $this->lineStart; $j < $tokensCount; $j++) {
if (isset($this->tokens[$j+1]) && $this->tokens[$j+1][self::TYPE] == self::T_PARTIAL) { if ($this->tokens[$j][self::TYPE] == self::T_TEXT) {
$this->tokens[$j+1][self::INDENT] = $this->tokens[$j][self::VALUE]; if (isset($this->tokens[$j+1]) && $this->tokens[$j+1][self::TYPE] == self::T_PARTIAL) {
} $this->tokens[$j+1][self::INDENT] = $this->tokens[$j][self::VALUE];
}
$this->tokens[$j] = null; $this->tokens[$j] = null;
} }
} }
} elseif (!$noNewLine) { } elseif (!$noNewLine) {
$this->tokens[] = array(self::TYPE => self::T_TEXT, self::VALUE => "\n"); $this->tokens[] = array(self::TYPE => self::T_TEXT, self::VALUE => "\n");
} }
$this->seenTag = false; $this->seenTag = false;
$this->lineStart = count($this->tokens); $this->lineStart = count($this->tokens);
} }
/** /**
* Change the current Mustache delimiters. Set new `otag` and `ctag` values. * Change the current Mustache delimiters. Set new `otag` and `ctag` values.
* *
* @param string $text Mustache template source * @param string $text Mustache template source
* @param int $index Current tokenizer index * @param int $index Current tokenizer index
* *
* @return int New index value * @return int New index value
*/ */
private function changeDelimiters($text, $index) { private function changeDelimiters($text, $index)
$startIndex = strpos($text, '=', $index) + 1; {
$close = '='.$this->ctag; $startIndex = strpos($text, '=', $index) + 1;
$closeIndex = strpos($text, $close, $index); $close = '='.$this->ctag;
$closeIndex = strpos($text, $close, $index);
list($otag, $ctag) = explode(' ', trim(substr($text, $startIndex, $closeIndex - $startIndex))); list($otag, $ctag) = explode(' ', trim(substr($text, $startIndex, $closeIndex - $startIndex)));
$this->otag = $otag; $this->otag = $otag;
$this->ctag = $ctag; $this->ctag = $ctag;
return $closeIndex + strlen($close) - 1; return $closeIndex + strlen($close) - 1;
} }
/** /**
* Test whether it's time to change tags. * Test whether it's time to change tags.
* *
* @param string $tag Current tag name * @param string $tag Current tag name
* @param string $text Mustache template source * @param string $text Mustache template source
* @param int $index Current tokenizer index * @param int $index Current tokenizer index
* *
* @return boolean True if this is a closing section tag * @return boolean True if this is a closing section tag
*/ */
private function tagChange($tag, $text, $index) { private function tagChange($tag, $text, $index)
return substr($text, $index, strlen($tag)) === $tag; {
} return substr($text, $index, strlen($tag)) === $tag;
}
} }
+17 -14
View File
@@ -12,22 +12,25 @@
/** /**
* @group unit * @group unit
*/ */
class Mustache_Test_AutoloaderTest extends PHPUnit_Framework_TestCase { class Mustache_Test_AutoloaderTest extends PHPUnit_Framework_TestCase
public function testRegister() { {
$loader = Mustache_Autoloader::register(); public function testRegister()
$this->assertTrue(spl_autoload_unregister(array($loader, 'autoload'))); {
} $loader = Mustache_Autoloader::register();
$this->assertTrue(spl_autoload_unregister(array($loader, 'autoload')));
}
public function testAutoloader() { public function testAutoloader()
$loader = new Mustache_Autoloader(dirname(__FILE__).'/../../fixtures/autoloader'); {
$loader = new Mustache_Autoloader(dirname(__FILE__).'/../../fixtures/autoloader');
$this->assertNull($loader->autoload('NonMustacheClass')); $this->assertNull($loader->autoload('NonMustacheClass'));
$this->assertFalse(class_exists('NonMustacheClass')); $this->assertFalse(class_exists('NonMustacheClass'));
$loader->autoload('Mustache_Foo'); $loader->autoload('Mustache_Foo');
$this->assertTrue(class_exists('Mustache_Foo')); $this->assertTrue(class_exists('Mustache_Foo'));
$loader->autoload('\Mustache_Bar'); $loader->autoload('\Mustache_Bar');
$this->assertTrue(class_exists('Mustache_Bar')); $this->assertTrue(class_exists('Mustache_Bar'));
} }
} }
+80 -75
View File
@@ -12,87 +12,92 @@
/** /**
* @group unit * @group unit
*/ */
class Mustache_Test_CompilerTest extends PHPUnit_Framework_TestCase { class Mustache_Test_CompilerTest extends PHPUnit_Framework_TestCase
{
/** /**
* @dataProvider getCompileValues * @dataProvider getCompileValues
*/ */
public function testCompile($source, array $tree, $name, $customEscaper, $charset, $expected) { public function testCompile($source, array $tree, $name, $customEscaper, $charset, $expected)
$compiler = new Mustache_Compiler; {
$compiler = new Mustache_Compiler;
$compiled = $compiler->compile($source, $tree, $name, $customEscaper, $charset); $compiled = $compiler->compile($source, $tree, $name, $customEscaper, $charset);
foreach ($expected as $contains) { foreach ($expected as $contains) {
$this->assertContains($contains, $compiled); $this->assertContains($contains, $compiled);
} }
} }
public function getCompileValues() { public function getCompileValues()
return array( {
array('', array(), 'Banana', false, 'ISO-8859-1', array( return array(
"\nclass Banana extends Mustache_Template", array('', array(), 'Banana', false, 'ISO-8859-1', array(
'return htmlspecialchars($buffer, ENT_COMPAT, \'ISO-8859-1\');', "\nclass Banana extends Mustache_Template",
'return $buffer;', 'return htmlspecialchars($buffer, ENT_COMPAT, \'ISO-8859-1\');',
)), 'return $buffer;',
)),
array('', array($this->createTextToken('TEXT')), 'Monkey', false, 'UTF-8', array( array('', array($this->createTextToken('TEXT')), 'Monkey', false, 'UTF-8', array(
"\nclass Monkey extends Mustache_Template", "\nclass Monkey extends Mustache_Template",
'return htmlspecialchars($buffer, ENT_COMPAT, \'UTF-8\');', 'return htmlspecialchars($buffer, ENT_COMPAT, \'UTF-8\');',
'$buffer .= $indent . \'TEXT\';', '$buffer .= $indent . \'TEXT\';',
'return $buffer;', 'return $buffer;',
)), )),
array('', array($this->createTextToken('TEXT')), 'Monkey', true, 'ISO-8859-1', array( array('', array($this->createTextToken('TEXT')), 'Monkey', true, 'ISO-8859-1', array(
"\nclass Monkey extends Mustache_Template", "\nclass Monkey extends Mustache_Template",
'$buffer .= $indent . \'TEXT\';', '$buffer .= $indent . \'TEXT\';',
'return call_user_func($this->mustache->getEscape(), $buffer);', 'return call_user_func($this->mustache->getEscape(), $buffer);',
'return $buffer;', 'return $buffer;',
)), )),
array( array(
'', '',
array( array(
$this->createTextToken('foo'), $this->createTextToken('foo'),
$this->createTextToken("\n"), $this->createTextToken("\n"),
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED,
Mustache_Tokenizer::NAME => 'name', Mustache_Tokenizer::NAME => 'name',
), ),
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED,
Mustache_Tokenizer::NAME => '.', Mustache_Tokenizer::NAME => '.',
), ),
$this->createTextToken("'bar'"), $this->createTextToken("'bar'"),
), ),
'Monkey', 'Monkey',
false, false,
'UTF-8', 'UTF-8',
array( array(
"\nclass Monkey extends Mustache_Template", "\nclass Monkey extends Mustache_Template",
'$buffer .= $indent . \'foo\'', '$buffer .= $indent . \'foo\'',
'$buffer .= "\n"', '$buffer .= "\n"',
'$value = $context->find(\'name\');', '$value = $context->find(\'name\');',
'$buffer .= htmlspecialchars($value, ENT_COMPAT, \'UTF-8\');', '$buffer .= htmlspecialchars($value, ENT_COMPAT, \'UTF-8\');',
'$value = $context->last();', '$value = $context->last();',
'$buffer .= \'\\\'bar\\\'\';', '$buffer .= \'\\\'bar\\\'\';',
'return htmlspecialchars($buffer, ENT_COMPAT, \'UTF-8\');', 'return htmlspecialchars($buffer, ENT_COMPAT, \'UTF-8\');',
'return $buffer;', 'return $buffer;',
) )
), ),
); );
} }
/** /**
* @expectedException InvalidArgumentException * @expectedException InvalidArgumentException
*/ */
public function testCompilerThrowsUnknownNodeTypeException() { public function testCompilerThrowsUnknownNodeTypeException()
$compiler = new Mustache_Compiler; {
$compiler->compile('', array(array(Mustache_Tokenizer::TYPE => 'invalid')), 'SomeClass'); $compiler = new Mustache_Compiler;
} $compiler->compile('', array(array(Mustache_Tokenizer::TYPE => 'invalid')), 'SomeClass');
}
private function createTextToken($value) { private function createTextToken($value)
return array( {
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT, return array(
Mustache_Tokenizer::VALUE => $value, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
); Mustache_Tokenizer::VALUE => $value,
} );
}
} }
+82 -74
View File
@@ -12,100 +12,108 @@
/** /**
* @group unit * @group unit
*/ */
class Mustache_Test_ContextTest extends PHPUnit_Framework_TestCase { class Mustache_Test_ContextTest extends PHPUnit_Framework_TestCase
public function testConstructor() { {
$one = new Mustache_Context; public function testConstructor()
$this->assertSame('', $one->find('foo')); {
$this->assertSame('', $one->find('bar')); $one = new Mustache_Context;
$this->assertSame('', $one->find('foo'));
$this->assertSame('', $one->find('bar'));
$two = new Mustache_Context(array( $two = new Mustache_Context(array(
'foo' => 'FOO', 'foo' => 'FOO',
'bar' => '<BAR>' 'bar' => '<BAR>'
)); ));
$this->assertEquals('FOO', $two->find('foo')); $this->assertEquals('FOO', $two->find('foo'));
$this->assertEquals('<BAR>', $two->find('bar')); $this->assertEquals('<BAR>', $two->find('bar'));
$obj = new StdClass; $obj = new StdClass;
$obj->name = 'NAME'; $obj->name = 'NAME';
$three = new Mustache_Context($obj); $three = new Mustache_Context($obj);
$this->assertSame($obj, $three->last()); $this->assertSame($obj, $three->last());
$this->assertEquals('NAME', $three->find('name')); $this->assertEquals('NAME', $three->find('name'));
} }
public function testPushPopAndLast() { public function testPushPopAndLast()
$context = new Mustache_Context; {
$this->assertFalse($context->last()); $context = new Mustache_Context;
$this->assertFalse($context->last());
$dummy = new Mustache_Test_TestDummy; $dummy = new Mustache_Test_TestDummy;
$context->push($dummy); $context->push($dummy);
$this->assertSame($dummy, $context->last()); $this->assertSame($dummy, $context->last());
$this->assertSame($dummy, $context->pop()); $this->assertSame($dummy, $context->pop());
$this->assertFalse($context->last()); $this->assertFalse($context->last());
$obj = new StdClass; $obj = new StdClass;
$context->push($dummy); $context->push($dummy);
$this->assertSame($dummy, $context->last()); $this->assertSame($dummy, $context->last());
$context->push($obj); $context->push($obj);
$this->assertSame($obj, $context->last()); $this->assertSame($obj, $context->last());
$this->assertSame($obj, $context->pop()); $this->assertSame($obj, $context->pop());
$this->assertSame($dummy, $context->pop()); $this->assertSame($dummy, $context->pop());
$this->assertFalse($context->last()); $this->assertFalse($context->last());
} }
public function testFind() { public function testFind()
$context = new Mustache_Context; {
$context = new Mustache_Context;
$dummy = new Mustache_Test_TestDummy; $dummy = new Mustache_Test_TestDummy;
$obj = new StdClass; $obj = new StdClass;
$obj->name = 'obj'; $obj->name = 'obj';
$arr = array( $arr = array(
'a' => array('b' => array('c' => 'see')), 'a' => array('b' => array('c' => 'see')),
'b' => 'bee', 'b' => 'bee',
); );
$string = 'some arbitrary string'; $string = 'some arbitrary string';
$context->push($dummy); $context->push($dummy);
$this->assertEquals('dummy', $context->find('name')); $this->assertEquals('dummy', $context->find('name'));
$context->push($obj); $context->push($obj);
$this->assertEquals('obj', $context->find('name')); $this->assertEquals('obj', $context->find('name'));
$context->pop(); $context->pop();
$this->assertEquals('dummy', $context->find('name')); $this->assertEquals('dummy', $context->find('name'));
$dummy->name = 'dummyer'; $dummy->name = 'dummyer';
$this->assertEquals('dummyer', $context->find('name')); $this->assertEquals('dummyer', $context->find('name'));
$context->push($arr); $context->push($arr);
$this->assertEquals('bee', $context->find('b')); $this->assertEquals('bee', $context->find('b'));
$this->assertEquals('see', $context->findDot('a.b.c')); $this->assertEquals('see', $context->findDot('a.b.c'));
$dummy->name = 'dummy'; $dummy->name = 'dummy';
$context->push($string); $context->push($string);
$this->assertSame($string, $context->last()); $this->assertSame($string, $context->last());
$this->assertEquals('dummy', $context->find('name')); $this->assertEquals('dummy', $context->find('name'));
$this->assertEquals('see', $context->findDot('a.b.c')); $this->assertEquals('see', $context->findDot('a.b.c'));
$this->assertEquals('<foo>', $context->find('foo')); $this->assertEquals('<foo>', $context->find('foo'));
$this->assertEquals('<bar>', $context->findDot('bar')); $this->assertEquals('<bar>', $context->findDot('bar'));
} }
} }
class Mustache_Test_TestDummy { class Mustache_Test_TestDummy
public $name = 'dummy'; {
public $name = 'dummy';
public function __invoke() { public function __invoke()
// nothing {
} // nothing
}
public static function foo() { public static function foo()
return '<foo>'; {
} return '<foo>';
}
public function bar() { public function bar()
return '<bar>'; {
} return '<bar>';
}
} }
+202 -186
View File
@@ -12,229 +12,245 @@
/** /**
* @group unit * @group unit
*/ */
class Mustache_Test_EngineTest extends PHPUnit_Framework_TestCase { class Mustache_Test_EngineTest extends PHPUnit_Framework_TestCase
{
private static $tempDir; private static $tempDir;
public static function setUpBeforeClass() { public static function setUpBeforeClass()
self::$tempDir = sys_get_temp_dir() . '/mustache_test'; {
if (file_exists(self::$tempDir)) { self::$tempDir = sys_get_temp_dir() . '/mustache_test';
self::rmdir(self::$tempDir); if (file_exists(self::$tempDir)) {
} self::rmdir(self::$tempDir);
} }
}
public function testConstructor() { public function testConstructor()
$loader = new Mustache_Loader_StringLoader; {
$partialsLoader = new Mustache_Loader_ArrayLoader; $loader = new Mustache_Loader_StringLoader;
$mustache = new Mustache_Engine(array( $partialsLoader = new Mustache_Loader_ArrayLoader;
'template_class_prefix' => '__whot__', $mustache = new Mustache_Engine(array(
'cache' => self::$tempDir, 'template_class_prefix' => '__whot__',
'loader' => $loader, 'cache' => self::$tempDir,
'partials_loader' => $partialsLoader, 'loader' => $loader,
'partials' => array( 'partials_loader' => $partialsLoader,
'foo' => '{{ foo }}', 'partials' => array(
), 'foo' => '{{ foo }}',
'helpers' => array( ),
'foo' => array($this, 'getFoo'), 'helpers' => array(
'bar' => 'BAR', 'foo' => array($this, 'getFoo'),
), 'bar' => 'BAR',
'escape' => 'strtoupper', ),
'charset' => 'ISO-8859-1', 'escape' => 'strtoupper',
)); 'charset' => 'ISO-8859-1',
));
$this->assertSame($loader, $mustache->getLoader()); $this->assertSame($loader, $mustache->getLoader());
$this->assertSame($partialsLoader, $mustache->getPartialsLoader()); $this->assertSame($partialsLoader, $mustache->getPartialsLoader());
$this->assertEquals('{{ foo }}', $partialsLoader->load('foo')); $this->assertEquals('{{ foo }}', $partialsLoader->load('foo'));
$this->assertContains('__whot__', $mustache->getTemplateClassName('{{ foo }}')); $this->assertContains('__whot__', $mustache->getTemplateClassName('{{ foo }}'));
$this->assertEquals('strtoupper', $mustache->getEscape()); $this->assertEquals('strtoupper', $mustache->getEscape());
$this->assertEquals('ISO-8859-1', $mustache->getCharset()); $this->assertEquals('ISO-8859-1', $mustache->getCharset());
$this->assertTrue($mustache->hasHelper('foo')); $this->assertTrue($mustache->hasHelper('foo'));
$this->assertTrue($mustache->hasHelper('bar')); $this->assertTrue($mustache->hasHelper('bar'));
$this->assertFalse($mustache->hasHelper('baz')); $this->assertFalse($mustache->hasHelper('baz'));
} }
public static function getFoo() { public static function getFoo()
return 'foo'; {
} return 'foo';
}
public function testRender() { public function testRender()
$source = '{{ foo }}'; {
$data = array('bar' => 'baz'); $source = '{{ foo }}';
$output = 'TEH OUTPUT'; $data = array('bar' => 'baz');
$output = 'TEH OUTPUT';
$template = $this->getMockBuilder('Mustache_Template') $template = $this->getMockBuilder('Mustache_Template')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
$mustache = new MustacheStub; $mustache = new MustacheStub;
$mustache->template = $template; $mustache->template = $template;
$template->expects($this->once()) $template->expects($this->once())
->method('render') ->method('render')
->with($data) ->with($data)
->will($this->returnValue($output)); ->will($this->returnValue($output));
$this->assertEquals($output, $mustache->render($source, $data)); $this->assertEquals($output, $mustache->render($source, $data));
$this->assertEquals($source, $mustache->source); $this->assertEquals($source, $mustache->source);
} }
public function testSettingServices() { public function testSettingServices()
$loader = new Mustache_Loader_StringLoader; {
$tokenizer = new Mustache_Tokenizer; $loader = new Mustache_Loader_StringLoader;
$parser = new Mustache_Parser; $tokenizer = new Mustache_Tokenizer;
$compiler = new Mustache_Compiler; $parser = new Mustache_Parser;
$mustache = new Mustache_Engine; $compiler = new Mustache_Compiler;
$mustache = new Mustache_Engine;
$this->assertNotSame($loader, $mustache->getLoader()); $this->assertNotSame($loader, $mustache->getLoader());
$mustache->setLoader($loader); $mustache->setLoader($loader);
$this->assertSame($loader, $mustache->getLoader()); $this->assertSame($loader, $mustache->getLoader());
$this->assertNotSame($loader, $mustache->getPartialsLoader()); $this->assertNotSame($loader, $mustache->getPartialsLoader());
$mustache->setPartialsLoader($loader); $mustache->setPartialsLoader($loader);
$this->assertSame($loader, $mustache->getPartialsLoader()); $this->assertSame($loader, $mustache->getPartialsLoader());
$this->assertNotSame($tokenizer, $mustache->getTokenizer()); $this->assertNotSame($tokenizer, $mustache->getTokenizer());
$mustache->setTokenizer($tokenizer); $mustache->setTokenizer($tokenizer);
$this->assertSame($tokenizer, $mustache->getTokenizer()); $this->assertSame($tokenizer, $mustache->getTokenizer());
$this->assertNotSame($parser, $mustache->getParser()); $this->assertNotSame($parser, $mustache->getParser());
$mustache->setParser($parser); $mustache->setParser($parser);
$this->assertSame($parser, $mustache->getParser()); $this->assertSame($parser, $mustache->getParser());
$this->assertNotSame($compiler, $mustache->getCompiler()); $this->assertNotSame($compiler, $mustache->getCompiler());
$mustache->setCompiler($compiler); $mustache->setCompiler($compiler);
$this->assertSame($compiler, $mustache->getCompiler()); $this->assertSame($compiler, $mustache->getCompiler());
} }
/** /**
* @group functional * @group functional
*/ */
public function testCache() { public function testCache()
$mustache = new Mustache_Engine(array( {
'template_class_prefix' => '__whot__', $mustache = new Mustache_Engine(array(
'cache' => self::$tempDir, 'template_class_prefix' => '__whot__',
)); 'cache' => self::$tempDir,
));
$source = '{{ foo }}'; $source = '{{ foo }}';
$template = $mustache->loadTemplate($source); $template = $mustache->loadTemplate($source);
$className = $mustache->getTemplateClassName($source); $className = $mustache->getTemplateClassName($source);
$fileName = self::$tempDir . '/' . $className . '.php'; $fileName = self::$tempDir . '/' . $className . '.php';
$this->assertInstanceOf($className, $template); $this->assertInstanceOf($className, $template);
$this->assertFileExists($fileName); $this->assertFileExists($fileName);
$this->assertContains("\nclass $className extends Mustache_Template", file_get_contents($fileName)); $this->assertContains("\nclass $className extends Mustache_Template", file_get_contents($fileName));
} }
/** /**
* @expectedException InvalidArgumentException * @expectedException InvalidArgumentException
* @dataProvider getBadEscapers * @dataProvider getBadEscapers
*/ */
public function testNonCallableEscapeThrowsException($escape) { public function testNonCallableEscapeThrowsException($escape)
new Mustache_Engine(array('escape' => $escape)); {
} new Mustache_Engine(array('escape' => $escape));
}
public function getBadEscapers() { public function getBadEscapers()
return array( {
array('nothing'), return array(
array('foo', 'bar'), array('nothing'),
); array('foo', 'bar'),
} );
}
/** /**
* @expectedException RuntimeException * @expectedException RuntimeException
*/ */
public function testImmutablePartialsLoadersThrowException() { public function testImmutablePartialsLoadersThrowException()
$mustache = new Mustache_Engine(array( {
'partials_loader' => new Mustache_Loader_StringLoader, $mustache = new Mustache_Engine(array(
)); 'partials_loader' => new Mustache_Loader_StringLoader,
));
$mustache->setPartials(array('foo' => '{{ foo }}')); $mustache->setPartials(array('foo' => '{{ foo }}'));
} }
public function testMissingPartialsTreatedAsEmptyString() { public function testMissingPartialsTreatedAsEmptyString()
$mustache = new Mustache_Engine(array( {
'partials_loader' => new Mustache_Loader_ArrayLoader(array( $mustache = new Mustache_Engine(array(
'foo' => 'FOO', 'partials_loader' => new Mustache_Loader_ArrayLoader(array(
'baz' => 'BAZ', 'foo' => 'FOO',
)) 'baz' => 'BAZ',
)); ))
));
$this->assertEquals('FOOBAZ', $mustache->render('{{>foo}}{{>bar}}{{>baz}}', array())); $this->assertEquals('FOOBAZ', $mustache->render('{{>foo}}{{>bar}}{{>baz}}', array()));
} }
public function testHelpers() { public function testHelpers()
$foo = array($this, 'getFoo'); {
$bar = 'BAR'; $foo = array($this, 'getFoo');
$mustache = new Mustache_Engine(array('helpers' => array( $bar = 'BAR';
'foo' => $foo, $mustache = new Mustache_Engine(array('helpers' => array(
'bar' => $bar, 'foo' => $foo,
))); 'bar' => $bar,
)));
$helpers = $mustache->getHelpers(); $helpers = $mustache->getHelpers();
$this->assertTrue($mustache->hasHelper('foo')); $this->assertTrue($mustache->hasHelper('foo'));
$this->assertTrue($mustache->hasHelper('bar')); $this->assertTrue($mustache->hasHelper('bar'));
$this->assertTrue($helpers->has('foo')); $this->assertTrue($helpers->has('foo'));
$this->assertTrue($helpers->has('bar')); $this->assertTrue($helpers->has('bar'));
$this->assertSame($foo, $mustache->getHelper('foo')); $this->assertSame($foo, $mustache->getHelper('foo'));
$this->assertSame($bar, $mustache->getHelper('bar')); $this->assertSame($bar, $mustache->getHelper('bar'));
$mustache->removeHelper('bar'); $mustache->removeHelper('bar');
$this->assertFalse($mustache->hasHelper('bar')); $this->assertFalse($mustache->hasHelper('bar'));
$mustache->addHelper('bar', $bar); $mustache->addHelper('bar', $bar);
$this->assertSame($bar, $mustache->getHelper('bar')); $this->assertSame($bar, $mustache->getHelper('bar'));
$baz = array($this, 'wrapWithUnderscores'); $baz = array($this, 'wrapWithUnderscores');
$this->assertFalse($mustache->hasHelper('baz')); $this->assertFalse($mustache->hasHelper('baz'));
$this->assertFalse($helpers->has('baz')); $this->assertFalse($helpers->has('baz'));
$mustache->addHelper('baz', $baz); $mustache->addHelper('baz', $baz);
$this->assertTrue($mustache->hasHelper('baz')); $this->assertTrue($mustache->hasHelper('baz'));
$this->assertTrue($helpers->has('baz')); $this->assertTrue($helpers->has('baz'));
// ... and a functional test // ... and a functional test
$tpl = $mustache->loadTemplate('{{foo}} - {{bar}} - {{#baz}}qux{{/baz}}'); $tpl = $mustache->loadTemplate('{{foo}} - {{bar}} - {{#baz}}qux{{/baz}}');
$this->assertEquals('foo - BAR - __qux__', $tpl->render()); $this->assertEquals('foo - BAR - __qux__', $tpl->render());
$this->assertEquals('foo - BAR - __qux__', $tpl->render(array('qux' => "won't mess things up"))); $this->assertEquals('foo - BAR - __qux__', $tpl->render(array('qux' => "won't mess things up")));
} }
public static function wrapWithUnderscores($text) { public static function wrapWithUnderscores($text)
return '__'.$text.'__'; {
} return '__'.$text.'__';
}
/** /**
* @expectedException InvalidArgumentException * @expectedException InvalidArgumentException
*/ */
public function testSetHelpersThrowsExceptions() { public function testSetHelpersThrowsExceptions()
$mustache = new Mustache_Engine; {
$mustache->setHelpers('monkeymonkeymonkey'); $mustache = new Mustache_Engine;
} $mustache->setHelpers('monkeymonkeymonkey');
}
private static function rmdir($path) { private static function rmdir($path)
$path = rtrim($path, '/').'/'; {
$handle = opendir($path); $path = rtrim($path, '/').'/';
while (($file = readdir($handle)) !== false) { $handle = opendir($path);
if ($file == '.' || $file == '..') { while (($file = readdir($handle)) !== false) {
continue; if ($file == '.' || $file == '..') {
} continue;
}
$fullpath = $path.$file; $fullpath = $path.$file;
if (is_dir($fullpath)) { if (is_dir($fullpath)) {
self::rmdir($fullpath); self::rmdir($fullpath);
} else { } else {
unlink($fullpath); unlink($fullpath);
} }
} }
closedir($handle); closedir($handle);
rmdir($path); rmdir($path);
} }
} }
class MustacheStub extends Mustache_Engine { class MustacheStub extends Mustache_Engine {
public $source; public $source;
public $template; public $template;
public function loadTemplate($source) { public function loadTemplate($source)
$this->source = $source; {
$this->source = $source;
return $this->template; return $this->template;
} }
} }
+18 -14
View File
@@ -13,24 +13,28 @@
* @group magic_methods * @group magic_methods
* @group functional * @group functional
*/ */
class Mustache_Test_Functional_CallTest extends PHPUnit_Framework_TestCase { class Mustache_Test_Functional_CallTest extends PHPUnit_Framework_TestCase
{
public function testCallEatsContext() { public function testCallEatsContext()
$m = new Mustache_Engine; {
$tpl = $m->loadTemplate('{{# foo }}{{ label }}: {{ name }}{{/ foo }}'); $m = new Mustache_Engine;
$tpl = $m->loadTemplate('{{# foo }}{{ label }}: {{ name }}{{/ foo }}');
$foo = new Mustache_Test_Functional_ClassWithCall(); $foo = new Mustache_Test_Functional_ClassWithCall();
$foo->name = 'Bob'; $foo->name = 'Bob';
$data = array('label' => 'name', 'foo' => $foo); $data = array('label' => 'name', 'foo' => $foo);
$this->assertEquals('name: Bob', $tpl->render($data)); $this->assertEquals('name: Bob', $tpl->render($data));
} }
} }
class Mustache_Test_Functional_ClassWithCall { class Mustache_Test_Functional_ClassWithCall
public $name; {
public function __call($method, $args) { public $name;
return 'unknown value'; public function __call($method, $args)
} {
return 'unknown value';
}
} }
+110 -105
View File
@@ -13,125 +13,130 @@
* @group examples * @group examples
* @group functional * @group functional
*/ */
class Mustache_Test_Functional_ExamplesTest extends PHPUnit_Framework_TestCase { class Mustache_Test_Functional_ExamplesTest extends PHPUnit_Framework_TestCase
{
/** /**
* Test everything in the `examples` directory. * Test everything in the `examples` directory.
* *
* @dataProvider getExamples * @dataProvider getExamples
* *
* @param string $context * @param string $context
* @param string $source * @param string $source
* @param array $partials * @param array $partials
* @param string $expected * @param string $expected
*/ */
public function testExamples($context, $source, $partials, $expected) { public function testExamples($context, $source, $partials, $expected)
$mustache = new Mustache_Engine(array( {
'partials' => $partials $mustache = new Mustache_Engine(array(
)); 'partials' => $partials
$this->assertEquals($expected, $mustache->loadTemplate($source)->render($context)); ));
} $this->assertEquals($expected, $mustache->loadTemplate($source)->render($context));
}
/** /**
* Data provider for testExamples method. * Data provider for testExamples method.
* *
* Loads examples from the test fixtures directory. * Loads examples from the test fixtures directory.
* *
* This examples directory should contain any number of subdirectories, each of which contains * 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 * three files: one Mustache class (.php), one Mustache template (.mustache), and one output file
* (.txt). Optionally, the directory may contain a folder full of partials. * (.txt). Optionally, the directory may contain a folder full of partials.
* *
* @return array * @return array
*/ */
public function getExamples() { public function getExamples()
$path = realpath(dirname(__FILE__).'/../../../fixtures/examples'); {
$examples = array(); $path = realpath(dirname(__FILE__).'/../../../fixtures/examples');
$examples = array();
$handle = opendir($path); $handle = opendir($path);
while (($file = readdir($handle)) !== false) { while (($file = readdir($handle)) !== false) {
if ($file == '.' || $file == '..') { if ($file == '.' || $file == '..') {
continue; continue;
} }
$fullpath = $path.'/'.$file; $fullpath = $path.'/'.$file;
if (is_dir($fullpath)) { if (is_dir($fullpath)) {
$examples[$file] = $this->loadExample($fullpath); $examples[$file] = $this->loadExample($fullpath);
} }
} }
closedir($handle); closedir($handle);
return $examples; return $examples;
} }
/** /**
* Helper method to load an example given the full path. * Helper method to load an example given the full path.
* *
* @param string $path * @param string $path
* *
* @return array arguments for testExamples * @return array arguments for testExamples
*/ */
private function loadExample($path) { private function loadExample($path)
$context = null; {
$source = null; $context = null;
$partials = array(); $source = null;
$expected = null; $partials = array();
$expected = null;
$handle = opendir($path); $handle = opendir($path);
while (($file = readdir($handle)) !== false) { while (($file = readdir($handle)) !== false) {
$fullpath = $path.'/'.$file; $fullpath = $path.'/'.$file;
$info = pathinfo($fullpath); $info = pathinfo($fullpath);
if (is_dir($fullpath) && $info['basename'] == 'partials') { if (is_dir($fullpath) && $info['basename'] == 'partials') {
// load partials // load partials
$partials = $this->loadPartials($fullpath); $partials = $this->loadPartials($fullpath);
} elseif (is_file($fullpath)) { } elseif (is_file($fullpath)) {
// load other files // load other files
switch ($info['extension']) { switch ($info['extension']) {
case 'php': case 'php':
require_once($fullpath); require_once($fullpath);
$context = new $info['filename']; $context = new $info['filename'];
break; break;
case 'mustache': case 'mustache':
$source = file_get_contents($fullpath); $source = file_get_contents($fullpath);
break; break;
case 'txt': case 'txt':
$expected = file_get_contents($fullpath); $expected = file_get_contents($fullpath);
break; break;
} }
} }
} }
closedir($handle); closedir($handle);
return array($context, $source, $partials, $expected); return array($context, $source, $partials, $expected);
} }
/** /**
* Helper method to load partials given an example directory. * Helper method to load partials given an example directory.
* *
* @param string $path * @param string $path
* *
* @return array $partials * @return array $partials
*/ */
private function loadPartials($path) { private function loadPartials($path)
$partials = array(); {
$partials = array();
$handle = opendir($path); $handle = opendir($path);
while (($file = readdir($handle)) !== false) { while (($file = readdir($handle)) !== false) {
if ($file == '.' || $file == '..') { if ($file == '.' || $file == '..') {
continue; continue;
} }
$fullpath = $path.'/'.$file; $fullpath = $path.'/'.$file;
$info = pathinfo($fullpath); $info = pathinfo($fullpath);
if ($info['extension'] === 'mustache') { if ($info['extension'] === 'mustache') {
$partials[$info['filename']] = file_get_contents($fullpath); $partials[$info['filename']] = file_get_contents($fullpath);
} }
} }
closedir($handle); closedir($handle);
return $partials; return $partials;
} }
} }
@@ -13,82 +13,94 @@
* @group lambdas * @group lambdas
* @group functional * @group functional
*/ */
class Mustache_Test_Functional_HigherOrderSectionsTest extends PHPUnit_Framework_TestCase { class Mustache_Test_Functional_HigherOrderSectionsTest extends PHPUnit_Framework_TestCase
{
private $mustache; private $mustache;
public function setUp() { public function setUp()
$this->mustache = new Mustache_Engine; {
} $this->mustache = new Mustache_Engine;
}
public function testRuntimeSectionCallback() { public function testRuntimeSectionCallback()
$tpl = $this->mustache->loadTemplate('{{#doublewrap}}{{name}}{{/doublewrap}}'); {
$tpl = $this->mustache->loadTemplate('{{#doublewrap}}{{name}}{{/doublewrap}}');
$foo = new Mustache_Test_Functional_Foo; $foo = new Mustache_Test_Functional_Foo;
$foo->doublewrap = array($foo, 'wrapWithBoth'); $foo->doublewrap = array($foo, 'wrapWithBoth');
$this->assertEquals(sprintf('<strong><em>%s</em></strong>', $foo->name), $tpl->render($foo)); $this->assertEquals(sprintf('<strong><em>%s</em></strong>', $foo->name), $tpl->render($foo));
} }
public function testStaticSectionCallback() { public function testStaticSectionCallback()
$tpl = $this->mustache->loadTemplate('{{#trimmer}} {{name}} {{/trimmer}}'); {
$tpl = $this->mustache->loadTemplate('{{#trimmer}} {{name}} {{/trimmer}}');
$foo = new Mustache_Test_Functional_Foo; $foo = new Mustache_Test_Functional_Foo;
$foo->trimmer = array(get_class($foo), 'staticTrim'); $foo->trimmer = array(get_class($foo), 'staticTrim');
$this->assertEquals($foo->name, $tpl->render($foo)); $this->assertEquals($foo->name, $tpl->render($foo));
} }
public function testViewArraySectionCallback() { public function testViewArraySectionCallback()
$tpl = $this->mustache->loadTemplate('{{#trim}} {{name}} {{/trim}}'); {
$tpl = $this->mustache->loadTemplate('{{#trim}} {{name}} {{/trim}}');
$foo = new Mustache_Test_Functional_Foo; $foo = new Mustache_Test_Functional_Foo;
$data = array( $data = array(
'name' => 'Bob', 'name' => 'Bob',
'trim' => array(get_class($foo), 'staticTrim'), 'trim' => array(get_class($foo), 'staticTrim'),
); );
$this->assertEquals($data['name'], $tpl->render($data)); $this->assertEquals($data['name'], $tpl->render($data));
} }
public function testMonsters() { public function testMonsters()
$tpl = $this->mustache->loadTemplate('{{#title}}{{title}} {{/title}}{{name}}'); {
$tpl = $this->mustache->loadTemplate('{{#title}}{{title}} {{/title}}{{name}}');
$frank = new Mustache_Test_Functional_Monster(); $frank = new Mustache_Test_Functional_Monster();
$frank->title = 'Dr.'; $frank->title = 'Dr.';
$frank->name = 'Frankenstein'; $frank->name = 'Frankenstein';
$this->assertEquals('Dr. Frankenstein', $tpl->render($frank)); $this->assertEquals('Dr. Frankenstein', $tpl->render($frank));
$dracula = new Mustache_Test_Functional_Monster(); $dracula = new Mustache_Test_Functional_Monster();
$dracula->title = 'Count'; $dracula->title = 'Count';
$dracula->name = 'Dracula'; $dracula->name = 'Dracula';
$this->assertEquals('Count Dracula', $tpl->render($dracula)); $this->assertEquals('Count Dracula', $tpl->render($dracula));
} }
} }
class Mustache_Test_Functional_Foo { class Mustache_Test_Functional_Foo
public $name = 'Justin'; {
public $lorem = 'Lorem ipsum dolor sit amet,'; public $name = 'Justin';
public $lorem = 'Lorem ipsum dolor sit amet,';
public function wrapWithEm($text) { public function wrapWithEm($text)
return sprintf('<em>%s</em>', $text); {
} return sprintf('<em>%s</em>', $text);
}
public function wrapWithStrong($text) { public function wrapWithStrong($text)
return sprintf('<strong>%s</strong>', $text); {
} return sprintf('<strong>%s</strong>', $text);
}
public function wrapWithBoth($text) { public function wrapWithBoth($text)
return self::wrapWithStrong(self::wrapWithEm($text)); {
} return self::wrapWithStrong(self::wrapWithEm($text));
}
public static function staticTrim($text) { public static function staticTrim($text)
return trim($text); {
} return trim($text);
}
} }
class Mustache_Test_Functional_Monster { class Mustache_Test_Functional_Monster
public $title; {
public $name; public $title;
public $name;
} }
@@ -13,128 +13,140 @@
* @group mustache_injection * @group mustache_injection
* @group functional * @group functional
*/ */
class Mustache_Test_Functional_MustacheInjectionTest extends PHPUnit_Framework_TestCase { class Mustache_Test_Functional_MustacheInjectionTest extends PHPUnit_Framework_TestCase
{
private $mustache; private $mustache;
public function setUp() { public function setUp()
$this->mustache = new Mustache_Engine; {
} $this->mustache = new Mustache_Engine;
}
// interpolation // interpolation
public function testInterpolationInjection() { public function testInterpolationInjection()
$tpl = $this->mustache->loadTemplate('{{ a }}'); {
$tpl = $this->mustache->loadTemplate('{{ a }}');
$data = array( $data = array(
'a' => '{{ b }}', 'a' => '{{ b }}',
'b' => 'FAIL' 'b' => 'FAIL'
); );
$this->assertEquals('{{ b }}', $tpl->render($data)); $this->assertEquals('{{ b }}', $tpl->render($data));
} }
public function testUnescapedInterpolationInjection() { public function testUnescapedInterpolationInjection()
$tpl = $this->mustache->loadTemplate('{{{ a }}}'); {
$tpl = $this->mustache->loadTemplate('{{{ a }}}');
$data = array( $data = array(
'a' => '{{ b }}', 'a' => '{{ b }}',
'b' => 'FAIL' 'b' => 'FAIL'
); );
$this->assertEquals('{{ b }}', $tpl->render($data)); $this->assertEquals('{{ b }}', $tpl->render($data));
} }
// sections // sections
public function testSectionInjection() { public function testSectionInjection()
$tpl = $this->mustache->loadTemplate('{{# a }}{{ b }}{{/ a }}'); {
$tpl = $this->mustache->loadTemplate('{{# a }}{{ b }}{{/ a }}');
$data = array( $data = array(
'a' => true, 'a' => true,
'b' => '{{ c }}', 'b' => '{{ c }}',
'c' => 'FAIL' 'c' => 'FAIL'
); );
$this->assertEquals('{{ c }}', $tpl->render($data)); $this->assertEquals('{{ c }}', $tpl->render($data));
} }
public function testUnescapedSectionInjection() { public function testUnescapedSectionInjection()
$tpl = $this->mustache->loadTemplate('{{# a }}{{{ b }}}{{/ a }}'); {
$tpl = $this->mustache->loadTemplate('{{# a }}{{{ b }}}{{/ a }}');
$data = array( $data = array(
'a' => true, 'a' => true,
'b' => '{{ c }}', 'b' => '{{ c }}',
'c' => 'FAIL' 'c' => 'FAIL'
); );
$this->assertEquals('{{ c }}', $tpl->render($data)); $this->assertEquals('{{ c }}', $tpl->render($data));
} }
// partials // partials
public function testPartialInjection() { public function testPartialInjection()
$tpl = $this->mustache->loadTemplate('{{> partial }}'); {
$this->mustache->setPartials(array( $tpl = $this->mustache->loadTemplate('{{> partial }}');
'partial' => '{{ a }}', $this->mustache->setPartials(array(
)); 'partial' => '{{ a }}',
));
$data = array( $data = array(
'a' => '{{ b }}', 'a' => '{{ b }}',
'b' => 'FAIL' 'b' => 'FAIL'
); );
$this->assertEquals('{{ b }}', $tpl->render($data)); $this->assertEquals('{{ b }}', $tpl->render($data));
} }
public function testPartialUnescapedInjection() { public function testPartialUnescapedInjection()
$tpl = $this->mustache->loadTemplate('{{> partial }}'); {
$this->mustache->setPartials(array( $tpl = $this->mustache->loadTemplate('{{> partial }}');
'partial' => '{{{ a }}}', $this->mustache->setPartials(array(
)); 'partial' => '{{{ a }}}',
));
$data = array( $data = array(
'a' => '{{ b }}', 'a' => '{{ b }}',
'b' => 'FAIL' 'b' => 'FAIL'
); );
$this->assertEquals('{{ b }}', $tpl->render($data)); $this->assertEquals('{{ b }}', $tpl->render($data));
} }
// lambdas // lambdas
public function testLambdaInterpolationInjection() { public function testLambdaInterpolationInjection()
$tpl = $this->mustache->loadTemplate('{{ a }}'); {
$tpl = $this->mustache->loadTemplate('{{ a }}');
$data = array( $data = array(
'a' => array($this, 'lambdaInterpolationCallback'), 'a' => array($this, 'lambdaInterpolationCallback'),
'b' => '{{ c }}', 'b' => '{{ c }}',
'c' => 'FAIL' 'c' => 'FAIL'
); );
$this->assertEquals('{{ c }}', $tpl->render($data)); $this->assertEquals('{{ c }}', $tpl->render($data));
} }
public static function lambdaInterpolationCallback() { public static function lambdaInterpolationCallback()
return '{{ b }}'; {
} return '{{ b }}';
}
public function testLambdaSectionInjection() { public function testLambdaSectionInjection()
$tpl = $this->mustache->loadTemplate('{{# a }}b{{/ a }}'); {
$tpl = $this->mustache->loadTemplate('{{# a }}b{{/ a }}');
$data = array( $data = array(
'a' => array($this, 'lambdaSectionCallback'), 'a' => array($this, 'lambdaSectionCallback'),
'b' => '{{ c }}', 'b' => '{{ c }}',
'c' => 'FAIL' 'c' => 'FAIL'
); );
$this->assertEquals('{{ c }}', $tpl->render($data)); $this->assertEquals('{{ c }}', $tpl->render($data));
} }
public static function lambdaSectionCallback($text) { public static function lambdaSectionCallback($text)
return '{{ ' . $text . ' }}'; {
} return '{{ ' . $text . ' }}';
}
} }
+134 -117
View File
@@ -15,144 +15,161 @@
* @group mustache-spec * @group mustache-spec
* @group functional * @group functional
*/ */
class Mustache_Test_Functional_MustacheSpecTest extends PHPUnit_Framework_TestCase { class Mustache_Test_Functional_MustacheSpecTest extends PHPUnit_Framework_TestCase
{
private static $mustache; private static $mustache;
public static function setUpBeforeClass() { public static function setUpBeforeClass()
self::$mustache = new Mustache_Engine; {
} self::$mustache = new Mustache_Engine;
}
/** /**
* For some reason data providers can't mark tests skipped, so this test exists * For some reason data providers can't mark tests skipped, so this test exists
* simply to provide a 'skipped' test if the `spec` submodule isn't initialized. * simply to provide a 'skipped' test if the `spec` submodule isn't initialized.
*/ */
public function testSpecInitialized() { public function testSpecInitialized()
if (!file_exists(dirname(__FILE__).'/../../../../vendor/spec/specs/')) { {
$this->markTestSkipped('Mustache spec submodule not initialized: run "git submodule update --init"'); if (!file_exists(dirname(__FILE__).'/../../../../vendor/spec/specs/')) {
} $this->markTestSkipped('Mustache spec submodule not initialized: run "git submodule update --init"');
} }
}
/** /**
* @group comments * @group comments
* @dataProvider loadCommentSpec * @dataProvider loadCommentSpec
*/ */
public function testCommentSpec($desc, $source, $partials, $data, $expected) { public function testCommentSpec($desc, $source, $partials, $data, $expected)
$template = self::loadTemplate($source, $partials); {
$this->assertEquals($expected, $template->render($data), $desc); $template = self::loadTemplate($source, $partials);
} $this->assertEquals($expected, $template->render($data), $desc);
}
public function loadCommentSpec() { public function loadCommentSpec()
return $this->loadSpec('comments'); {
} return $this->loadSpec('comments');
}
/** /**
* @group delimiters * @group delimiters
* @dataProvider loadDelimitersSpec * @dataProvider loadDelimitersSpec
*/ */
public function testDelimitersSpec($desc, $source, $partials, $data, $expected) { public function testDelimitersSpec($desc, $source, $partials, $data, $expected)
$template = self::loadTemplate($source, $partials); {
$this->assertEquals($expected, $template->render($data), $desc); $template = self::loadTemplate($source, $partials);
} $this->assertEquals($expected, $template->render($data), $desc);
}
public function loadDelimitersSpec() { public function loadDelimitersSpec()
return $this->loadSpec('delimiters'); {
} return $this->loadSpec('delimiters');
}
/** /**
* @group interpolation * @group interpolation
* @dataProvider loadInterpolationSpec * @dataProvider loadInterpolationSpec
*/ */
public function testInterpolationSpec($desc, $source, $partials, $data, $expected) { public function testInterpolationSpec($desc, $source, $partials, $data, $expected)
$template = self::loadTemplate($source, $partials); {
$this->assertEquals($expected, $template->render($data), $desc); $template = self::loadTemplate($source, $partials);
} $this->assertEquals($expected, $template->render($data), $desc);
}
public function loadInterpolationSpec() { public function loadInterpolationSpec()
return $this->loadSpec('interpolation'); {
} return $this->loadSpec('interpolation');
}
/** /**
* @group inverted * @group inverted
* @group inverted-sections * @group inverted-sections
* @dataProvider loadInvertedSpec * @dataProvider loadInvertedSpec
*/ */
public function testInvertedSpec($desc, $source, $partials, $data, $expected) { public function testInvertedSpec($desc, $source, $partials, $data, $expected)
$template = self::loadTemplate($source, $partials); {
$this->assertEquals($expected, $template->render($data), $desc); $template = self::loadTemplate($source, $partials);
} $this->assertEquals($expected, $template->render($data), $desc);
}
public function loadInvertedSpec() { public function loadInvertedSpec()
return $this->loadSpec('inverted'); {
} return $this->loadSpec('inverted');
}
/** /**
* @group partials * @group partials
* @dataProvider loadPartialsSpec * @dataProvider loadPartialsSpec
*/ */
public function testPartialsSpec($desc, $source, $partials, $data, $expected) { public function testPartialsSpec($desc, $source, $partials, $data, $expected)
$template = self::loadTemplate($source, $partials); {
$this->assertEquals($expected, $template->render($data), $desc); $template = self::loadTemplate($source, $partials);
} $this->assertEquals($expected, $template->render($data), $desc);
}
public function loadPartialsSpec() { public function loadPartialsSpec()
return $this->loadSpec('partials'); {
} return $this->loadSpec('partials');
}
/** /**
* @group sections * @group sections
* @dataProvider loadSectionsSpec * @dataProvider loadSectionsSpec
*/ */
public function testSectionsSpec($desc, $source, $partials, $data, $expected) { public function testSectionsSpec($desc, $source, $partials, $data, $expected)
$template = self::loadTemplate($source, $partials); {
$this->assertEquals($expected, $template->render($data), $desc); $template = self::loadTemplate($source, $partials);
} $this->assertEquals($expected, $template->render($data), $desc);
}
public function loadSectionsSpec() { public function loadSectionsSpec()
return $this->loadSpec('sections'); {
} return $this->loadSpec('sections');
}
/** /**
* Data provider for the mustache spec test. * Data provider for the mustache spec test.
* *
* Loads YAML files from the spec and converts them to PHPisms. * Loads YAML files from the spec and converts them to PHPisms.
* *
* @access public * @access public
* @return array * @return array
*/ */
private function loadSpec($name) { private function loadSpec($name)
$filename = dirname(__FILE__) . '/../../../../vendor/spec/specs/' . $name . '.yml'; {
if (!file_exists($filename)) { $filename = dirname(__FILE__) . '/../../../../vendor/spec/specs/' . $name . '.yml';
return array(); if (!file_exists($filename)) {
} return array();
}
$data = array(); $data = array();
$yaml = new sfYamlParser; $yaml = new sfYamlParser;
$file = file_get_contents($filename); $file = file_get_contents($filename);
// @hack: pre-process the 'lambdas' spec so the Symfony YAML parser doesn't complain. // @hack: pre-process the 'lambdas' spec so the Symfony YAML parser doesn't complain.
if ($name === '~lambdas') { if ($name === '~lambdas') {
$file = str_replace(" !code\n", "\n", $file); $file = str_replace(" !code\n", "\n", $file);
} }
$spec = $yaml->parse($file); $spec = $yaml->parse($file);
foreach ($spec['tests'] as $test) { foreach ($spec['tests'] as $test) {
$data[] = array( $data[] = array(
$test['name'] . ': ' . $test['desc'], $test['name'] . ': ' . $test['desc'],
$test['template'], $test['template'],
isset($test['partials']) ? $test['partials'] : array(), isset($test['partials']) ? $test['partials'] : array(),
$test['data'], $test['data'],
$test['expected'], $test['expected'],
); );
} }
return $data; return $data;
} }
private static function loadTemplate($source, $partials) { private static function loadTemplate($source, $partials)
self::$mustache->setPartials($partials); {
self::$mustache->setPartials($partials);
return self::$mustache->loadTemplate($source); return self::$mustache->loadTemplate($source);
} }
} }
@@ -13,82 +13,98 @@
* @group sections * @group sections
* @group functional * @group functional
*/ */
class Mustache_Test_Functional_ObjectSectionTest extends PHPUnit_Framework_TestCase { class Mustache_Test_Functional_ObjectSectionTest extends PHPUnit_Framework_TestCase
private $mustache; {
private $mustache;
public function setUp() { public function setUp()
$this->mustache = new Mustache_Engine; {
} $this->mustache = new Mustache_Engine;
}
public function testBasicObject() { public function testBasicObject()
$tpl = $this->mustache->loadTemplate('{{#foo}}{{name}}{{/foo}}'); {
$this->assertEquals('Foo', $tpl->render(new Mustache_Test_Functional_Alpha)); $tpl = $this->mustache->loadTemplate('{{#foo}}{{name}}{{/foo}}');
} $this->assertEquals('Foo', $tpl->render(new Mustache_Test_Functional_Alpha));
}
/** /**
* @group magic_methods * @group magic_methods
*/ */
public function testObjectWithGet() { public function testObjectWithGet()
$tpl = $this->mustache->loadTemplate('{{#foo}}{{name}}{{/foo}}'); {
$this->assertEquals('Foo', $tpl->render(new Mustache_Test_Functional_Beta)); $tpl = $this->mustache->loadTemplate('{{#foo}}{{name}}{{/foo}}');
} $this->assertEquals('Foo', $tpl->render(new Mustache_Test_Functional_Beta));
}
/** /**
* @group magic_methods * @group magic_methods
*/ */
public function testSectionObjectWithGet() { public function testSectionObjectWithGet()
$tpl = $this->mustache->loadTemplate('{{#bar}}{{#foo}}{{name}}{{/foo}}{{/bar}}'); {
$this->assertEquals('Foo', $tpl->render(new Mustache_Test_Functional_Gamma)); $tpl = $this->mustache->loadTemplate('{{#bar}}{{#foo}}{{name}}{{/foo}}{{/bar}}');
} $this->assertEquals('Foo', $tpl->render(new Mustache_Test_Functional_Gamma));
}
public function testSectionObjectWithFunction() { public function testSectionObjectWithFunction()
$tpl = $this->mustache->loadTemplate('{{#foo}}{{name}}{{/foo}}'); {
$alpha = new Mustache_Test_Functional_Alpha; $tpl = $this->mustache->loadTemplate('{{#foo}}{{name}}{{/foo}}');
$alpha->foo = new Mustache_Test_Functional_Delta; $alpha = new Mustache_Test_Functional_Alpha;
$this->assertEquals('Foo', $tpl->render($alpha)); $alpha->foo = new Mustache_Test_Functional_Delta;
} $this->assertEquals('Foo', $tpl->render($alpha));
}
} }
class Mustache_Test_Functional_Alpha { class Mustache_Test_Functional_Alpha
public $foo; {
public $foo;
public function __construct() { public function __construct()
$this->foo = new StdClass(); {
$this->foo->name = 'Foo'; $this->foo = new StdClass();
$this->foo->number = 1; $this->foo->name = 'Foo';
} $this->foo->number = 1;
}
} }
class Mustache_Test_Functional_Beta { class Mustache_Test_Functional_Beta
protected $_data = array(); {
protected $_data = array();
public function __construct() { public function __construct()
$this->_data['foo'] = new StdClass(); {
$this->_data['foo']->name = 'Foo'; $this->_data['foo'] = new StdClass();
$this->_data['foo']->number = 1; $this->_data['foo']->name = 'Foo';
} $this->_data['foo']->number = 1;
}
public function __isset($name) { public function __isset($name)
return array_key_exists($name, $this->_data); {
} return array_key_exists($name, $this->_data);
}
public function __get($name) { public function __get($name)
return $this->_data[$name]; {
} return $this->_data[$name];
}
} }
class Mustache_Test_Functional_Gamma { class Mustache_Test_Functional_Gamma
public $bar; {
public $bar;
public function __construct() { public function __construct()
$this->bar = new Mustache_Test_Functional_Beta; {
} $this->bar = new Mustache_Test_Functional_Beta;
}
} }
class Mustache_Test_Functional_Delta { class Mustache_Test_Functional_Delta
protected $_name = 'Foo'; {
protected $_name = 'Foo';
public function name() { public function name()
return $this->_name; {
} return $this->_name;
}
} }
+25 -18
View File
@@ -9,27 +9,31 @@
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
class Mustache_Test_HelperCollectionTest extends PHPUnit_Framework_TestCase { class Mustache_Test_HelperCollectionTest extends PHPUnit_Framework_TestCase
public function testConstructor() { {
$foo = array($this, 'getFoo'); public function testConstructor()
$bar = 'BAR'; {
$foo = array($this, 'getFoo');
$bar = 'BAR';
$helpers = new Mustache_HelperCollection(array( $helpers = new Mustache_HelperCollection(array(
'foo' => $foo, 'foo' => $foo,
'bar' => $bar, 'bar' => $bar,
)); ));
$this->assertSame($foo, $helpers->get('foo')); $this->assertSame($foo, $helpers->get('foo'));
$this->assertSame($bar, $helpers->get('bar')); $this->assertSame($bar, $helpers->get('bar'));
} }
public static function getFoo() { public static function getFoo()
{
echo 'foo'; echo 'foo';
} }
public function testAccessorsAndMutators() { public function testAccessorsAndMutators()
$foo = array($this, 'getFoo'); {
$bar = 'BAR'; $foo = array($this, 'getFoo');
$bar = 'BAR';
$helpers = new Mustache_HelperCollection; $helpers = new Mustache_HelperCollection;
$this->assertTrue($helpers->isEmpty()); $this->assertTrue($helpers->isEmpty());
@@ -52,7 +56,8 @@ class Mustache_Test_HelperCollectionTest extends PHPUnit_Framework_TestCase {
$this->assertTrue($helpers->has('bar')); $this->assertTrue($helpers->has('bar'));
} }
public function testMagicMethods() { public function testMagicMethods()
{
$foo = array($this, 'getFoo'); $foo = array($this, 'getFoo');
$bar = 'BAR'; $bar = 'BAR';
@@ -88,7 +93,8 @@ class Mustache_Test_HelperCollectionTest extends PHPUnit_Framework_TestCase {
/** /**
* @dataProvider getInvalidHelperArguments * @dataProvider getInvalidHelperArguments
*/ */
public function testHelperCollectionIsntAfraidToThrowExceptions($helpers = array(), $actions = array(), $exception = null) { public function testHelperCollectionIsntAfraidToThrowExceptions($helpers = array(), $actions = array(), $exception = null)
{
if ($exception) { if ($exception) {
$this->setExpectedException($exception); $this->setExpectedException($exception);
} }
@@ -100,7 +106,8 @@ class Mustache_Test_HelperCollectionTest extends PHPUnit_Framework_TestCase {
} }
} }
public function getInvalidHelperArguments() { public function getInvalidHelperArguments()
{
return array( return array(
array( array(
'not helpers', 'not helpers',
+32 -28
View File
@@ -12,37 +12,41 @@
/** /**
* @group unit * @group unit
*/ */
class Mustache_Test_Loader_ArrayLoaderTest extends PHPUnit_Framework_TestCase { class Mustache_Test_Loader_ArrayLoaderTest extends PHPUnit_Framework_TestCase
public function testConstructor() { {
$loader = new Mustache_Loader_ArrayLoader(array( public function testConstructor()
'foo' => 'bar' {
)); $loader = new Mustache_Loader_ArrayLoader(array(
'foo' => 'bar'
));
$this->assertEquals('bar', $loader->load('foo')); $this->assertEquals('bar', $loader->load('foo'));
} }
public function testSetAndLoadTemplates() { public function testSetAndLoadTemplates()
$loader = new Mustache_Loader_ArrayLoader(array( {
'foo' => 'bar' $loader = new Mustache_Loader_ArrayLoader(array(
)); 'foo' => 'bar'
$this->assertEquals('bar', $loader->load('foo')); ));
$this->assertEquals('bar', $loader->load('foo'));
$loader->setTemplate('baz', 'qux'); $loader->setTemplate('baz', 'qux');
$this->assertEquals('qux', $loader->load('baz')); $this->assertEquals('qux', $loader->load('baz'));
$loader->setTemplates(array( $loader->setTemplates(array(
'foo' => 'FOO', 'foo' => 'FOO',
'baz' => 'BAZ', 'baz' => 'BAZ',
)); ));
$this->assertEquals('FOO', $loader->load('foo')); $this->assertEquals('FOO', $loader->load('foo'));
$this->assertEquals('BAZ', $loader->load('baz')); $this->assertEquals('BAZ', $loader->load('baz'));
} }
/** /**
* @expectedException InvalidArgumentException * @expectedException InvalidArgumentException
*/ */
public function testMissingTemplatesThrowExceptions() { public function testMissingTemplatesThrowExceptions()
$loader = new Mustache_Loader_ArrayLoader; {
$loader->load('not_a_real_template'); $loader = new Mustache_Loader_ArrayLoader;
} $loader->load('not_a_real_template');
}
} }
@@ -12,35 +12,40 @@
/** /**
* @group unit * @group unit
*/ */
class Mustache_Test_Loader_FilesystemLoaderTest extends PHPUnit_Framework_TestCase { class Mustache_Test_Loader_FilesystemLoaderTest extends PHPUnit_Framework_TestCase
public function testConstructor() { {
$baseDir = realpath(dirname(__FILE__).'/../../../fixtures/templates'); public function testConstructor()
$loader = new Mustache_Loader_FilesystemLoader($baseDir, array('extension' => '.ms')); {
$this->assertEquals('alpha contents', $loader->load('alpha')); $baseDir = realpath(dirname(__FILE__).'/../../../fixtures/templates');
$this->assertEquals('beta contents', $loader->load('beta.ms')); $loader = new Mustache_Loader_FilesystemLoader($baseDir, array('extension' => '.ms'));
} $this->assertEquals('alpha contents', $loader->load('alpha'));
$this->assertEquals('beta contents', $loader->load('beta.ms'));
}
public function testLoadTemplates() { public function testLoadTemplates()
$baseDir = realpath(dirname(__FILE__).'/../../../fixtures/templates'); {
$loader = new Mustache_Loader_FilesystemLoader($baseDir); $baseDir = realpath(dirname(__FILE__).'/../../../fixtures/templates');
$this->assertEquals('one contents', $loader->load('one')); $loader = new Mustache_Loader_FilesystemLoader($baseDir);
$this->assertEquals('two contents', $loader->load('two.mustache')); $this->assertEquals('one contents', $loader->load('one'));
} $this->assertEquals('two contents', $loader->load('two.mustache'));
}
/** /**
* @expectedException RuntimeException * @expectedException RuntimeException
*/ */
public function testMissingBaseDirThrowsException() { public function testMissingBaseDirThrowsException()
$loader = new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/not_a_directory'); {
} $loader = new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/not_a_directory');
}
/** /**
* @expectedException InvalidArgumentException * @expectedException InvalidArgumentException
*/ */
public function testMissingTemplateThrowsException() { public function testMissingTemplateThrowsException()
$baseDir = realpath(dirname(__FILE__).'/../../../fixtures/templates'); {
$loader = new Mustache_Loader_FilesystemLoader($baseDir); $baseDir = realpath(dirname(__FILE__).'/../../../fixtures/templates');
$loader = new Mustache_Loader_FilesystemLoader($baseDir);
$loader->load('fake'); $loader->load('fake');
} }
} }
@@ -12,12 +12,14 @@
/** /**
* @group unit * @group unit
*/ */
class Mustache_Test_Loader_StringLoaderTest extends PHPUnit_Framework_TestCase { class Mustache_Test_Loader_StringLoaderTest extends PHPUnit_Framework_TestCase
public function testLoadTemplates() { {
$loader = new Mustache_Loader_StringLoader; public function testLoadTemplates()
{
$loader = new Mustache_Loader_StringLoader;
$this->assertEquals('foo', $loader->load('foo')); $this->assertEquals('foo', $loader->load('foo'));
$this->assertEquals('{{ bar }}', $loader->load('{{ bar }}')); $this->assertEquals('{{ bar }}', $loader->load('{{ bar }}'));
$this->assertEquals("\n{{! comment }}\n", $loader->load("\n{{! comment }}\n")); $this->assertEquals("\n{{! comment }}\n", $loader->load("\n{{! comment }}\n"));
} }
} }
+156 -153
View File
@@ -12,168 +12,171 @@
/** /**
* @group unit * @group unit
*/ */
class Mustache_Test_ParserTest extends PHPUnit_Framework_TestCase { class Mustache_Test_ParserTest extends PHPUnit_Framework_TestCase
{
/** /**
* @dataProvider getTokenSets * @dataProvider getTokenSets
*/ */
public function testParse($tokens, $expected) public function testParse($tokens, $expected)
{ {
$parser = new Mustache_Parser; $parser = new Mustache_Parser;
$this->assertEquals($expected, $parser->parse($tokens)); $this->assertEquals($expected, $parser->parse($tokens));
} }
public function getTokenSets() public function getTokenSets()
{ {
return array( return array(
array( array(
array(), array(),
array() array()
), ),
array( array(
array(array( array(array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::VALUE => 'text' Mustache_Tokenizer::VALUE => 'text'
)), )),
array(array( array(array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::VALUE => 'text' Mustache_Tokenizer::VALUE => 'text'
)), )),
), ),
array( array(
array(array( array(array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED,
Mustache_Tokenizer::NAME => 'name' Mustache_Tokenizer::NAME => 'name'
)), )),
array(array( array(array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED,
Mustache_Tokenizer::NAME => 'name' Mustache_Tokenizer::NAME => 'name'
)), )),
), ),
array( array(
array( array(
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::VALUE => 'foo' Mustache_Tokenizer::VALUE => 'foo'
), ),
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_INVERTED, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_INVERTED,
Mustache_Tokenizer::INDEX => 123, Mustache_Tokenizer::INDEX => 123,
Mustache_Tokenizer::NAME => 'parent' Mustache_Tokenizer::NAME => 'parent'
), ),
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED,
Mustache_Tokenizer::NAME => 'name' Mustache_Tokenizer::NAME => 'name'
), ),
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_END_SECTION, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_END_SECTION,
Mustache_Tokenizer::INDEX => 456, Mustache_Tokenizer::INDEX => 456,
Mustache_Tokenizer::NAME => 'parent' Mustache_Tokenizer::NAME => 'parent'
), ),
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::VALUE => 'bar' Mustache_Tokenizer::VALUE => 'bar'
), ),
), ),
array( array(
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::VALUE => 'foo' Mustache_Tokenizer::VALUE => 'foo'
), ),
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_INVERTED, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_INVERTED,
Mustache_Tokenizer::NAME => 'parent', Mustache_Tokenizer::NAME => 'parent',
Mustache_Tokenizer::INDEX => 123, Mustache_Tokenizer::INDEX => 123,
Mustache_Tokenizer::END => 456, Mustache_Tokenizer::END => 456,
Mustache_Tokenizer::NODES => array( Mustache_Tokenizer::NODES => array(
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED,
Mustache_Tokenizer::NAME => 'name' Mustache_Tokenizer::NAME => 'name'
), ),
), ),
), ),
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::VALUE => 'bar' Mustache_Tokenizer::VALUE => 'bar'
), ),
), ),
), ),
); );
} }
/** /**
* @dataProvider getBadParseTrees * @dataProvider getBadParseTrees
* @expectedException LogicException * @expectedException LogicException
*/ */
public function testParserThrowsExceptions($tokens) { public function testParserThrowsExceptions($tokens)
$parser = new Mustache_Parser; {
$parser->parse($tokens); $parser = new Mustache_Parser;
} $parser->parse($tokens);
}
public function getBadParseTrees() { public function getBadParseTrees()
return array( {
// no close return array(
array( // no close
array( array(
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_SECTION, array(
Mustache_Tokenizer::NAME => 'parent', Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_SECTION,
Mustache_Tokenizer::INDEX => 123, Mustache_Tokenizer::NAME => 'parent',
), Mustache_Tokenizer::INDEX => 123,
), ),
), ),
),
// no close inverted // no close inverted
array( array(
array( array(
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_INVERTED, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_INVERTED,
Mustache_Tokenizer::NAME => 'parent', Mustache_Tokenizer::NAME => 'parent',
Mustache_Tokenizer::INDEX => 123, Mustache_Tokenizer::INDEX => 123,
), ),
), ),
), ),
// no opening inverted // no opening inverted
array( array(
array( array(
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_END_SECTION, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_END_SECTION,
Mustache_Tokenizer::NAME => 'parent', Mustache_Tokenizer::NAME => 'parent',
Mustache_Tokenizer::INDEX => 123, Mustache_Tokenizer::INDEX => 123,
), ),
), ),
), ),
// weird nesting // weird nesting
array( array(
array( array(
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_SECTION, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_SECTION,
Mustache_Tokenizer::NAME => 'parent', Mustache_Tokenizer::NAME => 'parent',
Mustache_Tokenizer::INDEX => 123, Mustache_Tokenizer::INDEX => 123,
), ),
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_SECTION, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_SECTION,
Mustache_Tokenizer::NAME => 'child', Mustache_Tokenizer::NAME => 'child',
Mustache_Tokenizer::INDEX => 123, Mustache_Tokenizer::INDEX => 123,
), ),
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_END_SECTION, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_END_SECTION,
Mustache_Tokenizer::NAME => 'parent', Mustache_Tokenizer::NAME => 'parent',
Mustache_Tokenizer::INDEX => 123, Mustache_Tokenizer::INDEX => 123,
), ),
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_END_SECTION, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_END_SECTION,
Mustache_Tokenizer::NAME => 'child', Mustache_Tokenizer::NAME => 'child',
Mustache_Tokenizer::INDEX => 123, Mustache_Tokenizer::INDEX => 123,
), ),
), ),
), ),
); );
} }
} }
+33 -27
View File
@@ -12,38 +12,44 @@
/** /**
* @group unit * @group unit
*/ */
class Mustache_Test_TemplateTest extends PHPUnit_Framework_TestCase { class Mustache_Test_TemplateTest extends PHPUnit_Framework_TestCase
public function testConstructor() { {
$mustache = new Mustache_Engine; public function testConstructor()
$template = new Mustache_Test_TemplateStub($mustache); {
$this->assertSame($mustache, $template->getMustache()); $mustache = new Mustache_Engine;
} $template = new Mustache_Test_TemplateStub($mustache);
$this->assertSame($mustache, $template->getMustache());
}
public function testRendering() { public function testRendering()
$rendered = '<< wheee >>'; {
$mustache = new Mustache_Engine; $rendered = '<< wheee >>';
$template = new Mustache_Test_TemplateStub($mustache); $mustache = new Mustache_Engine;
$template->rendered = $rendered; $template = new Mustache_Test_TemplateStub($mustache);
$context = new Mustache_Context; $template->rendered = $rendered;
$context = new Mustache_Context;
if (version_compare(PHP_VERSION, '5.3.0', '>=')) { if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
$this->assertEquals($rendered, $template()); $this->assertEquals($rendered, $template());
} }
$this->assertEquals($rendered, $template->render()); $this->assertEquals($rendered, $template->render());
$this->assertEquals($rendered, $template->renderInternal($context)); $this->assertEquals($rendered, $template->renderInternal($context));
$this->assertEquals($rendered, $template->render(array('foo' => 'bar'))); $this->assertEquals($rendered, $template->render(array('foo' => 'bar')));
} }
} }
class Mustache_Test_TemplateStub extends Mustache_Template { class Mustache_Test_TemplateStub extends Mustache_Template
public $rendered; {
public $rendered;
public function getMustache() { public function getMustache()
return $this->mustache; {
} return $this->mustache;
}
public function renderInternal(Mustache_Context $context, $indent = '', $escape = false) { public function renderInternal(Mustache_Context $context, $indent = '', $escape = false)
return $this->rendered; {
} return $this->rendered;
}
} }
+121 -118
View File
@@ -12,130 +12,133 @@
/** /**
* @group unit * @group unit
*/ */
class Mustache_Test_TokenizerTest extends PHPUnit_Framework_TestCase { class Mustache_Test_TokenizerTest extends PHPUnit_Framework_TestCase
{
/** /**
* @dataProvider getTokens * @dataProvider getTokens
*/ */
public function testScan($text, $delimiters, $expected) { public function testScan($text, $delimiters, $expected)
$tokenizer = new Mustache_Tokenizer; {
$this->assertSame($expected, $tokenizer->scan($text, $delimiters)); $tokenizer = new Mustache_Tokenizer;
} $this->assertSame($expected, $tokenizer->scan($text, $delimiters));
}
public function getTokens() { public function getTokens()
return array( {
array( return array(
'text', array(
null, 'text',
array( null,
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT, array(
Mustache_Tokenizer::VALUE => 'text', Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
), Mustache_Tokenizer::VALUE => 'text',
), ),
), ),
),
array( array(
'text', 'text',
'<<< >>>', '<<< >>>',
array( array(
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::VALUE => 'text', Mustache_Tokenizer::VALUE => 'text',
), ),
), ),
), ),
array( array(
'{{ name }}', '{{ name }}',
null, null,
array( array(
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED,
Mustache_Tokenizer::NAME => 'name', Mustache_Tokenizer::NAME => 'name',
Mustache_Tokenizer::OTAG => '{{', Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}', Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::INDEX => 10, Mustache_Tokenizer::INDEX => 10,
) )
) )
), ),
array( array(
'{{ name }}', '{{ name }}',
'<<< >>>', '<<< >>>',
array( array(
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::VALUE => '{{ name }}', Mustache_Tokenizer::VALUE => '{{ name }}',
), ),
), ),
), ),
array( array(
'<<< name >>>', '<<< name >>>',
'<<< >>>', '<<< >>>',
array( array(
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED,
Mustache_Tokenizer::NAME => 'name', Mustache_Tokenizer::NAME => 'name',
Mustache_Tokenizer::OTAG => '<<<', Mustache_Tokenizer::OTAG => '<<<',
Mustache_Tokenizer::CTAG => '>>>', Mustache_Tokenizer::CTAG => '>>>',
Mustache_Tokenizer::INDEX => 12, Mustache_Tokenizer::INDEX => 12,
) )
) )
), ),
array( array(
"{{{ a }}}\n{{# b }} \n{{= | | =}}| c ||/ b |\n|{ d }|", "{{{ a }}}\n{{# b }} \n{{= | | =}}| c ||/ b |\n|{ d }|",
null, null,
array( array(
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_UNESCAPED, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_UNESCAPED,
Mustache_Tokenizer::NAME => 'a', Mustache_Tokenizer::NAME => 'a',
Mustache_Tokenizer::OTAG => '{{', Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}', Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::INDEX => 8, Mustache_Tokenizer::INDEX => 8,
), ),
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::VALUE => "\n", Mustache_Tokenizer::VALUE => "\n",
), ),
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_SECTION, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_SECTION,
Mustache_Tokenizer::NAME => 'b', Mustache_Tokenizer::NAME => 'b',
Mustache_Tokenizer::OTAG => '{{', Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}', Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::INDEX => 18, Mustache_Tokenizer::INDEX => 18,
), ),
null, null,
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED,
Mustache_Tokenizer::NAME => 'c', Mustache_Tokenizer::NAME => 'c',
Mustache_Tokenizer::OTAG => '|', Mustache_Tokenizer::OTAG => '|',
Mustache_Tokenizer::CTAG => '|', Mustache_Tokenizer::CTAG => '|',
Mustache_Tokenizer::INDEX => 37, Mustache_Tokenizer::INDEX => 37,
), ),
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_END_SECTION, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_END_SECTION,
Mustache_Tokenizer::NAME => 'b', Mustache_Tokenizer::NAME => 'b',
Mustache_Tokenizer::OTAG => '|', Mustache_Tokenizer::OTAG => '|',
Mustache_Tokenizer::CTAG => '|', Mustache_Tokenizer::CTAG => '|',
Mustache_Tokenizer::INDEX => 37, Mustache_Tokenizer::INDEX => 37,
), ),
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::VALUE => "\n", Mustache_Tokenizer::VALUE => "\n",
), ),
array( array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_UNESCAPED, Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_UNESCAPED,
Mustache_Tokenizer::NAME => 'd', Mustache_Tokenizer::NAME => 'd',
Mustache_Tokenizer::OTAG => '|', Mustache_Tokenizer::OTAG => '|',
Mustache_Tokenizer::CTAG => '|', Mustache_Tokenizer::CTAG => '|',
Mustache_Tokenizer::INDEX => 51, Mustache_Tokenizer::INDEX => 51,
), ),
) )
), ),
); );
} }
} }
+3 -2
View File
@@ -9,6 +9,7 @@
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
class Mustache_Bar { class Mustache_Bar
// nada {
// nada
} }
+3 -2
View File
@@ -9,6 +9,7 @@
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
class Mustache_Foo { class Mustache_Foo
// nada {
// nada
} }
+3 -2
View File
@@ -9,6 +9,7 @@
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
class NonMustacheClass { class NonMustacheClass
// noop {
// noop
} }
+10 -9
View File
@@ -1,13 +1,14 @@
<?php <?php
class ChildContext { class ChildContext
public $parent = array( {
'child' => 'child works', public $parent = array(
); 'child' => 'child works',
);
public $grandparent = array( public $grandparent = array(
'parent' => array( 'parent' => array(
'child' => 'grandchild works', 'child' => 'grandchild works',
), ),
); );
} }
+6 -4
View File
@@ -1,7 +1,9 @@
<?php <?php
class Comments { class Comments
public function title() { {
return 'A Comedy of Errors'; public function title()
} {
return 'A Comedy of Errors';
}
} }
+16 -13
View File
@@ -1,19 +1,22 @@
<?php <?php
class Complex { class Complex
public $header = 'Colors'; {
public $header = 'Colors';
public $item = array( public $item = array(
array('name' => 'red', 'current' => true, 'url' => '#Red'), array('name' => 'red', 'current' => true, 'url' => '#Red'),
array('name' => 'green', 'current' => false, 'url' => '#Green'), array('name' => 'green', 'current' => false, 'url' => '#Green'),
array('name' => 'blue', 'current' => false, 'url' => '#Blue'), array('name' => 'blue', 'current' => false, 'url' => '#Blue'),
); );
public function notEmpty() { public function notEmpty()
return !($this->isEmpty()); {
} return !($this->isEmpty());
}
public function isEmpty() { public function isEmpty()
return count($this->item) === 0; {
} return count($this->item) === 0;
}
} }
+11 -9
View File
@@ -1,14 +1,16 @@
<?php <?php
class Delimiters { class Delimiters
public $start = "It worked the first time."; {
public $start = "It worked the first time.";
public function middle() { public function middle()
return array( {
array('item' => "And it worked the second time."), return array(
array('item' => "As well as the third."), array('item' => "And it worked the second time."),
); array('item' => "As well as the third."),
} );
}
public $final = "Then, surprisingly, it worked the final time."; public $final = "Then, surprisingly, it worked the final time.";
} }
+11 -10
View File
@@ -1,14 +1,15 @@
<?php <?php
class DotNotation { class DotNotation
public $person = array( {
'name' => array('first' => 'Chris', 'last' => 'Firescythe'), public $person = array(
'age' => 24, 'name' => array('first' => 'Chris', 'last' => 'Firescythe'),
'hometown' => array( 'age' => 24,
'city' => 'Cincinnati', 'hometown' => array(
'state' => 'OH', 'city' => 'Cincinnati',
) 'state' => 'OH',
); )
);
public $normal = 'Normal'; public $normal = 'Normal';
} }
+7 -5
View File
@@ -1,9 +1,11 @@
<?php <?php
class DoubleSection { class DoubleSection
public function t() { {
return true; public function t()
} {
return true;
}
public $two = "second"; public $two = "second";
} }
+3 -2
View File
@@ -1,5 +1,6 @@
<?php <?php
class Escaped { class Escaped
public $title = '"Bear" > "Shark"'; {
public $title = '"Bear" > "Shark"';
} }
@@ -1,22 +1,24 @@
<?php <?php
class GrandParentContext { class GrandParentContext
public $grand_parent_id = 'grand_parent1'; {
public $parent_contexts = array(); public $grand_parent_id = 'grand_parent1';
public $parent_contexts = array();
public function __construct() { public function __construct()
$this->parent_contexts[] = array('parent_id' => 'parent1', 'child_contexts' => array( {
array('child_id' => 'parent1-child1'), $this->parent_contexts[] = array('parent_id' => 'parent1', 'child_contexts' => array(
array('child_id' => 'parent1-child2') array('child_id' => 'parent1-child1'),
)); array('child_id' => 'parent1-child2')
));
$parent2 = new stdClass(); $parent2 = new stdClass();
$parent2->parent_id = 'parent2'; $parent2->parent_id = 'parent2';
$parent2->child_contexts = array( $parent2->child_contexts = array(
array('child_id' => 'parent2-child1'), array('child_id' => 'parent2-child1'),
array('child_id' => 'parent2-child2') array('child_id' => 'parent2-child2')
); );
$this->parent_contexts[] = $parent2; $this->parent_contexts[] = $parent2;
} }
} }
+4 -2
View File
@@ -1,6 +1,7 @@
<?php <?php
class I18n { class I18n
{
// Variable to be interpolated // Variable to be interpolated
public $name = 'Bob'; public $name = 'Bob';
@@ -14,7 +15,8 @@ class I18n {
'My name is {{ name }}.' => 'Me llamo {{ name }}.', 'My name is {{ name }}.' => 'Me llamo {{ name }}.',
); );
public static function __trans($text) { public static function __trans($text)
{
return isset(self::$dictionary[$text]) ? self::$dictionary[$text] : $text; return isset(self::$dictionary[$text]) ? self::$dictionary[$text] : $text;
} }
} }
@@ -1,5 +1,6 @@
<?php <?php
class ImplicitIterator { class ImplicitIterator
public $data = array('Donkey Kong', 'Luigi', 'Mario', 'Peach', 'Yoshi'); {
public $data = array('Donkey Kong', 'Luigi', 'Mario', 'Peach', 'Yoshi');
} }
@@ -1,6 +1,7 @@
<?php <?php
class InvertedDoubleSection { class InvertedDoubleSection
public $t = false; {
public $two = 'second'; public $t = false;
public $two = 'second';
} }
@@ -1,5 +1,6 @@
<?php <?php
class InvertedSection { class InvertedSection
public $repo = array(); {
public $repo = array();
} }
@@ -1,12 +1,13 @@
<?php <?php
class RecursivePartials { class RecursivePartials
public $name = 'George'; {
public $child = array( public $name = 'George';
'name' => 'Dan', public $child = array(
'child' => array( 'name' => 'Dan',
'name' => 'Justin', 'child' => array(
'child' => false, 'name' => 'Justin',
) 'child' => false,
); )
);
} }
@@ -1,16 +1,18 @@
<?php <?php
class SectionIteratorObjects { class SectionIteratorObjects
public $start = "It worked the first time."; {
public $start = "It worked the first time.";
protected $_data = array( protected $_data = array(
array('item' => 'And it worked the second time.'), array('item' => 'And it worked the second time.'),
array('item' => 'As well as the third.'), array('item' => 'As well as the third.'),
); );
public function middle() { public function middle()
return new ArrayIterator($this->_data); {
} return new ArrayIterator($this->_data);
}
public $final = "Then, surprisingly, it worked the final time."; public $final = "Then, surprisingly, it worked the final time.";
} }
@@ -1,26 +1,31 @@
<?php <?php
class SectionMagicObjects { class SectionMagicObjects
public $start = "It worked the first time."; {
public $start = "It worked the first time.";
public function middle() { public function middle()
return new MagicObject(); {
} return new MagicObject();
}
public $final = "Then, surprisingly, it worked the final time."; public $final = "Then, surprisingly, it worked the final time.";
} }
class MagicObject { class MagicObject
protected $_data = array( {
'foo' => 'And it worked the second time.', protected $_data = array(
'bar' => 'As well as the third.' 'foo' => 'And it worked the second time.',
); 'bar' => 'As well as the third.'
);
public function __get($key) { public function __get($key)
return isset($this->_data[$key]) ? $this->_data[$key] : NULL; {
} return isset($this->_data[$key]) ? $this->_data[$key] : NULL;
}
public function __isset($key) { public function __isset($key)
return isset($this->_data[$key]); {
} return isset($this->_data[$key]);
}
} }
+12 -9
View File
@@ -1,16 +1,19 @@
<?php <?php
class SectionObjects { class SectionObjects
public $start = "It worked the first time."; {
public $start = "It worked the first time.";
public function middle() { public function middle()
return new SectionObject; {
} return new SectionObject;
}
public $final = "Then, surprisingly, it worked the final time."; public $final = "Then, surprisingly, it worked the final time.";
} }
class SectionObject { class SectionObject
public $foo = 'And it worked the second time.'; {
public $bar = 'As well as the third.'; public $foo = 'And it worked the second time.';
public $bar = 'As well as the third.';
} }
+11 -9
View File
@@ -1,14 +1,16 @@
<?php <?php
class Sections { class Sections
public $start = "It worked the first time."; {
public $start = "It worked the first time.";
public function middle() { public function middle()
return array( {
array('item' => "And it worked the second time."), return array(
array('item' => "As well as the third."), array('item' => "And it worked the second time."),
); array('item' => "As well as the third."),
} );
}
public $final = "Then, surprisingly, it worked the final time."; public $final = "Then, surprisingly, it worked the final time.";
} }
+31 -29
View File
@@ -1,33 +1,35 @@
<?php <?php
class SectionsNested { class SectionsNested
public $name = 'Little Mac'; {
public $name = 'Little Mac';
public function enemies() { public function enemies()
return array( {
array( return array(
'name' => 'Von Kaiser', array(
'enemies' => array( 'name' => 'Von Kaiser',
array('name' => 'Super Macho Man'), 'enemies' => array(
array('name' => 'Piston Honda'), array('name' => 'Super Macho Man'),
array('name' => 'Mr. Sandman'), array('name' => 'Piston Honda'),
) array('name' => 'Mr. Sandman'),
), )
array( ),
'name' => 'Mike Tyson', array(
'enemies' => array( 'name' => 'Mike Tyson',
array('name' => 'Soda Popinski'), 'enemies' => array(
array('name' => 'King Hippo'), array('name' => 'Soda Popinski'),
array('name' => 'Great Tiger'), array('name' => 'King Hippo'),
array('name' => 'Glass Joe'), array('name' => 'Great Tiger'),
) array('name' => 'Glass Joe'),
), )
array( ),
'name' => 'Don Flamenco', array(
'enemies' => array( 'name' => 'Don Flamenco',
array('name' => 'Bald Bull'), 'enemies' => array(
) array('name' => 'Bald Bull'),
), )
); ),
} );
}
} }
+9 -7
View File
@@ -1,12 +1,14 @@
<?php <?php
class Simple { class Simple
public $name = "Chris"; {
public $value = 10000; public $name = "Chris";
public $value = 10000;
public function taxed_value() { public function taxed_value()
return $this->value - ($this->value * 0.4); {
} return $this->value - ($this->value * 0.4);
}
public $in_ca = true; public $in_ca = true;
}; };
+3 -2
View File
@@ -1,5 +1,6 @@
<?php <?php
class Unescaped { class Unescaped
public $title = "Bear > Shark"; {
public $title = "Bear > Shark";
} }
+3 -2
View File
@@ -1,5 +1,6 @@
<?php <?php
class UTF8 { class UTF8
public $test = '中文又来啦'; {
public $test = '中文又来啦';
} }
+3 -2
View File
@@ -1,5 +1,6 @@
<?php <?php
class UTF8Unescaped { class UTF8Unescaped
public $test = '中文又来啦'; {
public $test = '中文又来啦';
} }
+20 -17
View File
@@ -8,24 +8,27 @@
* *
* `{{> tag }}` and `{{> tag}}` and `{{>tag}}` should all be equivalent. * `{{> tag }}` and `{{> tag}}` and `{{>tag}}` should all be equivalent.
*/ */
class Whitespace { class Whitespace
public $foo = 'alpha'; {
public $foo = 'alpha';
public $bar = 'beta'; public $bar = 'beta';
public function baz() { public function baz()
return 'gamma'; {
} return 'gamma';
}
public function qux() { public function qux()
return array( {
array('key with space' => 'A'), return array(
array('key with space' => 'B'), array('key with space' => 'A'),
array('key with space' => 'C'), array('key with space' => 'B'),
array('key with space' => 'D'), array('key with space' => 'C'),
array('key with space' => 'E'), array('key with space' => 'D'),
array('key with space' => 'F'), array('key with space' => 'E'),
array('key with space' => 'G'), array('key with space' => 'F'),
); array('key with space' => 'G'),
} );
}
} }