fixed documentation and added infix notation for in (already supported for is)
authorFabien Potencier <fabien.potencier@gmail.com>
Sun, 7 Nov 2010 13:21:10 +0000 (14:21 +0100)
committerFabien Potencier <fabien.potencier@gmail.com>
Sun, 7 Nov 2010 13:21:10 +0000 (14:21 +0100)
CHANGELOG
doc/02-Twig-for-Template-Designers.markdown
lib/Twig/ExpressionParser.php
test/Twig/Tests/Fixtures/expressions/in.test
test/Twig/Tests/Fixtures/tests/even.test

index 9c2f7e2..1fa01e1 100644 (file)
--- 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)
index 296ddf1..fa300a9 100644 (file)
@@ -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
index 9698b7a..137f084 100644 (file)
@@ -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()
index 344a97e..a5cbfb8 100644 (file)
@@ -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
index e96ef88..695b4c2 100644 (file)
@@ -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