* 1.5.0
- * ...
+ * enhanced exceptions for unknown filters, functions, tests, and tags
* 1.4.0 (2011-12-07)
return $this->binaryOperators;
}
+ public function computeAlternatives($name, $items)
+ {
+ $alternatives = array();
+ foreach ($items as $item) {
+ $lev = levenshtein($name, $item);
+ if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {
+ $alternatives[$item] = $lev;
+ }
+ }
+ asort($alternatives);
+
+ return array_keys($alternatives);
+ }
+
protected function initOperators()
{
$this->unaryOperators = array();
$name = $this->getNode('filter')->getAttribute('value');
if (false === $filter = $compiler->getEnvironment()->getFilter($name)) {
- $alternativeFilters = array();
-
- foreach ($compiler->getEnvironment()->getFilters() as $filterName => $filter) {
- if (false !== strpos($filterName, $name)) {
- $alternativeFilters[] = $filterName;
- }
- }
-
- $exceptionMessage = sprintf('The filter "%s" does not exist', $name);
-
- if (count($alternativeFilters)) {
- $exceptionMessage = sprintf('%s. Did you mean "%s"?', $exceptionMessage, implode('", "', $alternativeFilters));
+ $message = sprintf('The filter "%s" does not exist', $name);
+ if ($alternatives = $compiler->getEnvironment()->computeAlternatives($name, array_keys($compiler->getEnvironment()->getFilters()))) {
+ $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
}
- throw new Twig_Error_Syntax($exceptionMessage, $this->getLine());
+ throw new Twig_Error_Syntax($message, $this->getLine());
}
$this->compileFilter($compiler, $filter);
{
$name = $this->getAttribute('name');
- $function = $compiler->getEnvironment()->getFunction($name);
-
- if (false === $function) {
- $alternativeFunctions = array();
-
- foreach ($compiler->getEnvironment()->getFunctions() as $functionName => $function) {
- if (false !== strpos($functionName, $name)) {
- $alternativeFunctions[] = $functionName;
- }
- }
-
- $exceptionMessage = sprintf('The function "%s" does not exist', $name);
-
- if (count($alternativeFunctions)) {
- $exceptionMessage = sprintf('%s. Did you mean "%s"?', $exceptionMessage, implode('", "', $alternativeFunctions));
+ if (false === $function = $compiler->getEnvironment()->getFunction($name)) {
+ $message = sprintf('The function "%s" does not exist', $name);
+ if ($alternatives = $compiler->getEnvironment()->computeAlternatives($name, array_keys($compiler->getEnvironment()->getFunctions()))) {
+ $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
}
- throw new Twig_Error_Syntax($exceptionMessage, $this->getLine());
+ throw new Twig_Error_Syntax($message, $this->getLine());
}
$compiler
public function compile(Twig_Compiler $compiler)
{
+ $name = $this->getAttribute('name');
$testMap = $compiler->getEnvironment()->getTests();
- if (!isset($testMap[$this->getAttribute('name')])) {
- throw new Twig_Error_Syntax(sprintf('The test "%s" does not exist', $this->getAttribute('name')), $this->getLine());
+ if (!isset($testMap[$name])) {
+ $message = sprintf('The test "%s" does not exist', $name);
+ if ($alternatives = $compiler->getEnvironment()->computeAlternatives($name, array_keys($compiler->getEnvironment()->getTests()))) {
+ $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
+ }
+
+ throw new Twig_Error_Syntax($message, $this->getLine());
}
$name = $this->getAttribute('name');
throw new Twig_Error_Syntax(sprintf('Unexpected tag name "%s" (expecting closing tag for the "%s" tag defined near line %s)', $token->getValue(), $test[0]->getTag(), $lineno), $token->getLine(), $this->stream->getFilename());
}
- throw new Twig_Error_Syntax(sprintf('Unknown tag name "%s"', $token->getValue()), $token->getLine(), $this->stream->getFilename());
+ $message = sprintf('Unknown tag name "%s"', $token->getValue());
+ if ($alternatives = $this->env->computeAlternatives($token->getValue(), array_keys($this->env->getTags()))) {
+ $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
+ }
+
+ throw new Twig_Error_Syntax($message, $token->getLine(), $this->stream->getFilename());
}
$this->stream->next();
return $tests;
}
+ /**
+ * @covers Twig_Node_Expression_Filter::compile
+ * @expectedException Twig_Error_Syntax
+ * @expectedExceptionMessage The filter "uppe" does not exist. Did you mean "upper" at line 0
+ */
+ public function testUnknownFilter()
+ {
+ $node = $this->createFilter(new Twig_Node_Expression_Constant('foo', 0), 'uppe');
+ $node->compile($this->getCompiler());
+ }
+
protected function createFilter($node, $name, array $arguments = array())
{
$name = new Twig_Node_Expression_Constant($name, 0);
$arguments = new Twig_Node($arguments);
+
return new Twig_Node_Expression_Filter($node, $name, $arguments, 0);
}
}
parent::testCompile($node, $source, $environment);
}
+ /**
+ * @covers Twig_Node_Expression_Filter::compile
+ * @expectedException Twig_Error_Syntax
+ * @expectedExceptionMessage The function "cycl" does not exist. Did you mean "cycle" at line 0
+ */
public function testUnknownFunction()
{
- $node = $this->createFunction('unknown', array());
- try {
- $node->compile($this->getCompiler());
- $this->fail();
- } catch (Exception $e) {
- $this->assertEquals('Twig_Error_Syntax', get_class($e));
- }
+ $node = $this->createFunction('cycl', array());
+ $node->compile($this->getCompiler());
}
public function getTests()
protected function createFunction($name, array $arguments = array())
{
- $arguments = new Twig_Node($arguments);
- return new Twig_Node_Expression_Function($name, $arguments, 0);
+ return new Twig_Node_Expression_Function($name, new Twig_Node($arguments), 0);
}
}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../TestCase.php';
+
+class Twig_Tests_Node_Expression_TestTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_Test::__construct
+ */
+ public function testConstructor()
+ {
+ $expr = new Twig_Node_Expression_Constant('foo', 0);
+ $name = new Twig_Node_Expression_Constant('null', 0);
+ $args = new Twig_Node();
+ $node = new Twig_Node_Expression_Test($expr, $name, $args, 0);
+
+ $this->assertEquals($expr, $node->getNode('node'));
+ $this->assertEquals($args, $node->getNode('arguments'));
+ $this->assertEquals($name, $node->getAttribute('name'));
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Test::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $tests = array();
+
+ $expr = new Twig_Node_Expression_Constant('foo', 0);
+ $node = new Twig_Node_Expression_Test_Null($expr, 'null', new Twig_Node(array()), 0);
+
+ $tests[] = array($node, '(null === "foo")');
+
+ return $tests;
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Filter::compile
+ * @expectedException Twig_Error_Syntax
+ * @expectedExceptionMessage The test "nul" does not exist. Did you mean "null" at line 0
+ */
+ public function testUnknownTest()
+ {
+ $node = $this->createTest(new Twig_Node_Expression_Constant('foo', 0), 'nul');
+ $node->compile($this->getCompiler());
+ }
+
+ protected function createTest($node, $name, array $arguments = array())
+ {
+ return new Twig_Node_Expression_Test($node, $name, new Twig_Node($arguments), 0);
+ }
+}
}
/**
+ * @expectedException Twig_Error_Syntax
+ * @expectedExceptionMessage Unknown tag name "foo". Did you mean "for" at line 0
+ */
+ public function testUnkownTag()
+ {
+ $stream = new Twig_TokenStream(array(
+ new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', 0),
+ new Twig_Token(Twig_Token::NAME_TYPE, 'foo', 0),
+ new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', 0),
+ new Twig_Token(Twig_Token::EOF_TYPE, '', 0),
+ ));
+ $parser = new Twig_Parser(new Twig_Environment());
+ $parser->parse($stream);
+ }
+
+ /**
* @dataProvider getFilterBodyNodesData
*/
public function testFilterBodyNodes($input, $expected)