enforced usage of named arguments after positional ones
authorFabien Potencier <fabien.potencier@gmail.com>
Wed, 1 May 2013 06:13:09 +0000 (08:13 +0200)
committerFabien Potencier <fabien.potencier@gmail.com>
Wed, 1 May 2013 18:07:00 +0000 (20:07 +0200)
CHANGELOG
composer.json
doc/templates.rst
ext/twig/php_twig.h
lib/Twig/Environment.php
lib/Twig/Node/Expression/Call.php
test/Twig/Tests/Fixtures/filters/date_namedargs.test
test/Twig/Tests/Node/Expression/CallTest.php [new file with mode: 0644]

index c1ac6d9..da7ac75 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,6 @@
-* 1.12.4 (2013-XX-XX)
+* 1.13.0 (2013-XX-XX)
 
- * n/a
+ * enforced usage of named arguments after positional ones
 
 * 1.12.3 (2013-04-08)
 
index 5530d28..3c5d079 100644 (file)
@@ -25,7 +25,7 @@
     },
     "extra": {
         "branch-alias": {
-            "dev-master": "1.12-dev"
+            "dev-master": "1.13-dev"
         }
     }
 }
index a329c92..c2047d9 100644 (file)
@@ -227,14 +227,12 @@ to change the default value:
     {# or skip the format value by using a named argument for the timezone #}
     {{ "now"|date(timezone="Europe/Paris") }}
 
-You can also use both positional and named arguments in one call, which is not
-recommended as it can be confusing:
+You can also use both positional and named arguments in one call, in which
+case positional arguments must always come before named arguments:
 
 .. code-block:: jinja
 
-    {# both work #}
     {{ "now"|date('d/m/Y H:i', timezone="Europe/Paris") }}
-    {{ "now"|date(timezone="Europe/Paris", 'd/m/Y H:i') }}
 
 .. tip::
 
index 1bae647..ce0caf5 100644 (file)
@@ -15,7 +15,7 @@
 #ifndef PHP_TWIG_H
 #define PHP_TWIG_H
 
-#define PHP_TWIG_VERSION "1.12.4-DEV"
+#define PHP_TWIG_VERSION "1.13.0-DEV"
 
 #include "php.h"
 
index 32b026a..54df5be 100644 (file)
@@ -16,7 +16,7 @@
  */
 class Twig_Environment
 {
-    const VERSION = '1.12.4-DEV';
+    const VERSION = '1.13.0-DEV';
 
     protected $charset;
     protected $loader;
index a97b3b5..87b62de 100644 (file)
@@ -98,7 +98,10 @@ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
             if (!is_int($name)) {
                 $named = true;
                 $name = $this->normalizeName($name);
+            } elseif ($named) {
+                throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
             }
+
             $parameters[$name] = $node;
         }
 
@@ -142,6 +145,10 @@ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
             $name = $this->normalizeName($param->name);
 
             if (array_key_exists($name, $parameters)) {
+                if (array_key_exists($pos, $parameters)) {
+                    throw new Twig_Error_Syntax(sprintf('Arguments "%s" is defined twice for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
+                }
+
                 $arguments[] = $parameters[$name];
                 unset($parameters[$name]);
             } elseif (array_key_exists($pos, $parameters)) {
index 6ca2049..4ecde8a 100644 (file)
@@ -3,7 +3,6 @@
 --TEMPLATE--
 {{ date|date(format='d/m/Y H:i:s P', timezone='America/Chicago') }}
 {{ date|date(timezone='America/Chicago', format='d/m/Y H:i:s P') }}
-{{ date|date(timezone='America/Chicago', 'd/m/Y H:i:s P') }}
 {{ date|date('d/m/Y H:i:s P', timezone='America/Chicago') }}
 --DATA--
 date_default_timezone_set('UTC');
@@ -12,4 +11,3 @@ return array('date' => mktime(13, 45, 0, 10, 4, 2010))
 04/10/2010 08:45:00 -05:00
 04/10/2010 08:45:00 -05:00
 04/10/2010 08:45:00 -05:00
-04/10/2010 08:45:00 -05:00
diff --git a/test/Twig/Tests/Node/Expression/CallTest.php b/test/Twig/Tests/Node/Expression/CallTest.php
new file mode 100644 (file)
index 0000000..b465549
--- /dev/null
@@ -0,0 +1,47 @@
+<?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.
+ */
+
+class Twig_Tests_Node_Expression_CallTest extends PHPUnit_Framework_TestCase
+{
+    public function testGetArguments()
+    {
+        $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date'));
+        $this->assertEquals(array('U'), $node->getArguments('date', array('format' => 'U')));
+    }
+
+    /**
+     * @expectedException        Twig_Error_Syntax
+     * @expectedExceptionMessage Positional arguments cannot be used after named arguments for function "date".
+     */
+    public function testGetArgumentsWhenPositionalArgumentsAfterNamedArguments()
+    {
+        $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date'));
+        $node->getArguments('date', array('timestamp' => 123456, 'Y-m-d'));
+    }
+
+    /**
+     * @expectedException        Twig_Error_Syntax
+     * @expectedExceptionMessage Arguments "format" is defined twice for function "date".
+     */
+    public function testGetArgumentsWhenArgumentIsDefinedTwice()
+    {
+        $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date'));
+        $node->getArguments('date', array('Y-m-d', 'format' => 'U'));
+    }
+}
+
+class Twig_Tests_Node_Expression_Call extends Twig_Node_Expression_Call
+{
+    public function getArguments($callable, $arguments)
+    {
+        return parent::getArguments($callable, $arguments);
+    }
+}