added a slice filter

This commit is contained in:
Fabien Potencier
2012-01-14 08:48:59 +01:00
parent a4e1151d43
commit d9dc813dfd
5 changed files with 132 additions and 4 deletions
+2
View File
@@ -1,5 +1,7 @@
* 1.6.0-DEV
* added slice notation support for the [] operator (syntactic sugar for the slice operator)
* added a slice filter
* added string support for the reverse filter
* fixed the empty test and the length filter for Twig_Markup instances
* added a date function to ease date comparison
+57
View File
@@ -0,0 +1,57 @@
``slice``
===========
.. versionadded:: 1.6
The slice filter was added in Twig 1.6.
The ``slice`` filter extracts a slice of a sequence, a mapping, or a string:
.. code-block:: jinja
{% for i in [1, 2, 3, 4]|slice(1, 2) %}
{# will iterate over 2 and 3 #}
{% endfor %}
{{ '1234'|slice(1, 2) }}
{# outputs 23 #}
You can use any valid expression for both the start and the length:
.. code-block:: jinja
{% for i in [1, 2, 3, 4]|slice(start, length) %}
{# ... #}
{% endfor %}
As syntactic sugar, you can also use the ``[]`` notation:
.. code-block:: jinja
{% for i in [1, 2, 3, 4][start:length] %}
{# ... #}
{% endfor %}
{{ '1234'[1:2] }}
The ``slice`` filter works as the `array_slice`_ PHP function for arrays and
`substr`_ for strings.
If the start is non-negative, the sequence will start at that start in the
variable. If start is negative, the sequence will start that far from the end
of the variable.
If length is given and is positive, then the sequence will have up to that
many elements in it. If the variable is shorter than the length, then only the
available variable elements will be present. If length is given and is
negative then the sequence will stop that many elements from the end of the
variable. If it is omitted, then the sequence will have everything from offset
up until the end of the variable.
.. note::
It also works with objects implementing the `Traversable`_ interface.
.. _`Traversable`: http://php.net/manual/en/class.traversable.php
.. _`array_slice`: http://php.net/array_slice
.. _`substr`: http://php.net/substr
+19 -4
View File
@@ -320,12 +320,13 @@ class Twig_ExpressionParser
public function parseSubscriptExpression($node)
{
$token = $this->parser->getStream()->next();
$stream = $this->parser->getStream();
$token = $stream->next();
$lineno = $token->getLine();
$arguments = new Twig_Node();
$type = Twig_TemplateInterface::ANY_CALL;
if ($token->getValue() == '.') {
$token = $this->parser->getStream()->next();
$token = $stream->next();
if (
$token->getType() == Twig_Token::NAME_TYPE
||
@@ -335,7 +336,7 @@ class Twig_ExpressionParser
) {
$arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
if ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$type = Twig_TemplateInterface::METHOD_CALL;
$arguments = $this->parseArguments();
} else {
@@ -348,7 +349,21 @@ class Twig_ExpressionParser
$type = Twig_TemplateInterface::ARRAY_CALL;
$arg = $this->parseExpression();
$this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ']');
// slice?
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
$stream->next();
$class = $this->getFilterNodeClass('slice');
$arguments = new Twig_Node(array($arg, $this->parseExpression()));
$filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine());
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
return $filter;
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
}
return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno);
+30
View File
@@ -126,6 +126,7 @@ class Twig_Extension_Core extends Twig_Extension
// string/array filters
'reverse' => new Twig_Filter_Function('twig_reverse_filter', array('needs_environment' => true)),
'length' => new Twig_Filter_Function('twig_length_filter', array('needs_environment' => true)),
'slice' => new Twig_Filter_Function('twig_slice', array('needs_environment' => true)),
// iteration and runtime
'default' => new Twig_Filter_Node('Twig_Node_Expression_Filter_Default'),
@@ -494,6 +495,35 @@ function twig_array_merge($arr1, $arr2)
return array_merge($arr1, $arr2);
}
/**
* Slices a variable.
*
* @param Twig_Environment $env A Twig_Environment instance
* @param mixed $item A variable
* @param integer $start Start of the slice
* @param integer $length Size of the slice
*
* @return mixed The sliced variable
*/
function twig_slice(Twig_Environment $env, $item, $start, $length = null)
{
if ($item instanceof Traversable) {
$item = iterator_to_array($item, false);
}
if (is_array($item)) {
return array_slice($item, $start, $length);
}
$item = (string) $item;
if (function_exists('mb_get_info') && null !== $charset = $env->getCharset()) {
return mb_substr($item, $start, $length, $charset);
}
return substr($item, $start, $length);
}
/**
* Joins the values to a string.
*
@@ -0,0 +1,24 @@
--TEST--
"slice" filter
--TEMPLATE--
{{ [1, 2, 3, 4][1:2]|join('')}}
{{ {a: 1, b: 2, c: 3, d: 4}[1:2]|join('') }}
{{ [1, 2, 3, 4][start:length]|join('') }}
{{ [1, 2, 3, 4]|slice(1, 2)|join('') }}
{{ {a: 1, b: 2, c: 3, d: 4}|slice(1, 2)|join('') }}
{{ '1234'|slice(1, 2) }}
{{ '1234'[1:2] }}
{{ arr|slice(1, 2)|join('') }}
{{ arr[1:2]|join('') }}
--DATA--
return array('start' => 1, 'length' => 2, 'arr' => new ArrayObject(array(1, 2, 3, 4)))
--EXPECT--
23
23
23
23
23
23
23
23
23