From 011e727b22d94ba627b87d79a84e9e71be4967ba Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 7 Nov 2010 14:21:10 +0100 Subject: [PATCH] fixed documentation and added infix notation for in (already supported for is) --- CHANGELOG | 1 + doc/02-Twig-for-Template-Designers.markdown | 23 ++++++++++++++++++++--- lib/Twig/ExpressionParser.php | 16 +++++++++++++++- test/Twig/Tests/Fixtures/expressions/in.test | 7 ++++++- test/Twig/Tests/Fixtures/tests/even.test | 6 +++++- 5 files changed, 47 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9c2f7e2..1fa01e1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,7 @@ Backward incompatibilities: * the include tag now merges the passed variables with the current context by default (the old behavior is still possible by adding the "only" keyword) + * added support for {{ 1 not in [2, 3] }} (more readable than the current {{ not (1 in [2, 3]) }}) * escaping has been rewritten (from pre-escaping to post-escaping) * the implementation of template inheritance has been rewritten (blocks can now be called individually and still work with inheritance) diff --git a/doc/02-Twig-for-Template-Designers.markdown b/doc/02-Twig-for-Template-Designers.markdown index 296ddf1..fa300a9 100644 --- a/doc/02-Twig-for-Template-Designers.markdown +++ b/doc/02-Twig-for-Template-Designers.markdown @@ -141,6 +141,9 @@ Tests can accept arguments too: Tests can be negated by prepending them with `not`: [twig] + {% if not (loop.index is divisibleby(3)) %} + + {# also works with an infix notation #} {% if loop.index is not divisibleby(3) %} The built-in tests section below describes all the built-in tests. @@ -980,6 +983,12 @@ combine multiple expressions: * `(expr)`: Groups an expression. +>**NOTE** +>The `is` and `in` operators support negation using an infix notation too: `foo +>is not bar` and `foo not in bar` instead of `not (foo is bar)` and `not (foo +>in bar)`. All other expressions require a prefix notation: `not (foo and +>bar)`. + ### Comparisons The following comparison operators are supported in any expression: `==`, @@ -998,10 +1007,10 @@ The following operators are very useful but don't fit into any of the other two categories: * `in` (new in Twig 0.9.5): Performs containment test. Returns `true` if the - left operand is contained in the right. {{ 1 in [1, 2, 3] }} would for + left operand is contained in the right. `{{ 1 in [1, 2, 3] }}` would for example return `true`. To perform a negative test, the whole expression - should be prefixed with `not` ({{ not 1 in [1, 2, 3] }} would return - `false`). + should be prefixed with `not` (`{{ not (1 in [1, 2, 3]) }}` would return + `false` - can also be written `{{ 1 not in [1, 2, 3] }}`). * `..` (new in Twig 0.9.5): Creates a sequence based on the operand before and after the operator (see the `for` tag for some usage examples). @@ -1155,6 +1164,14 @@ The `in` operator is a syntactic sugar for the `in` filter: TRUE {% endif %} +You can negate an `in` expression with `not`: + + [twig] + {% if not (1 in [1, 2, 3]) %} + + {# also works with an infix notation #} + {% if 1 not in [1, 2, 3] %} + ### `range` (new in Twig 0.9.5) Returns a list containing a sequence of numbers. The left side of the filter diff --git a/lib/Twig/ExpressionParser.php b/lib/Twig/ExpressionParser.php index 9698b7a..137f084 100644 --- a/lib/Twig/ExpressionParser.php +++ b/lib/Twig/ExpressionParser.php @@ -80,11 +80,19 @@ class Twig_ExpressionParser $lineno = $this->parser->getCurrentToken()->getLine(); $expr = $this->parseAddExpression(); $ops = array(); + $negated = false; while ( $this->parser->getStream()->test(Twig_Token::OPERATOR_TYPE, $operators) || + ($this->parser->getStream()->test(Twig_Token::NAME_TYPE, 'not') && $this->parser->getStream()->look()->test(Twig_Token::NAME_TYPE, 'in')) + || $this->parser->getStream()->test(Twig_Token::NAME_TYPE, 'in') ) { + $this->parser->getStream()->rewind(); + if ($this->parser->getStream()->test(Twig_Token::NAME_TYPE, 'not')) { + $negated = true; + $this->parser->getStream()->next(); + } $ops[] = new Twig_Node_Expression_Constant($this->parser->getStream()->next()->getValue(), $lineno); $ops[] = $this->parseAddExpression(); } @@ -93,7 +101,13 @@ class Twig_ExpressionParser return $expr; } - return new Twig_Node_Expression_Compare($expr, new Twig_Node($ops), $lineno); + $node = new Twig_Node_Expression_Compare($expr, new Twig_Node($ops), $lineno); + + if ($negated) { + $node = new Twig_Node_Expression_Unary_Not($node, $lineno); + } + + return $node; } public function parseAddExpression() diff --git a/test/Twig/Tests/Fixtures/expressions/in.test b/test/Twig/Tests/Fixtures/expressions/in.test index 344a97e..a5cbfb8 100644 --- a/test/Twig/Tests/Fixtures/expressions/in.test +++ b/test/Twig/Tests/Fixtures/expressions/in.test @@ -4,7 +4,11 @@ Twig supports the in operator {% if bar in foo %} TRUE {% endif %} -{% if not bar in foo %} +{% if not (bar in foo) %} +{% else %} +TRUE +{% endif %} +{% if bar not in foo %} {% else %} TRUE {% endif %} @@ -13,3 +17,4 @@ return array('bar' => 'bar', 'foo' => array('bar' => 'bar')) --EXPECT-- TRUE TRUE +TRUE diff --git a/test/Twig/Tests/Fixtures/tests/even.test b/test/Twig/Tests/Fixtures/tests/even.test index e96ef88..695b4c2 100644 --- a/test/Twig/Tests/Fixtures/tests/even.test +++ b/test/Twig/Tests/Fixtures/tests/even.test @@ -3,8 +3,12 @@ --TEMPLATE-- {{ 1 is even ? 'ko' : 'ok' }} {{ 2 is even ? 'ok' : 'ko' }} +{{ 1 is not even ? 'ok' : 'ko' }} +{{ 2 is not even ? 'ko' : 'ok' }} --DATA-- return array() --EXPECT-- ok -ok \ No newline at end of file +ok +ok +ok -- 1.7.2.5