Merge branch 'release/2.7.0'

This commit is contained in:
Justin Hileman
2014-08-26 12:50:10 -07:00
40 changed files with 1531 additions and 216 deletions
+6
View File
@@ -0,0 +1,6 @@
<?php
$config = new Symfony\CS\Config\Config();
$config->getFinder()->in(__DIR__)->exclude('bin');
return $config;
+8 -4
View File
@@ -1,4 +1,12 @@
language: php
before_script:
- curl http://cs.sensiolabs.org/get/php-cs-fixer.phar -o php-cs-fixer.phar
script:
- phpunit
- if [[ `php -r "echo version_compare(PHP_VERSION, '5.3.6', '>=');"` ]]; then php php-cs-fixer.phar --dry-run -v fix .; fi
php:
- 5.2
- 5.3
@@ -6,7 +14,3 @@ php:
- 5.5
- 5.6
- hhvm
matrix:
allow_failures:
- php: hhvm # See https://github.com/facebook/hhvm/pull/1860
+6 -4
View File
@@ -5,13 +5,15 @@
1. [Fork the repo on GitHub](https://github.com/bobthecow/mustache.php).
2. Run the test suite. We only take pull requests with passing tests, and it's great to know that you have a clean slate. Make sure you have PHPUnit 3.5+, then run `phpunit` from the project directory.
2. Update submodules: `git submodule update --init`
3. Add tests for your change. Only refactoring and documentation changes require no new tests. If you are adding functionality or fixing a bug, add a test!
3. Run the test suite. We only take pull requests with passing tests, and it's great to know that you have a clean slate. Make sure you have PHPUnit 3.5+, then run `phpunit` from the project directory.
4. Make the tests pass.
4. Add tests for your change. Only refactoring and documentation changes require no new tests. If you are adding functionality or fixing a bug, add a test!
5. Push your fork to GitHub and submit a pull request against the `dev` branch.
5. Make the tests pass.
6. Push your fork to GitHub and submit a pull request against the `dev` branch.
### You can do some things to increase the chance that your pull request is accepted the first time:
+211 -58
View File
@@ -16,6 +16,9 @@
*/
class Mustache_Compiler
{
private $pragmas;
private $defaultPragmas = array();
private $sections;
private $source;
private $indentNextLine;
@@ -23,7 +26,6 @@ class Mustache_Compiler
private $entityFlags;
private $charset;
private $strictCallables;
private $pragmas;
/**
* Compile a Mustache token parse tree into PHP source code.
@@ -40,7 +42,7 @@ class Mustache_Compiler
*/
public function compile($source, array $tree, $name, $customEscape = false, $charset = 'UTF-8', $strictCallables = false, $entityFlags = ENT_COMPAT)
{
$this->pragmas = array();
$this->pragmas = $this->defaultPragmas;
$this->sections = array();
$this->source = $source;
$this->indentNextLine = true;
@@ -52,6 +54,23 @@ class Mustache_Compiler
return $this->writeCode($tree, $name);
}
/**
* Enable pragmas across all templates, regardless of the presence of pragma
* tags in the individual templates.
*
* @internal Users should set global pragmas in Mustache_Engine, not here :)
*
* @param string[] $pragmas
*/
public function setPragmas(array $pragmas)
{
$this->pragmas = array();
foreach ($pragmas as $pragma) {
$this->pragmas[$pragma] = true;
}
$this->defaultPragmas = $this->pragmas;
}
/**
* Helper function for walking the Mustache token parse tree.
*
@@ -76,6 +95,7 @@ class Mustache_Compiler
$code .= $this->section(
$node[Mustache_Tokenizer::NODES],
$node[Mustache_Tokenizer::NAME],
isset($node[Mustache_Tokenizer::FILTERS]) ? $node[Mustache_Tokenizer::FILTERS] : array(),
$node[Mustache_Tokenizer::INDEX],
$node[Mustache_Tokenizer::END],
$node[Mustache_Tokenizer::OTAG],
@@ -88,12 +108,12 @@ class Mustache_Compiler
$code .= $this->invertedSection(
$node[Mustache_Tokenizer::NODES],
$node[Mustache_Tokenizer::NAME],
isset($node[Mustache_Tokenizer::FILTERS]) ? $node[Mustache_Tokenizer::FILTERS] : array(),
$level
);
break;
case Mustache_Tokenizer::T_PARTIAL:
case Mustache_Tokenizer::T_PARTIAL_2:
$code .= $this->partial(
$node[Mustache_Tokenizer::NAME],
isset($node[Mustache_Tokenizer::INDENT]) ? $node[Mustache_Tokenizer::INDENT] : '',
@@ -101,16 +121,51 @@ class Mustache_Compiler
);
break;
case Mustache_Tokenizer::T_UNESCAPED:
case Mustache_Tokenizer::T_UNESCAPED_2:
$code .= $this->variable($node[Mustache_Tokenizer::NAME], false, $level);
case Mustache_Tokenizer::T_PARENT:
$code .= $this->parent(
$node[Mustache_Tokenizer::NAME],
isset($node[Mustache_Tokenizer::INDENT]) ? $node[Mustache_Tokenizer::INDENT] : '',
$node[Mustache_Tokenizer::NODES],
$level
);
break;
case Mustache_Tokenizer::T_BLOCK_ARG:
$code .= $this->blockArg(
$node[Mustache_Tokenizer::NODES],
$node[Mustache_Tokenizer::NAME],
$node[Mustache_Tokenizer::INDEX],
$node[Mustache_Tokenizer::END],
$node[Mustache_Tokenizer::OTAG],
$node[Mustache_Tokenizer::CTAG],
$level
);
break;
case Mustache_Tokenizer::T_BLOCK_VAR:
$code .= $this->blockVar(
$node[Mustache_Tokenizer::NODES],
$node[Mustache_Tokenizer::NAME],
$node[Mustache_Tokenizer::INDEX],
$node[Mustache_Tokenizer::END],
$node[Mustache_Tokenizer::OTAG],
$node[Mustache_Tokenizer::CTAG],
$level
);
break;
case Mustache_Tokenizer::T_COMMENT:
break;
case Mustache_Tokenizer::T_ESCAPED:
$code .= $this->variable($node[Mustache_Tokenizer::NAME], true, $level);
case Mustache_Tokenizer::T_UNESCAPED:
case Mustache_Tokenizer::T_UNESCAPED_2:
$code .= $this->variable(
$node[Mustache_Tokenizer::NAME],
isset($node[Mustache_Tokenizer::FILTERS]) ? $node[Mustache_Tokenizer::FILTERS] : array(),
$node[Mustache_Tokenizer::TYPE] === Mustache_Tokenizer::T_ESCAPED,
$level
);
break;
case Mustache_Tokenizer::T_TEXT:
@@ -135,6 +190,7 @@ class Mustache_Compiler
{
$this->lambdaHelper = new Mustache_LambdaHelper($this->mustache, $context);
$buffer = \'\';
$newContext = array();
%s
return $buffer;
@@ -149,6 +205,7 @@ class Mustache_Compiler
public function renderInternal(Mustache_Context $context, $indent = \'\')
{
$buffer = \'\';
$newContext = array();
%s
return $buffer;
@@ -170,11 +227,68 @@ class Mustache_Compiler
$code = $this->walk($tree);
$sections = implode("\n", $this->sections);
$klass = empty($this->sections) ? self::KLASS_NO_LAMBDAS : self::KLASS;
$callable = $this->strictCallables ? $this->prepare(self::STRICT_CALLABLE) : '';
return sprintf($this->prepare($klass, 0, false, true), $name, $callable, $code, $sections);
}
const BLOCK_VAR = '
$value = $this->resolveValue($context->findInBlock(%s), $context, $indent);
if ($value && !is_array($value) && !is_object($value)) {
$buffer .= $value;
} else {
%s
}
';
/**
* Generate Mustache Template inheritance block variable PHP source.
*
* @param array $nodes Array of child tokens
* @param string $id Section name
* @param int $start Section start offset
* @param int $end Section end offset
* @param string $otag Current Mustache opening tag
* @param string $ctag Current Mustache closing tag
* @param int $level
*
* @return string Generated PHP source code
*/
private function blockVar($nodes, $id, $start, $end, $otag, $ctag, $level)
{
$id = var_export($id, true);
return sprintf($this->prepare(self::BLOCK_VAR, $level), $id, $this->walk($nodes, 2));
}
const BLOCK_ARG = '
// %s block_arg
$value = $this->section%s($context, $indent, true);
$newContext[%s] = %s$value;
';
/**
* Generate Mustache Template inheritance block argument PHP source.
*
* @param array $nodes Array of child tokens
* @param string $id Section name
* @param int $start Section start offset
* @param int $end Section end offset
* @param string $otag Current Mustache opening tag
* @param string $ctag Current Mustache closing tag
* @param int $level
*
* @return string Generated PHP source code
*/
private function blockArg($nodes, $id, $start, $end, $otag, $ctag, $level)
{
$key = $this->section($nodes, $id, array(), $start, $end, $otag, $ctag, $level, true);
$id = var_export($id, true);
return sprintf($this->prepare(self::BLOCK_ARG, $level), $id, $key, $id, $this->flushIndent());
}
const SECTION_CALL = '
// %s section
$value = $context->%s(%s);%s
@@ -198,7 +312,8 @@ class Mustache_Compiler
} elseif (!empty($value)) {
$values = $this->isIterable($value) ? $value : array($value);
foreach ($values as $value) {
$context->push($value);%s
$context->push($value);
%s
$context->pop();
}
}
@@ -211,24 +326,18 @@ class Mustache_Compiler
*
* @param array $nodes Array of child tokens
* @param string $id Section name
* @param string[] $filters Array of filters
* @param int $start Section start offset
* @param int $end Section end offset
* @param string $otag Current Mustache opening tag
* @param string $ctag Current Mustache closing tag
* @param int $level
* @param bool $arg (default: false)
*
* @return string Generated section PHP source code
*/
private function section($nodes, $id, $start, $end, $otag, $ctag, $level)
private function section($nodes, $id, $filters, $start, $end, $otag, $ctag, $level, $arg = false)
{
$filters = '';
if (isset($this->pragmas[Mustache_Engine::PRAGMA_FILTERS])) {
list($id, $filters) = $this->getFilters($id, $level);
}
$method = $this->getFindMethod($id);
$id = var_export($id, true);
$source = var_export(substr($this->source, $start, $end - $start), true);
$callable = $this->getCallable();
@@ -244,8 +353,16 @@ class Mustache_Compiler
$this->sections[$key] = sprintf($this->prepare(self::SECTION), $key, $callable, $source, $delims, $this->walk($nodes, 2));
}
if ($arg === true) {
return $key;
} else {
$method = $this->getFindMethod($id);
$id = var_export($id, true);
$filters = $this->getFilters($filters, $level);
return sprintf($this->prepare(self::SECTION_CALL, $level), $id, $method, $id, $filters, $key);
}
}
const INVERTED_SECTION = '
// %s inverted section
@@ -259,27 +376,24 @@ class Mustache_Compiler
*
* @param array $nodes Array of child tokens
* @param string $id Section name
* @param string[] $filters Array of filters
* @param int $level
*
* @return string Generated inverted section PHP source code
*/
private function invertedSection($nodes, $id, $level)
private function invertedSection($nodes, $id, $filters, $level)
{
$filters = '';
if (isset($this->pragmas[Mustache_Engine::PRAGMA_FILTERS])) {
list($id, $filters) = $this->getFilters($id, $level);
}
$method = $this->getFindMethod($id);
$id = var_export($id, true);
$filters = $this->getFilters($filters, $level);
return sprintf($this->prepare(self::INVERTED_SECTION, $level), $id, $method, $id, $filters, $this->walk($nodes, $level));
}
const PARTIAL_INDENT = ', $indent . %s';
const PARTIAL = '
if ($partial = $this->mustache->loadPartial(%s)) {
$buffer .= $partial->renderInternal($context, $indent . %s);
$buffer .= $partial->renderInternal($context%s);
}
';
@@ -294,13 +408,63 @@ class Mustache_Compiler
*/
private function partial($id, $indent, $level)
{
if ($indent !== '') {
$indentParam = sprintf(self::PARTIAL_INDENT, var_export($indent, true));
} else {
$indentParam = '';
}
return sprintf(
$this->prepare(self::PARTIAL, $level),
var_export($id, true),
$indentParam
);
}
const PARENT = '
%s
if ($parent = $this->mustache->LoadPartial(%s)) {
$context->pushBlockContext($newContext);
$buffer .= $parent->renderInternal($context, $indent);
$context->popBlockContext();
}
';
/**
* Generate Mustache Template inheritance parent call PHP source.
*
* @param string $id Parent tag name
* @param string $indent Whitespace indent to apply to parent
* @param array $children Child nodes
* @param int $level
*
* @return string Generated PHP source code
*/
private function parent($id, $indent, array $children, $level)
{
$realChildren = array_filter($children, array(__CLASS__, 'onlyBlockArgs'));
return sprintf(
$this->prepare(self::PARENT, $level),
$this->walk($realChildren, $level),
var_export($id, true),
var_export($indent, true)
);
}
/**
* Helper method for filtering out non-block-arg tokens.
*
* @param array $node
*
* @return boolean True if $node is a block arg token.
*/
private static function onlyBlockArgs(array $node)
{
return $node[Mustache_Tokenizer::TYPE] === Mustache_Tokenizer::T_BLOCK_ARG;
}
const VARIABLE = '
$value = $this->resolveValue($context->%s(%s), $context, $indent);%s
$buffer .= %s%s;
@@ -310,42 +474,22 @@ class Mustache_Compiler
* Generate Mustache Template variable interpolation PHP source.
*
* @param string $id Variable name
* @param string[] $filters Array of filters
* @param boolean $escape Escape the variable value for output?
* @param int $level
*
* @return string Generated variable interpolation PHP source
*/
private function variable($id, $escape, $level)
private function variable($id, $filters, $escape, $level)
{
$filters = '';
if (isset($this->pragmas[Mustache_Engine::PRAGMA_FILTERS])) {
list($id, $filters) = $this->getFilters($id, $level);
}
$method = $this->getFindMethod($id);
$id = ($method !== 'last') ? var_export($id, true) : '';
$filters = $this->getFilters($filters, $level);
$value = $escape ? $this->getEscape() : '$value';
return sprintf($this->prepare(self::VARIABLE, $level), $method, $id, $filters, $this->flushIndent(), $value);
}
/**
* Generate Mustache Template variable filtering PHP source.
*
* @param string $id Variable name
* @param int $level
*
* @return string Generated variable filtering PHP source
*/
private function getFilters($id, $level)
{
$filters = array_map('trim', explode('|', $id));
$id = array_shift($filters);
return array($id, $this->getFilter($filters, $level));
}
const FILTER = '
$filter = $context->%s(%s);
if (!(%s)) {
@@ -355,14 +499,14 @@ class Mustache_Compiler
';
/**
* Generate PHP source for a single filter.
* Generate Mustache Template variable filtering PHP source.
*
* @param array $filters
* @param string[] $filters Array of filters
* @param int $level
*
* @return string Generated filter PHP source
*/
private function getFilter(array $filters, $level)
private function getFilters(array $filters, $level)
{
if (empty($filters)) {
return '';
@@ -374,7 +518,7 @@ class Mustache_Compiler
$callable = $this->getCallable('$filter');
$msg = var_export($name, true);
return sprintf($this->prepare(self::FILTER, $level), $method, $filter, $callable, $msg, $this->getFilter($filters, $level));
return sprintf($this->prepare(self::FILTER, $level), $method, $filter, $callable, $msg, $this->getFilters($filters, $level));
}
const LINE = '$buffer .= "\n";';
@@ -434,9 +578,9 @@ class Mustache_Compiler
{
if ($this->customEscape) {
return sprintf(self::CUSTOM_ESCAPE, $value);
} else {
return sprintf(self::DEFAULT_ESCAPE, $value, var_export($this->entityFlags, true), var_export($this->charset, true));
}
return sprintf(self::DEFAULT_ESCAPE, $value, var_export($this->entityFlags, true), var_export($this->charset, true));
}
/**
@@ -456,16 +600,25 @@ class Mustache_Compiler
{
if ($id === '.') {
return 'last';
} elseif (strpos($id, '.') === false) {
return 'find';
} else {
return 'findDot';
}
if (strpos($id, '.') === false) {
return 'find';
}
return 'findDot';
}
const IS_CALLABLE = '!is_string(%s) && is_callable(%s)';
const STRICT_IS_CALLABLE = 'is_object(%s) && is_callable(%s)';
/**
* Helper function to compile strict vs lax "is callable" logic.
*
* @param string $variable (default: '$value')
*
* @return string "is callable" logic
*/
private function getCallable($variable = '$value')
{
$tpl = $this->strictCallables ? self::STRICT_IS_CALLABLE : self::IS_CALLABLE;
+61 -9
View File
@@ -15,6 +15,7 @@
class Mustache_Context
{
private $stack = array();
private $blockStack = array();
/**
* Mustache rendering Context constructor.
@@ -38,6 +39,16 @@ class Mustache_Context
array_push($this->stack, $value);
}
/**
* Push a new Context frame onto the block context stack.
*
* @param mixed $value Object or array to use for block context
*/
public function pushBlockContext($value)
{
array_push($this->blockStack, $value);
}
/**
* Pop the last Context frame from the stack.
*
@@ -48,6 +59,16 @@ class Mustache_Context
return array_pop($this->stack);
}
/**
* Pop the last block Context frame from the stack.
*
* @return mixed Last block Context frame (object or array)
*/
public function popBlockContext()
{
return array_pop($this->blockStack);
}
/**
* Get the last Context frame.
*
@@ -120,6 +141,24 @@ class Mustache_Context
return $value;
}
/**
* Find an argument in the block context stack.
*
* @param string $id
*
* @return mixed Variable value, or '' if not found.
*/
public function findInBlock($id)
{
foreach ($this->blockStack as $context) {
if (array_key_exists($id, $context)) {
return $context[$id];
}
}
return '';
}
/**
* Helper function to find a variable in the Context stack.
*
@@ -133,19 +172,32 @@ class Mustache_Context
private function findVariableInStack($id, array $stack)
{
for ($i = count($stack) - 1; $i >= 0; $i--) {
if (is_object($stack[$i]) && !($stack[$i] instanceof Closure)) {
$frame = &$stack[$i];
switch (gettype($frame)) {
case 'object':
if (!($frame instanceof Closure)) {
// Note that is_callable() *will not work here*
// See https://github.com/bobthecow/mustache.php/wiki/Magic-Methods
if (method_exists($stack[$i], $id)) {
return $stack[$i]->$id();
} elseif (isset($stack[$i]->$id)) {
return $stack[$i]->$id;
} elseif ($stack[$i] instanceof ArrayAccess && isset($stack[$i][$id])) {
return $stack[$i][$id];
if (method_exists($frame, $id)) {
return $frame->$id();
}
} elseif (is_array($stack[$i]) && array_key_exists($id, $stack[$i])) {
return $stack[$i][$id];
if (isset($frame->$id)) {
return $frame->$id;
}
if ($frame instanceof ArrayAccess && isset($frame[$id])) {
return $frame[$id];
}
}
break;
case 'array':
if (array_key_exists($id, $frame)) {
return $frame[$id];
}
break;
}
}
+49 -11
View File
@@ -23,10 +23,17 @@
*/
class Mustache_Engine
{
const VERSION = '2.6.1';
const VERSION = '2.7.0';
const SPEC_VERSION = '1.1.2';
const PRAGMA_FILTERS = 'FILTERS';
const PRAGMA_BLOCKS = 'BLOCKS';
// Known pragmas
private static $knownPragmas = array(
self::PRAGMA_FILTERS => true,
self::PRAGMA_BLOCKS => true,
);
// Template cache
private $templates = array();
@@ -44,6 +51,7 @@ class Mustache_Engine
private $charset = 'UTF-8';
private $logger;
private $strictCallables = false;
private $pragmas = array();
// Services
private $tokenizer;
@@ -110,6 +118,10 @@ class Mustache_Engine
* // helps protect against arbitrary code execution when user input is passed directly into the template.
* // This currently defaults to false, but will default to true in v3.0.
* 'strict_callables' => true,
*
* // Enable pragmas across all templates, regardless of the presence of pragma tags in the individual
* // templates.
* 'pragmas' => [Mustache_Engine::PRAGMA_FILTERS],
* );
*
* @throws Mustache_Exception_InvalidArgumentException If `escape` option is not callable.
@@ -176,6 +188,15 @@ class Mustache_Engine
if (isset($options['strict_callables'])) {
$this->strictCallables = $options['strict_callables'];
}
if (isset($options['pragmas'])) {
foreach ($options['pragmas'] as $pragma) {
if (!isset(self::$knownPragmas[$pragma])) {
throw new Mustache_Exception_InvalidArgumentException(sprintf('Unknown pragma: "%s".', $pragma));
}
$this->pragmas[$pragma] = true;
}
}
}
/**
@@ -226,6 +247,16 @@ class Mustache_Engine
return $this->charset;
}
/**
* Get the current globally enabled pragmas.
*
* @return array
*/
public function getPragmas()
{
return array_keys($this->pragmas);
}
/**
* Set the Mustache template Loader instance.
*
@@ -247,7 +278,7 @@ class Mustache_Engine
public function getLoader()
{
if (!isset($this->loader)) {
$this->loader = new Mustache_Loader_StringLoader;
$this->loader = new Mustache_Loader_StringLoader();
}
return $this->loader;
@@ -274,7 +305,7 @@ class Mustache_Engine
public function getPartialsLoader()
{
if (!isset($this->partialsLoader)) {
$this->partialsLoader = new Mustache_Loader_ArrayLoader;
$this->partialsLoader = new Mustache_Loader_ArrayLoader();
}
return $this->partialsLoader;
@@ -290,7 +321,7 @@ class Mustache_Engine
public function setPartials(array $partials = array())
{
if (!isset($this->partialsLoader)) {
$this->partialsLoader = new Mustache_Loader_ArrayLoader;
$this->partialsLoader = new Mustache_Loader_ArrayLoader();
}
if (!$this->partialsLoader instanceof Mustache_Loader_MutableLoader) {
@@ -334,7 +365,7 @@ class Mustache_Engine
public function getHelpers()
{
if (!isset($this->helpers)) {
$this->helpers = new Mustache_HelperCollection;
$this->helpers = new Mustache_HelperCollection();
}
return $this->helpers;
@@ -443,7 +474,7 @@ class Mustache_Engine
public function getTokenizer()
{
if (!isset($this->tokenizer)) {
$this->tokenizer = new Mustache_Tokenizer;
$this->tokenizer = new Mustache_Tokenizer();
}
return $this->tokenizer;
@@ -469,7 +500,7 @@ class Mustache_Engine
public function getParser()
{
if (!isset($this->parser)) {
$this->parser = new Mustache_Parser;
$this->parser = new Mustache_Parser();
}
return $this->parser;
@@ -495,7 +526,7 @@ class Mustache_Engine
public function getCompiler()
{
if (!isset($this->compiler)) {
$this->compiler = new Mustache_Compiler;
$this->compiler = new Mustache_Compiler();
}
return $this->compiler;
@@ -563,12 +594,13 @@ class Mustache_Engine
public function getTemplateClassName($source)
{
return $this->templateClassPrefix . md5(sprintf(
'version:%s,escape:%s,entity_flags:%i,charset:%s,strict_callables:%s,source:%s',
'version:%s,escape:%s,entity_flags:%i,charset:%s,strict_callables:%s,pragmas:%s,source:%s',
self::VERSION,
isset($this->escape) ? 'custom' : 'default',
$this->entityFlags,
$this->charset,
$this->strictCallables ? 'true' : 'false',
implode(' ', $this->getPragmas()),
$source
));
}
@@ -705,7 +737,10 @@ class Mustache_Engine
*/
private function parse($source)
{
return $this->getParser()->parse($this->tokenize($source));
$parser = $this->getParser();
$parser->setPragmas($this->getPragmas());
return $parser->parse($this->tokenize($source));
}
/**
@@ -728,7 +763,10 @@ class Mustache_Engine
array('className' => $name)
);
return $this->getCompiler()->compile($source, $tree, $name, isset($this->escape), $this->charset, $this->strictCallables, $this->entityFlags);
$compiler = $this->getCompiler();
$compiler->setPragmas($this->getPragmas());
return $compiler->compile($source, $tree, $name, isset($this->escape), $this->charset, $this->strictCallables, $this->entityFlags);
}
/**
+1 -1
View File
@@ -49,7 +49,7 @@ class Mustache_Loader_FilesystemLoader implements Mustache_Loader
{
$this->baseDir = $baseDir;
if (strpos($this->baseDir, '://') === -1) {
if (strpos($this->baseDir, '://') === false) {
$this->baseDir = realpath($this->baseDir);
}
+115 -4
View File
@@ -18,6 +18,11 @@ class Mustache_Parser
{
private $lineNum;
private $lineTokens;
private $pragmas;
private $defaultPragmas = array();
private $pragmaFilters;
private $pragmaBlocks;
/**
* Process an array of Mustache tokens and convert them into a parse tree.
@@ -30,10 +35,31 @@ class Mustache_Parser
{
$this->lineNum = -1;
$this->lineTokens = 0;
$this->pragmas = $this->defaultPragmas;
$this->pragmaFilters = isset($this->pragmas[Mustache_Engine::PRAGMA_FILTERS]);
$this->pragmaBlocks = isset($this->pragmas[Mustache_Engine::PRAGMA_BLOCKS]);
return $this->buildTree($tokens);
}
/**
* Enable pragmas across all templates, regardless of the presence of pragma
* tags in the individual templates.
*
* @internal Users should set global pragmas in Mustache_Engine, not here :)
*
* @param string[] $pragmas
*/
public function setPragmas(array $pragmas)
{
$this->pragmas = array();
foreach ($pragmas as $pragma) {
$this->enablePragma($pragma);
}
$this->defaultPragmas = $this->pragmas;
}
/**
* Helper method for recursively building a parse tree.
*
@@ -58,13 +84,23 @@ class Mustache_Parser
$this->lineTokens = 0;
}
if ($this->pragmaFilters && isset($token[Mustache_Tokenizer::NAME])) {
list($name, $filters) = $this->getNameAndFilters($token[Mustache_Tokenizer::NAME]);
if (!empty($filters)) {
$token[Mustache_Tokenizer::NAME] = $name;
$token[Mustache_Tokenizer::FILTERS] = $filters;
}
}
switch ($token[Mustache_Tokenizer::TYPE]) {
case Mustache_Tokenizer::T_DELIM_CHANGE:
$this->checkIfTokenIsAllowedInParent($parent, $token);
$this->clearStandaloneLines($nodes, $tokens);
break;
case Mustache_Tokenizer::T_SECTION:
case Mustache_Tokenizer::T_INVERTED:
$this->checkIfTokenIsAllowedInParent($parent, $token);
$this->clearStandaloneLines($nodes, $tokens);
$nodes[] = $this->buildTree($tokens, $token);
break;
@@ -97,15 +133,40 @@ class Mustache_Parser
return $parent;
case Mustache_Tokenizer::T_PARTIAL:
case Mustache_Tokenizer::T_PARTIAL_2:
// store the whitespace prefix for laters!
$this->checkIfTokenIsAllowedInParent($parent, $token);
//store the whitespace prefix for laters!
if ($indent = $this->clearStandaloneLines($nodes, $tokens)) {
$token[Mustache_Tokenizer::INDENT] = $indent[Mustache_Tokenizer::VALUE];
}
$nodes[] = $token;
break;
case Mustache_Tokenizer::T_PARENT:
$this->checkIfTokenIsAllowedInParent($parent, $token);
$nodes[] = $this->buildTree($tokens, $token);
break;
case Mustache_Tokenizer::T_BLOCK_VAR:
if ($this->pragmaBlocks) {
// BLOCKS pragma is enabled, let's do this!
if ($parent[Mustache_Tokenizer::TYPE] === Mustache_Tokenizer::T_PARENT) {
$token[Mustache_Tokenizer::TYPE] = Mustache_Tokenizer::T_BLOCK_ARG;
}
$this->clearStandaloneLines($nodes, $tokens);
$nodes[] = $this->buildTree($tokens, $token);
} else {
// pretend this was just a normal "escaped" token...
$token[Mustache_Tokenizer::TYPE] = Mustache_Tokenizer::T_ESCAPED;
// TODO: figure out how to figure out if there was a space after this dollar:
$token[Mustache_Tokenizer::NAME] = '$' . $token[Mustache_Tokenizer::NAME];
$nodes[] = $token;
}
break;
case Mustache_Tokenizer::T_PRAGMA:
$this->enablePragma($token[Mustache_Tokenizer::NAME]);
// no break
case Mustache_Tokenizer::T_COMMENT:
$this->clearStandaloneLines($nodes, $tokens);
$nodes[] = $token;
@@ -137,7 +198,7 @@ class Mustache_Parser
* @param array $nodes Parsed nodes.
* @param array $tokens Tokens to be parsed.
*
* @return array Resulting indent token, if any.
* @return array|null Resulting indent token, if any.
*/
private function clearStandaloneLines(array &$nodes, array &$tokens)
{
@@ -197,10 +258,60 @@ class Mustache_Parser
*/
private function tokenIsWhitespace(array $token)
{
if ($token[Mustache_Tokenizer::TYPE] == Mustache_Tokenizer::T_TEXT) {
if ($token[Mustache_Tokenizer::TYPE] === Mustache_Tokenizer::T_TEXT) {
return preg_match('/^\s*$/', $token[Mustache_Tokenizer::VALUE]);
}
return false;
}
/**
* Check whether a token is allowed inside a parent tag.
*
* @throws Mustache_Exception_SyntaxException if an invalid token is found inside a parent tag.
*
* @param array|null $parent
* @param array $token
*/
private function checkIfTokenIsAllowedInParent($parent, array $token)
{
if ($parent[Mustache_Tokenizer::TYPE] === Mustache_Tokenizer::T_PARENT) {
throw new Mustache_Exception_SyntaxException('Illegal content in < parent tag', $token);
}
}
/**
* Split a tag name into name and filters.
*
* @param string $name
*
* @return array [Tag name, Array of filters]
*/
private function getNameAndFilters($name)
{
$filters = array_map('trim', explode('|', $name));
$name = array_shift($filters);
return array($name, $filters);
}
/**
* Enable a pragma.
*
* @param string $name
*/
private function enablePragma($name)
{
$this->pragmas[$name] = true;
switch ($name) {
case Mustache_Engine::PRAGMA_BLOCKS:
$this->pragmaBlocks = true;
break;
case Mustache_Engine::PRAGMA_FILTERS:
$this->pragmaFilters = true;
break;
}
}
}
+10 -5
View File
@@ -63,7 +63,9 @@ abstract class Mustache_Template
*/
public function render($context = array())
{
return $this->renderInternal($this->prepareContextStack($context));
return $this->renderInternal(
$this->prepareContextStack($context)
);
}
/**
@@ -111,9 +113,11 @@ abstract class Mustache_Template
*/
protected function isIterable($value)
{
if (is_object($value)) {
switch (gettype($value)) {
case 'object':
return $value instanceof Traversable;
} elseif (is_array($value)) {
case 'array':
$i = 0;
foreach ($value as $k => $v) {
if ($k !== $i++) {
@@ -122,7 +126,8 @@ abstract class Mustache_Template
}
return true;
} else {
default:
return false;
}
}
@@ -138,7 +143,7 @@ abstract class Mustache_Template
*/
protected function prepareContextStack($context = null)
{
$stack = new Mustache_Context;
$stack = new Mustache_Context();
$helpers = $this->mustache->getHelpers();
if (!$helpers->isEmpty()) {
+6 -2
View File
@@ -27,13 +27,15 @@ class Mustache_Tokenizer
const T_END_SECTION = '/';
const T_COMMENT = '!';
const T_PARTIAL = '>';
const T_PARTIAL_2 = '<';
const T_PARENT = '<';
const T_DELIM_CHANGE = '=';
const T_ESCAPED = '_v';
const T_UNESCAPED = '{';
const T_UNESCAPED_2 = '&';
const T_TEXT = '_t';
const T_PRAGMA = '%';
const T_BLOCK_VAR = '$';
const T_BLOCK_ARG = '$arg';
// Valid token types
private static $tagTypes = array(
@@ -42,12 +44,13 @@ class Mustache_Tokenizer
self::T_END_SECTION => true,
self::T_COMMENT => true,
self::T_PARTIAL => true,
self::T_PARTIAL_2 => true,
self::T_PARENT => true,
self::T_DELIM_CHANGE => true,
self::T_ESCAPED => true,
self::T_UNESCAPED => true,
self::T_UNESCAPED_2 => true,
self::T_PRAGMA => true,
self::T_BLOCK_VAR => true,
);
// Interpolated tags
@@ -68,6 +71,7 @@ class Mustache_Tokenizer
const INDENT = 'indent';
const NODES = 'nodes';
const VALUE = 'value';
const FILTERS = 'filters';
private $state;
private $tagType;
+2 -2
View File
@@ -20,7 +20,7 @@ class Mustache_Test_CompilerTest extends PHPUnit_Framework_TestCase
*/
public function testCompile($source, array $tree, $name, $customEscaper, $entityFlags, $charset, $expected)
{
$compiler = new Mustache_Compiler;
$compiler = new Mustache_Compiler();
$compiled = $compiler->compile($source, $tree, $name, $customEscaper, $charset, false, $entityFlags);
foreach ($expected as $contains) {
@@ -138,7 +138,7 @@ class Mustache_Test_CompilerTest extends PHPUnit_Framework_TestCase
*/
public function testCompilerThrowsSyntaxException()
{
$compiler = new Mustache_Compiler;
$compiler = new Mustache_Compiler();
$compiler->compile('', array(array(Mustache_Tokenizer::TYPE => 'invalid')), 'SomeClass');
}
+9 -9
View File
@@ -16,7 +16,7 @@ class Mustache_Test_ContextTest extends PHPUnit_Framework_TestCase
{
public function testConstructor()
{
$one = new Mustache_Context;
$one = new Mustache_Context();
$this->assertSame('', $one->find('foo'));
$this->assertSame('', $one->find('bar'));
@@ -27,7 +27,7 @@ class Mustache_Test_ContextTest extends PHPUnit_Framework_TestCase
$this->assertEquals('FOO', $two->find('foo'));
$this->assertEquals('<BAR>', $two->find('bar'));
$obj = new StdClass;
$obj = new StdClass();
$obj->name = 'NAME';
$three = new Mustache_Context($obj);
$this->assertSame($obj, $three->last());
@@ -36,16 +36,16 @@ class Mustache_Test_ContextTest extends PHPUnit_Framework_TestCase
public function testPushPopAndLast()
{
$context = new Mustache_Context;
$context = new Mustache_Context();
$this->assertFalse($context->last());
$dummy = new Mustache_Test_TestDummy;
$dummy = new Mustache_Test_TestDummy();
$context->push($dummy);
$this->assertSame($dummy, $context->last());
$this->assertSame($dummy, $context->pop());
$this->assertFalse($context->last());
$obj = new StdClass;
$obj = new StdClass();
$context->push($dummy);
$this->assertSame($dummy, $context->last());
$context->push($obj);
@@ -57,11 +57,11 @@ class Mustache_Test_ContextTest extends PHPUnit_Framework_TestCase
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';
$arr = array(
@@ -112,7 +112,7 @@ class Mustache_Test_ContextTest extends PHPUnit_Framework_TestCase
public function testAccessorPriority()
{
$context = new Mustache_Context(new Mustache_Test_AllTheThings);
$context = new Mustache_Context(new Mustache_Test_AllTheThings());
$this->assertEquals('win', $context->find('foo'), 'method beats property');
$this->assertEquals('win', $context->find('bar'), 'property beats ArrayAccess');
+24 -12
View File
@@ -17,8 +17,8 @@ class Mustache_Test_EngineTest extends Mustache_Test_FunctionalTestCase
public function testConstructor()
{
$logger = new Mustache_Logger_StreamLogger(tmpfile());
$loader = new Mustache_Loader_StringLoader;
$partialsLoader = new Mustache_Loader_ArrayLoader;
$loader = new Mustache_Loader_StringLoader();
$partialsLoader = new Mustache_Loader_ArrayLoader();
$mustache = new Mustache_Engine(array(
'template_class_prefix' => '__whot__',
'cache' => self::$tempDir,
@@ -36,6 +36,7 @@ class Mustache_Test_EngineTest extends Mustache_Test_FunctionalTestCase
'escape' => 'strtoupper',
'entity_flags' => ENT_QUOTES,
'charset' => 'ISO-8859-1',
'pragmas' => array(Mustache_Engine::PRAGMA_FILTERS),
));
$this->assertSame($logger, $mustache->getLogger());
@@ -50,6 +51,7 @@ class Mustache_Test_EngineTest extends Mustache_Test_FunctionalTestCase
$this->assertTrue($mustache->hasHelper('bar'));
$this->assertFalse($mustache->hasHelper('baz'));
$this->assertInstanceOf('Mustache_Cache_FilesystemCache', $mustache->getCache());
$this->assertEquals(array(Mustache_Engine::PRAGMA_FILTERS), $mustache->getPragmas());
}
public static function getFoo()
@@ -67,7 +69,7 @@ class Mustache_Test_EngineTest extends Mustache_Test_FunctionalTestCase
->disableOriginalConstructor()
->getMock();
$mustache = new MustacheStub;
$mustache = new MustacheStub();
$mustache->template = $template;
$template->expects($this->once())
@@ -82,11 +84,11 @@ class Mustache_Test_EngineTest extends Mustache_Test_FunctionalTestCase
public function testSettingServices()
{
$logger = new Mustache_Logger_StreamLogger(tmpfile());
$loader = new Mustache_Loader_StringLoader;
$tokenizer = new Mustache_Tokenizer;
$parser = new Mustache_Parser;
$compiler = new Mustache_Compiler;
$mustache = new Mustache_Engine;
$loader = new Mustache_Loader_StringLoader();
$tokenizer = new Mustache_Tokenizer();
$parser = new Mustache_Parser();
$compiler = new Mustache_Compiler();
$mustache = new Mustache_Engine();
$cache = new Mustache_Cache_FilesystemCache(self::$tempDir);
$this->assertNotSame($logger, $mustache->getLogger());
@@ -179,7 +181,7 @@ class Mustache_Test_EngineTest extends Mustache_Test_FunctionalTestCase
public function testImmutablePartialsLoadersThrowException()
{
$mustache = new Mustache_Engine(array(
'partials_loader' => new Mustache_Loader_StringLoader,
'partials_loader' => new Mustache_Loader_StringLoader(),
));
$mustache->setPartials(array('foo' => '{{ foo }}'));
@@ -243,7 +245,7 @@ class Mustache_Test_EngineTest extends Mustache_Test_FunctionalTestCase
*/
public function testSetHelpersThrowsExceptions()
{
$mustache = new Mustache_Engine;
$mustache = new Mustache_Engine();
$mustache->setHelpers('monkeymonkeymonkey');
}
@@ -252,8 +254,8 @@ class Mustache_Test_EngineTest extends Mustache_Test_FunctionalTestCase
*/
public function testSetLoggerThrowsExceptions()
{
$mustache = new Mustache_Engine;
$mustache->setLogger(new StdClass);
$mustache = new Mustache_Engine();
$mustache->setLogger(new StdClass());
}
public function testLoadPartialCascading()
@@ -319,6 +321,16 @@ class Mustache_Test_EngineTest extends Mustache_Test_FunctionalTestCase
$this->assertContains("WARNING: Partial not found: \"bar\"", $log);
}
/**
* @expectedException Mustache_Exception_InvalidArgumentException
*/
public function testUnknownPragmaThrowsException()
{
new Mustache_Engine(array(
'pragmas' => array('UNKNOWN')
));
}
private function getLoggedMustache($level = Mustache_Logger::ERROR)
{
$name = tempnam(sys_get_temp_dir(), 'mustache-test');
@@ -19,7 +19,7 @@ class Mustache_Test_FiveThree_Functional_ClosureQuirksTest extends PHPUnit_Frame
public function setUp()
{
$this->mustache = new Mustache_Engine;
$this->mustache = new Mustache_Engine();
}
public function testClosuresDontLikeItWhenYouTouchTheirProperties()
@@ -0,0 +1,50 @@
<?php
/*
* This file is part of Mustache.php.
*
* (c) 2010-2014 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* @group pragmas
* @group functional
*/
class Mustache_Test_FiveThree_Functional_EngineTest extends PHPUnit_Framework_TestCase
{
/**
* @dataProvider pragmaData
*/
public function testPragmasConstructorOption($pragmas, $helpers, $data, $tpl, $expect)
{
$mustache = new Mustache_Engine(array(
'pragmas' => $pragmas,
'helpers' => $helpers,
));
$this->assertEquals($expect, $mustache->render($tpl, $data));
}
public function pragmaData()
{
$helpers = array(
'longdate' => function (\DateTime $value) {
return $value->format('Y-m-d h:m:s');
}
);
$data = array(
'date' => new DateTime('1/1/2000', new DateTimeZone('UTC')),
);
$tpl = '{{ date | longdate }}';
return array(
array(array(Mustache_Engine::PRAGMA_FILTERS), $helpers, $data, $tpl, '2000-01-01 12:01:00'),
array(array(), $helpers, $data, $tpl, '' ),
);
}
}
@@ -19,7 +19,7 @@ class Mustache_Test_FiveThree_Functional_FiltersTest extends PHPUnit_Framework_T
public function setUp()
{
$this->mustache = new Mustache_Engine;
$this->mustache = new Mustache_Engine();
}
/**
@@ -71,7 +71,7 @@ class Mustache_Test_FiveThree_Functional_FiltersTest extends PHPUnit_Framework_T
return sprintf('[[%s]]', $value);
});
$foo = new \StdClass;
$foo = new \StdClass();
$foo->date = new DateTime('1/1/2000', new DateTimeZone("UTC"));
$this->assertEquals('[[2000-01-01 12:01:00]]', $tpl->render($foo));
@@ -19,14 +19,14 @@ class Mustache_Test_FiveThree_Functional_HigherOrderSectionsTest extends PHPUnit
public function setUp()
{
$this->mustache = new Mustache_Engine;
$this->mustache = new Mustache_Engine();
}
public function testAnonymousFunctionSectionCallback()
{
$tpl = $this->mustache->loadTemplate('{{#wrapper}}{{name}}{{/wrapper}}');
$foo = new Mustache_Test_FiveThree_Functional_Foo;
$foo = new Mustache_Test_FiveThree_Functional_Foo();
$foo->name = 'Mario';
$foo->wrapper = function ($text) {
return sprintf('<div class="anonymous">%s</div>', $text);
@@ -40,7 +40,7 @@ class Mustache_Test_FiveThree_Functional_HigherOrderSectionsTest extends PHPUnit
$one = $this->mustache->loadTemplate('{{name}}');
$two = $this->mustache->loadTemplate('{{#wrap}}{{name}}{{/wrap}}');
$foo = new Mustache_Test_FiveThree_Functional_Foo;
$foo = new Mustache_Test_FiveThree_Functional_Foo();
$foo->name = 'Luigi';
$this->assertEquals($foo->name, $one->render($foo));
@@ -19,7 +19,7 @@ class Mustache_Test_FiveThree_Functional_LambdaHelperTest extends PHPUnit_Framew
public function setUp()
{
$this->mustache = new Mustache_Engine;
$this->mustache = new Mustache_Engine();
}
public function testSectionLambdaHelper()
@@ -27,7 +27,7 @@ class Mustache_Test_FiveThree_Functional_LambdaHelperTest extends PHPUnit_Framew
$one = $this->mustache->loadTemplate('{{name}}');
$two = $this->mustache->loadTemplate('{{#lambda}}{{name}}{{/lambda}}');
$foo = new StdClass;
$foo = new StdClass();
$foo->name = 'Mario';
$foo->lambda = function ($text, $mustache) {
return strtoupper($mustache->render($text));
@@ -23,7 +23,7 @@ class Mustache_Test_FiveThree_Functional_StrictCallablesTest extends PHPUnit_Fra
$mustache = new Mustache_Engine(array('strict_callables' => $strict));
$tpl = $mustache->loadTemplate('{{# section }}{{ name }}{{/ section }}');
$data = new StdClass;
$data = new StdClass();
$data->name = $name;
$data->section = $section;
+1 -1
View File
@@ -18,7 +18,7 @@ class Mustache_Test_Functional_CallTest extends PHPUnit_Framework_TestCase
public function testCallEatsContext()
{
$m = new Mustache_Engine;
$m = new Mustache_Engine();
$tpl = $m->loadTemplate('{{# foo }}{{ label }}: {{ name }}{{/ foo }}');
$foo = new Mustache_Test_Functional_ClassWithCall();
@@ -92,8 +92,9 @@ class Mustache_Test_Functional_ExamplesTest extends PHPUnit_Framework_TestCase
// load other files
switch ($info['extension']) {
case 'php':
require_once($fullpath);
$context = new $info['filename'];
require_once $fullpath;
$className = $info['filename'];
$context = new $className();
break;
case 'mustache':
@@ -19,7 +19,7 @@ class Mustache_Test_Functional_HigherOrderSectionsTest extends Mustache_Test_Fun
public function setUp()
{
$this->mustache = new Mustache_Engine;
$this->mustache = new Mustache_Engine();
}
/**
@@ -32,10 +32,10 @@ class Mustache_Test_Functional_HigherOrderSectionsTest extends Mustache_Test_Fun
public function sectionCallbackData()
{
$foo = new Mustache_Test_Functional_Foo;
$foo = new Mustache_Test_Functional_Foo();
$foo->doublewrap = array($foo, 'wrapWithBoth');
$bar = new Mustache_Test_Functional_Foo;
$bar = new Mustache_Test_Functional_Foo();
$bar->trimmer = array(get_class($bar), 'staticTrim');
return array(
@@ -48,7 +48,7 @@ class Mustache_Test_Functional_HigherOrderSectionsTest extends Mustache_Test_Fun
{
$tpl = $this->mustache->loadTemplate('{{#trim}} {{name}} {{/trim}}');
$foo = new Mustache_Test_Functional_Foo;
$foo = new Mustache_Test_Functional_Foo();
$data = array(
'name' => 'Bob',
@@ -81,7 +81,7 @@ class Mustache_Test_Functional_HigherOrderSectionsTest extends Mustache_Test_Fun
$tpl = $mustache->loadTemplate('{{#wrap}}NAME{{/wrap}}');
$foo = new Mustache_Test_Functional_Foo;
$foo = new Mustache_Test_Functional_Foo();
$foo->wrap = array($foo, 'wrapWithEm');
$this->assertEquals('<em>NAME</em>', $tpl->render($foo));
@@ -96,7 +96,7 @@ class Mustache_Test_Functional_HigherOrderSectionsTest extends Mustache_Test_Fun
$tpl = $mustache->loadTemplate('{{#wrap}}{{name}}{{/wrap}}');
$foo = new Mustache_Test_Functional_Foo;
$foo = new Mustache_Test_Functional_Foo();
$foo->wrap = array($foo, 'wrapWithEm');
$this->assertEquals('<em>' . $foo->name . '</em>', $tpl->render($foo));
@@ -115,7 +115,7 @@ class Mustache_Test_Functional_HigherOrderSectionsTest extends Mustache_Test_Fun
));
$tpl = $mustache->loadTemplate('{{#wrap}}{{name}}{{/wrap}}');
$foo = new Mustache_Test_Functional_Foo;
$foo = new Mustache_Test_Functional_Foo();
$foo->wrap = array($foo, 'wrapWithEm');
$this->assertEquals('<em>' . $foo->name . '</em>', $tpl->render($foo));
$this->assertCount($expect, glob($cacheDir . '/*.php'));
@@ -0,0 +1,437 @@
<?php
/**
* @group inheritance
* @group functional
*/
class Mustache_Test_Functional_InheritanceTest extends PHPUnit_Framework_TestCase
{
private $mustache;
public function setUp()
{
$this->mustache = new Mustache_Engine(array(
'pragmas' => array(Mustache_Engine::PRAGMA_BLOCKS),
));
}
public function getIllegalInheritanceExamples()
{
return array(
array(
array(
'foo' => '{{$baz}}default content{{/baz}}',
),
array(
'bar' => 'set by user'
),
'{{< foo }}{{# bar }}{{$ baz }}{{/ baz }}{{/ bar }}{{/ foo }}',
),
array(
array(
'foo' => '{{$baz}}default content{{/baz}}'
),
array(
),
'{{<foo}}{{^bar}}{{$baz}}set by template{{/baz}}{{/bar}}{{/foo}}',
),
array(
array(
'foo' => '{{$baz}}default content{{/baz}}',
'qux' => 'I am a partial'
),
array(
),
'{{<foo}}{{>qux}}{{$baz}}set by template{{/baz}}{{/foo}}'
),
array(
array(
'foo' => '{{$baz}}default content{{/baz}}'
),
array(),
'{{<foo}}{{=<% %>=}}<%={{ }}=%>{{/foo}}'
)
);
}
public function getLegalInheritanceExamples()
{
return array(
array(
array(
'foo' => '{{$baz}}default content{{/baz}}',
),
array(
'bar' => 'set by user'
),
'{{<foo}}{{bar}}{{$baz}}override{{/baz}}{{/foo}}',
'override'
),
array(
array(
'foo' => '{{$baz}}default content{{/baz}}'
),
array(
),
'{{<foo}}{{! ignore me }}{{$baz}}set by template{{/baz}}{{/foo}}',
'set by template'
),
array(
array(
'foo' => '{{$baz}}defualt content{{/baz}}'
),
array(),
'{{<foo}}set by template{{$baz}}also set by template{{/baz}}{{/foo}}',
'also set by template'
)
);
}
public function testDefaultContent()
{
$tpl = $this->mustache->loadTemplate('{{$title}}Default title{{/title}}');
$data = array();
$this->assertEquals('Default title', $tpl->render($data));
}
public function testDefaultContentRendersVariables()
{
$tpl = $this->mustache->loadTemplate('{{$foo}}default {{bar}} content{{/foo}}');
$data = array(
'bar' => 'baz'
);
$this->assertEquals('default baz content', $tpl->render($data));
}
public function testDefaultContentRendersTripleMustacheVariables()
{
$tpl = $this->mustache->loadTemplate('{{$foo}}default {{{bar}}} content{{/foo}}');
$data = array(
'bar' => '<baz>'
);
$this->assertEquals('default <baz> content', $tpl->render($data));
}
public function testDefaultContentRendersSections()
{
$tpl = $this->mustache->loadTemplate(
'{{$foo}}default {{#bar}}{{baz}}{{/bar}} content{{/foo}}'
);
$data = array(
'bar' => array('baz' => 'qux')
);
$this->assertEquals('default qux content', $tpl->render($data));
}
public function testDefaultContentRendersNegativeSections()
{
$tpl = $this->mustache->loadTemplate(
'{{$foo}}default {{^bar}}{{baz}}{{/bar}} content{{/foo}}'
);
$data = array(
'foo' => array('bar' => 'qux'),
'baz' => 'three'
);
$this->assertEquals('default three content', $tpl->render($data));
}
public function testMustacheInjectionInDefaultContent()
{
$tpl = $this->mustache->loadTemplate(
'{{$foo}}default {{#bar}}{{baz}}{{/bar}} content{{/foo}}'
);
$data = array(
'bar' => array('baz' => '{{qux}}')
);
$this->assertEquals('default {{qux}} content', $tpl->render($data));
}
public function testDefaultContentRenderedInsideIncludedTemplates()
{
$partials = array(
'include' => '{{$foo}}default content{{/foo}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<include}}{{/include}}'
);
$data = array();
$this->assertEquals('default content', $tpl->render($data));
}
public function testOverriddenContent()
{
$partials = array(
'super' => '...{{$title}}Default title{{/title}}...'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<super}}{{$title}}sub template title{{/title}}{{/super}}'
);
$data = array();
$this->assertEquals('...sub template title...', $tpl->render($data));
}
public function testOverriddenPartial()
{
$partials = array(
'partial' => '|{{$stuff}}...{{/stuff}}{{$default}} default{{/default}}|'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'test {{<partial}}{{$stuff}}override1{{/stuff}}{{/partial}} {{<partial}}{{$stuff}}override2{{/stuff}}{{/partial}}'
);
$data = array();
$this->assertEquals('test |override1 default| |override2 default|', $tpl->render($data));
}
public function testDataDoesNotOverrideBlock()
{
$partials = array(
'include' => '{{$var}}var in include{{/var}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<include}}{{$var}}var in template{{/var}}{{/include}}'
);
$data = array(
'var' => 'var in data'
);
$this->assertEquals('var in template', $tpl->render($data));
}
public function testDataDoesNotOverrideDefaultBlockValue()
{
$partials = array(
'include' => '{{$var}}var in include{{/var}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<include}}{{/include}}'
);
$data = array(
'var' => 'var in data'
);
$this->assertEquals('var in include', $tpl->render($data));
}
public function testOverridePartialWithNewlines()
{
$partials = array(
'partial' => '{{$ballmer}}peaking{{/ballmer}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
"{{<partial}}{{\$ballmer}}\npeaked\n\n:(\n{{/ballmer}}{{/partial}}"
);
$data = array();
$this->assertEquals("peaked\n\n:(\n", $tpl->render($data));
}
public function testInheritIndentationWhenOverridingAPartial()
{
$partials = array(
'partial' =>
'stop:
{{$nineties}}collaborate and listen{{/nineties}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<partial}}{{$nineties}}hammer time{{/nineties}}{{/partial}}'
);
$data = array();
$this->assertEquals(
'stop:
hammer time',
$tpl->render($data)
);
}
public function testOverrideOneSubstitutionButNotTheOther()
{
$partials = array(
'partial' => '{{$stuff}}default one{{/stuff}}, {{$stuff2}}default two{{/stuff2}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<partial}}{{$stuff2}}override two{{/stuff2}}{{/partial}}'
);
$data = array();
$this->assertEquals('default one, override two', $tpl->render($data));
}
public function testSuperTemplatesWithNoParameters()
{
$partials = array(
'include' => '{{$foo}}default content{{/foo}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{>include}}|{{<include}}{{/include}}'
);
$data = array();
$this->assertEquals('default content|default content', $tpl->render($data));
}
public function testRecursionInInheritedTemplates()
{
$partials = array(
'include' => '{{$foo}}default content{{/foo}} {{$bar}}{{<include2}}{{/include2}}{{/bar}}',
'include2' => '{{$foo}}include2 default content{{/foo}} {{<include}}{{$bar}}don\'t recurse{{/bar}}{{/include}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<include}}{{$foo}}override{{/foo}}{{/include}}'
);
$data = array();
$this->assertEquals('override override override don\'t recurse', $tpl->render($data));
}
public function testTopLevelSubstitutionsTakePrecedenceInMultilevelInheritance()
{
$partials = array(
'parent' => '{{<older}}{{$a}}p{{/a}}{{/older}}',
'older' => '{{<grandParent}}{{$a}}o{{/a}}{{/grandParent}}',
'grandParent' => '{{$a}}g{{/a}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<parent}}{{$a}}c{{/a}}{{/parent}}'
);
$data = array();
$this->assertEquals('c', $tpl->render($data));
}
public function testMultiLevelInheritanceNoSubChild()
{
$partials = array(
'parent' => '{{<older}}{{$a}}p{{/a}}{{/older}}',
'older' => '{{<grandParent}}{{$a}}o{{/a}}{{/grandParent}}',
'grandParent' => '{{$a}}g{{/a}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<parent}}{{/parent}}'
);
$data = array();
$this->assertEquals('p', $tpl->render($data));
}
public function testIgnoreTextInsideSuperTemplatesButParseArgs()
{
$partials = array(
'include' => '{{$foo}}default content{{/foo}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<include}} asdfasd {{$foo}}hmm{{/foo}} asdfasdfasdf {{/include}}'
);
$data = array();
$this->assertEquals('hmm', $tpl->render($data));
}
public function testIgnoreTextInsideSuperTemplates()
{
$partials = array(
'include' => '{{$foo}}default content{{/foo}}'
);
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate(
'{{<include}} asdfasd asdfasdfasdf {{/include}}'
);
$data = array();
$this->assertEquals('default content', $tpl->render($data));
}
/**
* @dataProvider getIllegalInheritanceExamples
* @expectedException Mustache_Exception_SyntaxException
* @expectedExceptionMessage Illegal content in < parent tag
*/
public function testIllegalInheritanceExamples($partials, $data, $template)
{
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate($template);
$tpl->render($data);
}
/**
* @dataProvider getLegalInheritanceExamples
*/
public function testLegalInheritanceExamples($partials, $data, $template, $expect)
{
$this->mustache->setPartials($partials);
$tpl = $this->mustache->loadTemplate($template);
$this->assertSame($expect, $tpl->render($data));
}
}
@@ -20,7 +20,7 @@ class Mustache_Test_Functional_MustacheInjectionTest extends PHPUnit_Framework_T
public function setUp()
{
$this->mustache = new Mustache_Engine;
$this->mustache = new Mustache_Engine();
}
/**
@@ -0,0 +1,45 @@
<?php
/*
* This file is part of Mustache.php.
*
* (c) 2010-2014 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* @group functional
* @group partials
*/
class Mustache_Test_Functional_NestedPartialIndentTest extends PHPUnit_Framework_TestCase
{
/**
* @dataProvider partialsAndStuff
*/
public function testNestedPartialsAreIndentedProperly($src, array $partials, $expected)
{
$m = new Mustache_Engine(array(
'partials' => $partials
));
$tpl = $m->loadTemplate($src);
$this->assertEquals($expected, $tpl->render());
}
public function partialsAndStuff()
{
$partials = array(
'a' => ' {{> b }}',
'b' => ' {{> d }}',
'c' => ' {{> d }}{{> d }}',
'd' => 'D!',
);
return array(
array(' {{> a }}', $partials, ' D!'),
array(' {{> b }}', $partials, ' D!'),
array(' {{> c }}', $partials, ' D!D!'),
);
}
}
@@ -19,13 +19,13 @@ class Mustache_Test_Functional_ObjectSectionTest extends PHPUnit_Framework_TestC
public function setUp()
{
$this->mustache = new Mustache_Engine;
$this->mustache = new Mustache_Engine();
}
public function testBasicObject()
{
$tpl = $this->mustache->loadTemplate('{{#foo}}{{name}}{{/foo}}');
$this->assertEquals('Foo', $tpl->render(new Mustache_Test_Functional_Alpha));
$this->assertEquals('Foo', $tpl->render(new Mustache_Test_Functional_Alpha()));
}
/**
@@ -34,7 +34,7 @@ class Mustache_Test_Functional_ObjectSectionTest extends PHPUnit_Framework_TestC
public function testObjectWithGet()
{
$tpl = $this->mustache->loadTemplate('{{#foo}}{{name}}{{/foo}}');
$this->assertEquals('Foo', $tpl->render(new Mustache_Test_Functional_Beta));
$this->assertEquals('Foo', $tpl->render(new Mustache_Test_Functional_Beta()));
}
/**
@@ -43,14 +43,14 @@ class Mustache_Test_Functional_ObjectSectionTest extends PHPUnit_Framework_TestC
public function testSectionObjectWithGet()
{
$tpl = $this->mustache->loadTemplate('{{#bar}}{{#foo}}{{name}}{{/foo}}{{/bar}}');
$this->assertEquals('Foo', $tpl->render(new Mustache_Test_Functional_Gamma));
$this->assertEquals('Foo', $tpl->render(new Mustache_Test_Functional_Gamma()));
}
public function testSectionObjectWithFunction()
{
$tpl = $this->mustache->loadTemplate('{{#foo}}{{name}}{{/foo}}');
$alpha = new Mustache_Test_Functional_Alpha;
$alpha->foo = new Mustache_Test_Functional_Delta;
$alpha = new Mustache_Test_Functional_Alpha();
$alpha->foo = new Mustache_Test_Functional_Delta();
$this->assertEquals('Foo', $tpl->render($alpha));
}
}
@@ -95,7 +95,7 @@ class Mustache_Test_Functional_Gamma
public function __construct()
{
$this->bar = new Mustache_Test_Functional_Beta;
$this->bar = new Mustache_Test_Functional_Beta();
}
}
+2 -2
View File
@@ -35,7 +35,7 @@ class Mustache_Test_HelperCollectionTest extends PHPUnit_Framework_TestCase
$foo = array($this, 'getFoo');
$bar = 'BAR';
$helpers = new Mustache_HelperCollection;
$helpers = new Mustache_HelperCollection();
$this->assertTrue($helpers->isEmpty());
$this->assertFalse($helpers->has('foo'));
$this->assertFalse($helpers->has('bar'));
@@ -61,7 +61,7 @@ class Mustache_Test_HelperCollectionTest extends PHPUnit_Framework_TestCase
$foo = array($this, 'getFoo');
$bar = 'BAR';
$helpers = new Mustache_HelperCollection;
$helpers = new Mustache_HelperCollection();
$this->assertTrue($helpers->isEmpty());
$this->assertFalse($helpers->has('foo'));
$this->assertFalse($helpers->has('bar'));
@@ -46,7 +46,7 @@ class Mustache_Test_Loader_ArrayLoaderTest extends PHPUnit_Framework_TestCase
*/
public function testMissingTemplatesThrowExceptions()
{
$loader = new Mustache_Loader_ArrayLoader;
$loader = new Mustache_Loader_ArrayLoader();
$loader->load('not_a_real_template');
}
}
@@ -16,7 +16,7 @@ class Mustache_Test_Loader_StringLoaderTest extends PHPUnit_Framework_TestCase
{
public function testLoadTemplates()
{
$loader = new Mustache_Loader_StringLoader;
$loader = new Mustache_Loader_StringLoader();
$this->assertEquals('foo', $loader->load('foo'));
$this->assertEquals('{{ bar }}', $loader->load('{{ bar }}'));
@@ -16,7 +16,7 @@ class Mustache_Test_Logger_AbstractLoggerTest extends PHPUnit_Framework_TestCase
{
public function testEverything()
{
$logger = new Mustache_Test_Logger_TestLogger;
$logger = new Mustache_Test_Logger_TestLogger();
$logger->emergency('emergency message');
$logger->alert('alert message');
+226 -2
View File
@@ -20,7 +20,7 @@ class Mustache_Test_ParserTest extends PHPUnit_Framework_TestCase
*/
public function testParse($tokens, $expected)
{
$parser = new Mustache_Parser;
$parser = new Mustache_Parser();
$this->assertEquals($expected, $parser->parse($tokens));
}
@@ -88,6 +88,7 @@ class Mustache_Test_ParserTest extends PHPUnit_Framework_TestCase
Mustache_Tokenizer::VALUE => 'bar'
),
),
array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
@@ -116,6 +117,202 @@ class Mustache_Test_ParserTest extends PHPUnit_Framework_TestCase
),
),
// This *would* be an invalid inheritance parse tree, but that pragma
// isn't enabled so it'll thunk it back into an "escaped" token:
array(
array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_BLOCK_VAR,
Mustache_Tokenizer::NAME => 'foo',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::VALUE => 'bar'
),
),
array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED,
Mustache_Tokenizer::NAME => '$foo',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::VALUE => 'bar'
),
),
),
array(
array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::VALUE => " ",
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_DELIM_CHANGE,
Mustache_Tokenizer::LINE => 0,
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::VALUE => " \n",
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED,
Mustache_Tokenizer::NAME => 'foo',
Mustache_Tokenizer::OTAG => '[[',
Mustache_Tokenizer::CTAG => ']]',
Mustache_Tokenizer::LINE => 1,
),
),
array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_ESCAPED,
Mustache_Tokenizer::NAME => 'foo',
Mustache_Tokenizer::OTAG => '[[',
Mustache_Tokenizer::CTAG => ']]',
Mustache_Tokenizer::LINE => 1,
),
),
),
);
}
/**
* @dataProvider getInheritanceTokenSets
*/
public function testParseWithInheritance($tokens, $expected)
{
$parser = new Mustache_Parser();
$parser->setPragmas(array(Mustache_Engine::PRAGMA_BLOCKS));
$this->assertEquals($expected, $parser->parse($tokens));
}
public function getInheritanceTokenSets()
{
return array(
array(
array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_PARENT,
Mustache_Tokenizer::NAME => 'foo',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::INDEX => 8
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_BLOCK_VAR,
Mustache_Tokenizer::NAME => 'bar',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::INDEX => 16
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::VALUE => 'baz'
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_END_SECTION,
Mustache_Tokenizer::NAME => 'bar',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::INDEX => 19
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_END_SECTION,
Mustache_Tokenizer::NAME => 'foo',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::INDEX => 27
)
),
array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_PARENT,
Mustache_Tokenizer::NAME => 'foo',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::INDEX => 8,
Mustache_Tokenizer::END => 27,
Mustache_Tokenizer::NODES => array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_BLOCK_ARG,
Mustache_Tokenizer::NAME => 'bar',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::INDEX => 16,
Mustache_Tokenizer::END => 19,
Mustache_Tokenizer::NODES => array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::VALUE => 'baz'
)
)
)
)
)
)
),
array(
array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_BLOCK_VAR,
Mustache_Tokenizer::NAME => 'foo',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::VALUE => 'bar'
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_END_SECTION,
Mustache_Tokenizer::NAME => 'foo',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::INDEX => 11,
),
),
array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_BLOCK_VAR,
Mustache_Tokenizer::NAME => 'foo',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::END => 11,
Mustache_Tokenizer::NODES => array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::VALUE => 'bar'
)
)
)
)
),
);
}
@@ -125,7 +322,7 @@ class Mustache_Test_ParserTest extends PHPUnit_Framework_TestCase
*/
public function testParserThrowsExceptions($tokens)
{
$parser = new Mustache_Parser;
$parser = new Mustache_Parser();
$parser->parse($tokens);
}
@@ -197,6 +394,33 @@ class Mustache_Test_ParserTest extends PHPUnit_Framework_TestCase
),
),
),
// This *would* be a valid inheritance parse tree, but that pragma
// isn't enabled here so it's going to fail :)
array(
array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_BLOCK_VAR,
Mustache_Tokenizer::NAME => 'foo',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::VALUE => 'bar'
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_END_SECTION,
Mustache_Tokenizer::NAME => 'foo',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::INDEX => 11,
),
),
),
);
}
}
+2 -2
View File
@@ -15,7 +15,7 @@ abstract class Mustache_Test_SpecTestCase extends PHPUnit_Framework_TestCase
public static function setUpBeforeClass()
{
self::$mustache = new Mustache_Engine;
self::$mustache = new Mustache_Engine();
}
protected static function loadTemplate($source, $partials)
@@ -42,7 +42,7 @@ abstract class Mustache_Test_SpecTestCase extends PHPUnit_Framework_TestCase
}
$data = array();
$yaml = new sfYamlParser;
$yaml = new sfYamlParser();
$file = file_get_contents($filename);
// @hack: pre-process the 'lambdas' spec so the Symfony YAML parser doesn't complain.
+3 -3
View File
@@ -16,7 +16,7 @@ class Mustache_Test_TemplateTest extends PHPUnit_Framework_TestCase
{
public function testConstructor()
{
$mustache = new Mustache_Engine;
$mustache = new Mustache_Engine();
$template = new Mustache_Test_TemplateStub($mustache);
$this->assertSame($mustache, $template->getMustache());
}
@@ -24,10 +24,10 @@ class Mustache_Test_TemplateTest extends PHPUnit_Framework_TestCase
public function testRendering()
{
$rendered = '<< wheee >>';
$mustache = new Mustache_Engine;
$mustache = new Mustache_Engine();
$template = new Mustache_Test_TemplateStub($mustache);
$template->rendered = $rendered;
$context = new Mustache_Context;
$context = new Mustache_Context();
if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
$this->assertEquals($rendered, $template());
+32 -3
View File
@@ -20,7 +20,7 @@ class Mustache_Test_TokenizerTest extends PHPUnit_Framework_TestCase
*/
public function testScan($text, $delimiters, $expected)
{
$tokenizer = new Mustache_Tokenizer;
$tokenizer = new Mustache_Tokenizer();
$this->assertSame($expected, $tokenizer->scan($text, $delimiters));
}
@@ -29,7 +29,7 @@ class Mustache_Test_TokenizerTest extends PHPUnit_Framework_TestCase
*/
public function testUnevenBracesThrowExceptions()
{
$tokenizer = new Mustache_Tokenizer;
$tokenizer = new Mustache_Tokenizer();
$text = "{{{ name }}";
$tokenizer->scan($text, null);
@@ -40,7 +40,7 @@ class Mustache_Test_TokenizerTest extends PHPUnit_Framework_TestCase
*/
public function testUnevenBracesWithCustomDelimiterThrowExceptions()
{
$tokenizer = new Mustache_Tokenizer;
$tokenizer = new Mustache_Tokenizer();
$text = "<%{ name %>";
$tokenizer->scan($text, "<% %>");
@@ -273,6 +273,35 @@ class Mustache_Test_TokenizerTest extends PHPUnit_Framework_TestCase
)
)
),
// Ensure that $arg token is not picked up during tokenization
array(
'{{$arg}}default{{/arg}}',
null,
array(
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_BLOCK_VAR,
Mustache_Tokenizer::NAME => 'arg',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::INDEX => 8
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_TEXT,
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::VALUE => "default",
),
array(
Mustache_Tokenizer::TYPE => Mustache_Tokenizer::T_END_SECTION,
Mustache_Tokenizer::NAME => 'arg',
Mustache_Tokenizer::OTAG => '{{',
Mustache_Tokenizer::CTAG => '}}',
Mustache_Tokenizer::LINE => 0,
Mustache_Tokenizer::INDEX => 15,
)
)
),
);
}
}
+88
View File
@@ -0,0 +1,88 @@
<?php
class Filters
{
public $states = array(
'al' => 'Alabama',
'ak' => 'Alaska',
'az' => 'Arizona',
'ar' => 'Arkansas',
'ca' => 'California',
'co' => 'Colorado',
'ct' => 'Connecticut',
'de' => 'Delaware',
'fl' => 'Florida',
'ga' => 'Georgia',
'hi' => 'Hawaii',
'id' => 'Idaho',
'il' => 'Illinois',
'in' => 'Indiana',
'ia' => 'Iowa',
'ks' => 'Kansas',
'ky' => 'Kentucky',
'la' => 'Louisiana',
'me' => 'Maine',
'md' => 'Maryland',
'ma' => 'Massachusetts',
'mi' => 'Michigan',
'mn' => 'Minnesota',
'ms' => 'Mississippi',
'mo' => 'Missouri',
'mt' => 'Montana',
'ne' => 'Nebraska',
'nv' => 'Nevada',
'nh' => 'New Hampshire',
'nj' => 'New Jersey',
'nm' => 'New Mexico',
'ny' => 'New York',
'nc' => 'North Carolina',
'nd' => 'North Dakota',
'oh' => 'Ohio',
'ok' => 'Oklahoma',
'or' => 'Oregon',
'pa' => 'Pennsylvania',
'ri' => 'Rhode Island',
'sc' => 'South Carolina',
'sd' => 'South Dakota',
'tn' => 'Tennessee',
'tx' => 'Texas',
'ut' => 'Utah',
'vt' => 'Vermont',
'va' => 'Virginia',
'wa' => 'Washington',
'wv' => 'West Virginia',
'wi' => 'Wisconsin',
'wy' => 'Wyoming',
);
// The next few functions are ugly, because they have to work in PHP 5.2...
// for everyone who doesn't have to support 5.2, please, for the love, make
// your ViewModel return closures rather than `array($this, '...')`
//
// :)
public function upcase()
{
return array($this, '_upcase');
}
public function _upcase($val)
{
return strtoupper($val);
}
public function eachPair()
{
return array($this, '_eachPair');
}
public function _eachPair($val)
{
$ret = array();
foreach ($val as $key => $value) {
array_push($ret, compact('key', 'value'));
}
return $ret;
}
}
+4
View File
@@ -0,0 +1,4 @@
{{%FILTERS}}
{{# states | eachPair }}
{{ key | upcase }}: {{ value }}
{{/ states }}
+50
View File
@@ -0,0 +1,50 @@
AL: Alabama
AK: Alaska
AZ: Arizona
AR: Arkansas
CA: California
CO: Colorado
CT: Connecticut
DE: Delaware
FL: Florida
GA: Georgia
HI: Hawaii
ID: Idaho
IL: Illinois
IN: Indiana
IA: Iowa
KS: Kansas
KY: Kentucky
LA: Louisiana
ME: Maine
MD: Maryland
MA: Massachusetts
MI: Michigan
MN: Minnesota
MS: Mississippi
MO: Missouri
MT: Montana
NE: Nebraska
NV: Nevada
NH: New Hampshire
NJ: New Jersey
NM: New Mexico
NY: New York
NC: North Carolina
ND: North Dakota
OH: Ohio
OK: Oklahoma
OR: Oregon
PA: Pennsylvania
RI: Rhode Island
SC: South Carolina
SD: South Dakota
TN: Tennessee
TX: Texas
UT: Utah
VT: Vermont
VA: Virginia
WA: Washington
WV: West Virginia
WI: Wisconsin
WY: Wyoming
@@ -21,7 +21,7 @@ class MagicObject
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)
+1 -1
View File
@@ -6,7 +6,7 @@ class SectionObjects
public function middle()
{
return new SectionObject;
return new SectionObject();
}
public $final = "Then, surprisingly, it worked the final time.";