Permalink
Browse files

added support for named arguments for filters, tests, and functions

  • Loading branch information...
1 parent 65637b7 commit a59dcde3c2ae9293b449078b9a371f0450e045a9 @fabpot committed Nov 15, 2012
Showing with 557 additions and 26 deletions.
  1. +1 −0 CHANGELOG
  2. +6 −0 doc/filters/convert_encoding.rst
  3. +6 −0 doc/filters/date.rst
  4. +5 −0 doc/filters/date_modify.rst
  5. +5 −0 doc/filters/default.rst
  6. +6 −0 doc/filters/escape.rst
  7. +5 −0 doc/filters/join.rst
  8. +5 −0 doc/filters/json_encode.rst
  9. +7 −0 doc/filters/number_format.rst
  10. +5 −0 doc/filters/replace.rst
  11. +7 −0 doc/filters/slice.rst
  12. +6 −0 doc/filters/split.rst
  13. +5 −0 doc/filters/trim.rst
  14. +5 −0 doc/functions/cycle.rst
  15. +6 −0 doc/functions/date.rst
  16. +5 −0 doc/functions/dump.rst
  17. +5 −0 doc/functions/random.rst
  18. +7 −0 doc/functions/range.rst
  19. +5 −0 doc/functions/template_from_string.rst
  20. +50 −0 doc/templates.rst
  21. +32 −7 lib/Twig/ExpressionParser.php
  22. +6 −6 lib/Twig/Extension/Core.php
  23. +7 −1 lib/Twig/Filter.php
  24. +2 −0 lib/Twig/Filter/Function.php
  25. +2 −0 lib/Twig/Filter/Method.php
  26. +21 −0 lib/Twig/FilterCallableInterface.php
  27. +7 −1 lib/Twig/Function.php
  28. +2 −0 lib/Twig/Function/Function.php
  29. +2 −0 lib/Twig/Function/Method.php
  30. +21 −0 lib/Twig/FunctionCallableInterface.php
  31. +85 −2 lib/Twig/Node/Expression/Call.php
  32. +7 −1 lib/Twig/Node/Expression/Filter.php
  33. +7 −1 lib/Twig/Node/Expression/Function.php
  34. +8 −1 lib/Twig/Node/Expression/Test.php
  35. +34 −0 lib/Twig/Test.php
  36. +6 −2 lib/Twig/Test/Function.php
  37. +6 −2 lib/Twig/Test/Method.php
  38. +4 −2 lib/Twig/Test/Node.php
  39. +21 −0 lib/Twig/TestCallableInterface.php
  40. +22 −0 test/Twig/Tests/ExpressionParserTest.php
  41. +15 −0 test/Twig/Tests/Fixtures/filters/date_namedargs.test
  42. +6 −0 test/Twig/Tests/Fixtures/filters/reverse.test
  43. +11 −0 test/Twig/Tests/Fixtures/functions/date_namedargs.test
  44. +8 −0 test/Twig/Tests/Fixtures/functions/range.test
  45. +56 −0 test/Twig/Tests/Node/Expression/FilterTest.php
  46. +7 −0 test/Twig/Tests/Node/Expression/FunctionTest.php
View
@@ -1,5 +1,6 @@
* 1.12.0 (2012-XX-XX)
+ * added support for named arguments for filters, tests, and functions
* moved filters/functions/tests syntax errors to the parser
* added support for extended ternary operator syntaxes
@@ -18,5 +18,11 @@ is the input charset:
them must be installed. In case both are installed, `mbstring`_ is used by
default (Twig before 1.8.1 uses `iconv`_ by default).
+Arguments
+---------
+
+ * ``from``: The input charset
+ * ``to``: The output charset
+
.. _`iconv`: http://php.net/iconv
.. _`mbstring`: http://php.net/mbstring
View
@@ -77,6 +77,12 @@ The default timezone can also be set globally by calling ``setTimezone()``:
$twig = new Twig_Environment($loader);
$twig->getExtension('core')->setTimezone('Europe/Paris');
+Arguments
+---------
+
+ * ``format``: The date format
+ * ``timezone``: The date timezone
+
.. _`strtotime`: http://www.php.net/strtotime
.. _`DateTime`: http://www.php.net/DateTime
.. _`DateInterval`: http://www.php.net/DateInterval
@@ -14,5 +14,10 @@ The ``date_modify`` filter accepts strings (it must be in a format supported
by the `strtotime`_ function) or `DateTime`_ instances. You can easily combine
it with the :doc:`date<date>` filter for formatting.
+Arguments
+---------
+
+ * ``modifier``: The modifier
+
.. _`strtotime`: http://www.php.net/strtotime
.. _`DateTime`: http://www.php.net/DateTime
View
@@ -26,3 +26,8 @@ undefined:
Read the documentation for the :doc:`defined<../tests/defined>` and
:doc:`empty<../tests/empty>` tests to learn more about their semantics.
+
+Arguments
+---------
+
+ * ``default``: The default value
View
@@ -84,4 +84,10 @@ The ``escape`` filter supports the following escaping strategies:
{{ var|escape(strategy)|raw }} {# won't be double-escaped #}
{% endautoescape %}
+Arguments
+---------
+
+ * ``strategy``: The escaping strategy
+ * ``charset``: The string charset
+
.. _`htmlspecialchars`: http://php.net/htmlspecialchars
View
@@ -16,3 +16,8 @@ define it with the optional first parameter:
{{ [1, 2, 3]|join('|') }}
{# returns 1|2|3 #}
+
+Arguments
+---------
+
+ * ``glue``: The separator
@@ -11,4 +11,9 @@ The ``json_encode`` filter returns the JSON representation of a string:
Internally, Twig uses the PHP `json_encode`_ function.
+Arguments
+---------
+
+ * ``options``: The options
+
.. _`json_encode`: http://php.net/json_encode
@@ -35,4 +35,11 @@ These defaults can be easily changed through the core extension:
The defaults set for ``number_format`` can be over-ridden upon each call using the
additional parameters.
+Arguments
+---------
+
+ * ``decimal``: The number of decimal points to display
+ * ``decimal_point``: The character(s) to use for the decimal point
+ * ``decimal_sep``: The character(s) to use for the thousands separator
+
.. _`number_format`: http://php.net/number_format
View
@@ -11,4 +11,9 @@ The ``replace`` filter formats a given string by replacing the placeholders
{# returns I like foo and bar
if the foo parameter equals to the foo string. #}
+Arguments
+---------
+
+ * ``replace_pairs``: The placeholder values
+
.. seealso:: :doc:`format<format>`
View
@@ -52,6 +52,13 @@ up until the end of the variable.
It also works with objects implementing the `Traversable`_ interface.
+Arguments
+---------
+
+ * ``start``: The start of the slice
+ * ``length``: The size of the slice
+ * ``preserve_keys``: Whether to preserve key or not (when the input is an array)
+
.. _`Traversable`: http://php.net/manual/en/class.traversable.php
.. _`array_slice`: http://php.net/array_slice
.. _`substr`: http://php.net/substr
View
@@ -43,5 +43,11 @@ chunks. Length is set by the ``limit`` argument (one character by default).
Internally, Twig uses the PHP `explode`_ or `str_split`_ (if delimiter is
empty) functions for string splitting.
+Arguments
+---------
+
+ * ``delimiter``: The delimiter
+ * ``limit``: The limit argument
+
.. _`explode`: http://php.net/explode
.. _`str_split`: http://php.net/str_split
View
@@ -21,4 +21,9 @@ and end of a string:
Internally, Twig uses the PHP `trim`_ function.
+Arguments
+---------
+
+ * ``character_mask``: The characters to strip
+
.. _`trim`: http://php.net/trim
View
@@ -18,3 +18,8 @@ The array can contain any number of values:
{% for i in 0..10 %}
{{ cycle(fruits, i) }}
{% endfor %}
+
+Arguments
+---------
+
+ * ``position``: The cycle position
View
@@ -43,4 +43,10 @@ If no argument is passed, the function returns the current date:
$twig = new Twig_Environment($loader);
$twig->getExtension('core')->setTimezone('Europe/Paris');
+Arguments
+---------
+
+ * ``date``: The date
+ * ``timezone``: The timezone
+
.. _`date`: http://www.php.net/date
View
@@ -60,5 +60,10 @@ dumped:
Internally, Twig uses the PHP `var_dump`_ function.
+Arguments
+---------
+
+ * ``context``: The context to dump
+
.. _`XDebug`: http://xdebug.org/docs/display
.. _`var_dump`: http://php.net/var_dump
View
@@ -21,4 +21,9 @@ parameter type:
{{ random() }} {# example output: 15386094 (works as native PHP `mt_rand`_ function) #}
{{ random(5) }} {# example output: 3 #}
+Arguments
+---------
+
+ * ``values``: The values
+
.. _`mt_rand`: http://php.net/mt_rand
View
@@ -35,4 +35,11 @@ function (with a step of 1):
The ``range`` function works as the native PHP `range`_ function.
+Arguments
+---------
+
+ * ``low``: The first value of the sequence.
+ * ``high``: The highest possible value of the sequence.
+ * ``step``: The increment between elements of the sequence.
+
.. _`range`: http://php.net/range
@@ -25,3 +25,8 @@ The ``template_from_string`` function loads a template from a string:
Even if you will probably always use the ``template_from_string`` function
with the ``include`` tag, you can use it with any tag or function that
takes a template as an argument (like the ``embed`` or ``extends`` tags).
+
+Arguments
+---------
+
+ * ``template``: The template
View
@@ -190,6 +190,56 @@ progression of integers:
Go to the :doc:`functions<functions/index>` page to learn more about the
built-in functions.
+Named Arguments
+---------------
+
+.. versionadded:: 1.12
+ Support for named arguments was added in Twig 1.12.
+
+Arguments for filters and functions can also be passed as *named arguments*:
+
+.. code-block:: jinja
+
+ {% for i in range(low=1, high=10, step=2) %}
+ {{ i }},
+ {% endfor %}
+
+Using named arguments makes your templates more explicit about the meaning of
+the values you pass as arguments:
+
+.. code-block:: jinja
+
+ {{ data|convert_encoding('UTF-8', 'iso-2022-jp') }}
+
+ {# versus #}
+
+ {{ data|convert_encoding(from='iso-2022-jp', to='UTF-8') }}
+
+Named arguments also allow you to skip some arguments for which you don't want
+to change the default value::
+
+.. code-block:: jinja
+
+ {# the first argument is the date format, which defaults to the global date format if null is passed #}
+ {{ "now"|date(null, "Europe/Paris") }}
+
+ {# 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:
+
+.. 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::
+
+ Each function and filter documentation page has a section where the names
+ of all arguments are listed when supported.
+
Control Structure
-----------------
@@ -297,9 +297,9 @@ public function parsePostfixExpression($node)
public function getFunctionNode($name, $line)
{
- $args = $this->parseArguments();
switch ($name) {
case 'parent':
+ $args = $this->parseArguments();
if (!count($this->parser->getBlockStack())) {
throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename());
}
@@ -310,8 +310,9 @@ public function getFunctionNode($name, $line)
return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
case 'block':
- return new Twig_Node_Expression_BlockReference($args->getNode(0), false, $line);
+ return new Twig_Node_Expression_BlockReference($this->parseArguments()->getNode(0), false, $line);
case 'attribute':
+ $args = $this->parseArguments();
if (count($args) < 2) {
throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename());
}
@@ -320,7 +321,7 @@ public function getFunctionNode($name, $line)
default:
if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
$arguments = new Twig_Node_Expression_Array(array(), $line);
- foreach ($args as $n) {
+ foreach ($this->parseArguments() as $n) {
$arguments->addElement($n);
}
@@ -330,6 +331,7 @@ public function getFunctionNode($name, $line)
return $node;
}
+ $args = $this->parseArguments(true);
$class = $this->getFunctionNodeClass($name, $line);
return new $class($name, $args, $line);
@@ -416,7 +418,7 @@ public function parseFilterExpressionRaw($node, $tag = null)
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$arguments = new Twig_Node();
} else {
- $arguments = $this->parseArguments();
+ $arguments = $this->parseArguments(true);
}
$class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
@@ -433,17 +435,40 @@ public function parseFilterExpressionRaw($node, $tag = null)
return $node;
}
- public function parseArguments()
+ /**
+ * Parses arguments.
+ *
+ * @param Boolean $namedArguments Whether to allow named arguments or not
+ * @param Boolean $definition Whether we are parsing arguments for a function definition
+ */
+ public function parseArguments($namedArguments = false, $definition = false)
{
$args = array();
$stream = $this->parser->getStream();
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must be opened by a parenthesis');
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) {
if (!empty($args)) {
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
}
- $args[] = $this->parseExpression();
+
+ $value = $this->parseExpression();
+
+ $name = null;
+ if ($namedArguments && $stream->test(Twig_Token::OPERATOR_TYPE, '=')) {
+ $token = $stream->next();
+ if (!$value instanceof Twig_Node_Expression_Name) {
+ throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given', get_class($value)), $token->getLine());
+ }
+ $name = $value->getAttribute('name');
+ $value = $definition ? $this->parsePrimaryExpression() : $this->parseExpression();
+ }
+
+ if (null === $name) {
+ $args[] = $value;
+ } else {
+ $args[$name] = $value;
+ }
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
@@ -267,7 +267,7 @@ public function parseTestExpression(Twig_Parser $parser, $node)
$name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
$arguments = null;
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
- $arguments = $parser->getExpressionParser()->parseArguments();
+ $arguments = $parser->getExpressionParser()->parseArguments(true);
}
$class = $this->getTestNodeClass($parser, $name, $node->getLine());
@@ -305,18 +305,18 @@ public function getName()
/**
* Cycles over a value.
*
- * @param ArrayAccess|array $values An array or an ArrayAccess instance
- * @param integer $i The cycle value
+ * @param ArrayAccess|array $values An array or an ArrayAccess instance
+ * @param integer $position The cycle position
*
* @return string The next value in the cycle
*/
-function twig_cycle($values, $i)
+function twig_cycle($values, $position)
{
if (!is_array($values) && !$values instanceof ArrayAccess) {
return $values;
}
- return $values[$i % count($values)];
+ return $values[$position % count($values)];
}
/**
@@ -410,7 +410,7 @@ function twig_date_format_filter(Twig_Environment $env, $date, $format = null, $
* Returns a new date object modified
*
* <pre>
- * {{ post.published_at|modify("-1day")|date("m/d/Y") }}
+ * {{ post.published_at|date_modify("-1day")|date("m/d/Y") }}
* </pre>
*
* @param Twig_Environment $env A Twig_Environment instance
Oops, something went wrong.

0 comments on commit a59dcde

Please sign in to comment.