From 9d77cf2254a5bc8b51fb11f60e80cb0ae5a81439 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 19 Dec 2010 11:26:38 +0100 Subject: [PATCH] added from tag --- CHANGELOG | 1 + doc/templates.rst | 43 +++++++++++++----- lib/Twig/Extension/Core.php | 1 + lib/Twig/Node/From.php | 48 ++++++++++++++++++++ lib/Twig/TokenParser/From.php | 60 +++++++++++++++++++++++++ test/Twig/Tests/Fixtures/tags/macro/from.test | 18 +++++++ 6 files changed, 159 insertions(+), 12 deletions(-) create mode 100644 lib/Twig/Node/From.php create mode 100644 lib/Twig/TokenParser/From.php create mode 100644 test/Twig/Tests/Fixtures/tags/macro/from.test diff --git a/CHANGELOG b/CHANGELOG index baf47ee..945352d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,7 @@ Backward incompatibilities: Changes: + * added the "from" tag to import macros as functions * added support for functions (a function is just syntactic sugar for a getAttribute() call) * made macros callable when sandbox mode is enabled * added an exception when a macro uses a reserved name diff --git a/doc/templates.rst b/doc/templates.rst index 33e0844..633a2d4 100644 --- a/doc/templates.rst +++ b/doc/templates.rst @@ -647,7 +647,7 @@ Here is a small example of a macro that renders a form element: .. code-block:: jinja {% macro input(name, value, type, size) %} - + {% endmacro %} 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 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``): .. code-block:: jinja {% macro input(name, value, type, size) %} - + {% endmacro %} {% macro textarea(name, value, rows) %} - + {% 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 {% import 'forms.html' as forms %}
-
Username
-
{{ forms.input('username') }}
-
Password
-
{{ forms.input('password', none, 'password') }}
+
Username
+
{{ forms.input('username') }}
+
Password
+
{{ forms.input('password', none, 'password') }}

{{ forms.textarea('comment') }}

-Importing is not needed if the macros and the template are defined in the file; -use the special ``_self`` variable instead: +Alternatively you can import names from the template into the current +namespace: + +.. code-block:: jinja + + {% from 'forms.html' import input as input_field, textarea %} + +
+
Username
+
{{ input_field('username') }}
+
Password
+
{{ input_field('password', type='password') }}
+
+

{{ textarea('comment') }}

+ +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 {# index.html template #} {% macro textarea(name, value, rows) %} - + {% endmacro %}

{{ _self.textarea('comment') }}

@@ -904,7 +923,7 @@ But you can still create an alias by importing from the ``_self`` variable: {# index.html template #} {% macro textarea(name, value, rows) %} - + {% endmacro %} {% import _self as forms %} diff --git a/lib/Twig/Extension/Core.php b/lib/Twig/Extension/Core.php index f647163..74517b5 100644 --- a/lib/Twig/Extension/Core.php +++ b/lib/Twig/Extension/Core.php @@ -28,6 +28,7 @@ class Twig_Extension_Core extends Twig_Extension new Twig_TokenParser_Filter(), new Twig_TokenParser_Macro(), new Twig_TokenParser_Import(), + new Twig_TokenParser_From(), new Twig_TokenParser_Set(), new Twig_TokenParser_Spaceless(), ); diff --git a/lib/Twig/Node/From.php b/lib/Twig/Node/From.php new file mode 100644 index 0000000..a71a7e2 --- /dev/null +++ b/lib/Twig/Node/From.php @@ -0,0 +1,48 @@ + + */ +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") + ; + } + } +} diff --git a/lib/Twig/TokenParser/From.php b/lib/Twig/TokenParser/From.php new file mode 100644 index 0000000..9398f1d --- /dev/null +++ b/lib/Twig/TokenParser/From.php @@ -0,0 +1,60 @@ +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'; + } +} diff --git a/test/Twig/Tests/Fixtures/tags/macro/from.test b/test/Twig/Tests/Fixtures/tags/macro/from.test new file mode 100644 index 0000000..205f591 --- /dev/null +++ b/test/Twig/Tests/Fixtures/tags/macro/from.test @@ -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 -- 1.7.2.5