added from tag

This commit is contained in:
Fabien Potencier
2010-12-19 11:26:38 +01:00
parent 1621435b89
commit 9d77cf2254
6 changed files with 159 additions and 12 deletions
+1
View File
@@ -6,6 +6,7 @@ Backward incompatibilities:
Changes: Changes:
* added the "from" tag to import macros as functions
* added support for functions (a function is just syntactic sugar for a getAttribute() call) * added support for functions (a function is just syntactic sugar for a getAttribute() call)
* made macros callable when sandbox mode is enabled * made macros callable when sandbox mode is enabled
* added an exception when a macro uses a reserved name * added an exception when a macro uses a reserved name
+31 -12
View File
@@ -647,7 +647,7 @@ Here is a small example of a macro that renders a form element:
.. code-block:: jinja .. code-block:: jinja
{% macro input(name, value, type, size) %} {% macro input(name, value, type, size) %}
<input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" /> <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
{% endmacro %} {% endmacro %}
Macros differs from native PHP functions in a few ways: Macros differs from native PHP functions in a few ways:
@@ -858,41 +858,60 @@ Import
Twig supports putting often used code into macros. These macros can go into Twig supports putting often used code into macros. These macros can go into
different templates and get imported from there. different templates and get imported from there.
There are two ways to import templates. You can import the complete template
into a variable or request specific macros from it.
Imagine we have a helper module that renders forms (called ``forms.html``): Imagine we have a helper module that renders forms (called ``forms.html``):
.. code-block:: jinja .. code-block:: jinja
{% macro input(name, value, type, size) %} {% macro input(name, value, type, size) %}
<input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" /> <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
{% endmacro %} {% endmacro %}
{% macro textarea(name, value, rows) %} {% macro textarea(name, value, rows) %}
<textarea name="{{ name }}" rows="{{ rows|default(10) }}" cols="{{ cols|default(40) }}">{{ value|e }}</textarea> <textarea name="{{ name }}" rows="{{ rows|default(10) }}" cols="{{ cols|default(40) }}">{{ value|e }}</textarea>
{% endmacro %} {% endmacro %}
Importing these macros in a template is as easy as using the ``import`` tag: The easiest and most flexible is importing the whole module into a variable.
That way you can access the attributes:
.. code-block:: jinja .. code-block:: jinja
{% import 'forms.html' as forms %} {% import 'forms.html' as forms %}
<dl> <dl>
<dt>Username</dt> <dt>Username</dt>
<dd>{{ forms.input('username') }}</dd> <dd>{{ forms.input('username') }}</dd>
<dt>Password</dt> <dt>Password</dt>
<dd>{{ forms.input('password', none, 'password') }}</dd> <dd>{{ forms.input('password', none, 'password') }}</dd>
</dl> </dl>
<p>{{ forms.textarea('comment') }}</p> <p>{{ forms.textarea('comment') }}</p>
Importing is not needed if the macros and the template are defined in the file; Alternatively you can import names from the template into the current
use the special ``_self`` variable instead: namespace:
.. code-block:: jinja
{% from 'forms.html' import input as input_field, textarea %}
<dl>
<dt>Username</dt>
<dd>{{ input_field('username') }}</dd>
<dt>Password</dt>
<dd>{{ input_field('password', type='password') }}</dd>
</dl>
<p>{{ textarea('comment') }}</p>
Importing is not needed if the macros and the template are defined in the same
file; use the special ``_self`` variable instead:
.. code-block:: jinja .. code-block:: jinja
{# index.html template #} {# index.html template #}
{% macro textarea(name, value, rows) %} {% macro textarea(name, value, rows) %}
<textarea name="{{ name }}" rows="{{ rows|default(10) }}" cols="{{ cols|default(40) }}">{{ value|e }}</textarea> <textarea name="{{ name }}" rows="{{ rows|default(10) }}" cols="{{ cols|default(40) }}">{{ value|e }}</textarea>
{% endmacro %} {% endmacro %}
<p>{{ _self.textarea('comment') }}</p> <p>{{ _self.textarea('comment') }}</p>
@@ -904,7 +923,7 @@ But you can still create an alias by importing from the ``_self`` variable:
{# index.html template #} {# index.html template #}
{% macro textarea(name, value, rows) %} {% macro textarea(name, value, rows) %}
<textarea name="{{ name }}" rows="{{ rows|default(10) }}" cols="{{ cols|default(40) }}">{{ value|e }}</textarea> <textarea name="{{ name }}" rows="{{ rows|default(10) }}" cols="{{ cols|default(40) }}">{{ value|e }}</textarea>
{% endmacro %} {% endmacro %}
{% import _self as forms %} {% import _self as forms %}
+1
View File
@@ -28,6 +28,7 @@ class Twig_Extension_Core extends Twig_Extension
new Twig_TokenParser_Filter(), new Twig_TokenParser_Filter(),
new Twig_TokenParser_Macro(), new Twig_TokenParser_Macro(),
new Twig_TokenParser_Import(), new Twig_TokenParser_Import(),
new Twig_TokenParser_From(),
new Twig_TokenParser_Set(), new Twig_TokenParser_Set(),
new Twig_TokenParser_Spaceless(), new Twig_TokenParser_Spaceless(),
); );
+48
View File
@@ -0,0 +1,48 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2010 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a from node.
*
* @package twig
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
*/
class Twig_Node_From extends Twig_Node_Import
{
public function __construct(Twig_Node_Expression $expr, array $imports, $lineno, $tag = null)
{
parent::__construct($expr, new Twig_Node_Expression_AssignName('_imported_'.rand(10000, 99999), $lineno), $lineno, $tag);
$this->setAttribute('imports', $imports);
}
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile($compiler)
{
parent::compile($compiler);
foreach ($this->getAttribute('imports') as $name => $alias) {
$compiler
->write('$context[')
->repr($alias)
->raw('] = new Twig_Function(')
->subcompile($this->getNode('var'))
->raw(', ')
->repr($name)
->raw(");\n")
;
}
}
}
+60
View File
@@ -0,0 +1,60 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2010 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_TokenParser_From extends Twig_TokenParser
{
/**
* Parses a token and returns a node.
*
* @param Twig_Token $token A Twig_Token instance
*
* @return Twig_NodeInterface A Twig_NodeInterface instance
*/
public function parse(Twig_Token $token)
{
$macro = $this->parser->getExpressionParser()->parseExpression();
$stream = $this->parser->getStream();
$stream->expect('import');
$targets = array();
do {
$name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
$alias = $name;
if ($stream->test('as')) {
$stream->next();
$alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
}
$targets[$name] = $alias;
if (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ',')) {
break;
}
$stream->next();
} while (true);
$stream->expect(Twig_Token::BLOCK_END_TYPE);
return new Twig_Node_From($macro, $targets, $token->getLine(), $this->getTag());
}
/**
* Gets the tag name associated with this token parser.
*
* @param string The tag name
*/
public function getTag()
{
return 'from';
}
}
@@ -0,0 +1,18 @@
--TEST--
"macro" tag
--TEMPLATE--
{% from 'forms.twig' import foo %}
{% from 'forms.twig' import foo as foobar, bar %}
{{ foo('foo') }}
{{ foobar('foo') }}
{{ bar('foo') }}
--TEMPLATE(forms.twig)--
{% macro foo(name) %}foo{{ name }}{% endmacro %}
{% macro bar(name) %}bar{{ name }}{% endmacro %}
--DATA--
return array()
--EXPECT--
foofoo
foofoo
barfoo