Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allows compiled templates to be imported, included and extended. #581

Merged
merged 2 commits into from
Nov 11, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Changelog
master (unreleased)
-------------------

* Allows compiled templates to be imported, included and extended. Thanks
Luis Gutierrez-Sheris. Merge of [#581](https://github.com/mozilla/nunjucks/pull/581).
* Fix issue with different nunjucks environments sharing same globals. Each
environment is now independent. Thanks Paul Pechin. Merge of
[#574](https://github.com/mozilla/nunjucks/pull/574).
Expand Down
21 changes: 15 additions & 6 deletions docs/templating.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,10 @@ This is the default content
```

You can store the template to inherit in a variable and use it by
omitting quotes. That way you can dynamically change which template is
inherited when rendering by setting it in the context.
omitting quotes. This variable can contain a string that points to a
template file, or it can contain a compiled Template object that has
been added to the context. That way you can dynamically change which
template is inherited when rendering by setting it in the context.

```jinja
{% extends parentTemplate %}
Expand Down Expand Up @@ -357,15 +359,22 @@ Inheritance](#template-inheritance).
```

You can store the template to inherit in a variable and use it by
omitting quotes. That way you can dynamically change which template is
omitting quotes. This variable can contain a string that points to a
template file, or it can contain a compiled Template object that has
been added to the context. That way you can dynamically change which template is
inherited when rendering by setting it in the context.

```jinja
{% extends parentTemplate %}
```

In fact, `extends` accepts any arbitrary expression, so you can pass
anything into it: `{% extends name + ".html" %}`.
anything into it, as long as that expression evaluates to a string or
a compiled Template object:

```jinja
{% extends name + ".html" %}`.
```

### block

Expand Down Expand Up @@ -419,7 +428,7 @@ You can even include templates in the middle of loops:

This is especially useful for cutting up templates into pieces so that the browser-side environment can render the small chunks when it needs to change the page.

`include` actually accepts any arbitrary expression, so you can pass anything into it: `{% include name + ".html" %}`.
`include` actually accepts any arbitrary expression, so you can pass anything into it, as long as the expression evaluates to a string or a compiled Template object: `{% include name + ".html" %}`.

It might be useful to not throw an error if a template does not exist. Use the `ignore missing` option to suppress such errors.

Expand Down Expand Up @@ -472,7 +481,7 @@ You can also import specific values from a template into the current namespace w
{{ field('pass', type='password') }}
```

`import` actually accepts any arbitrary expression, so you can pass anything into it: `{% import name + ".html" as obj %}`.
`import` actually accepts any arbitrary expression, so you can pass anything into it, as long as the expression evaluates to a string or a compiled Template object: `{% import name + ".html" as obj %}`.

### raw

Expand Down
16 changes: 10 additions & 6 deletions src/environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,14 +171,18 @@ var Environment = Obj.extend({
eagerCompile = false;
}

if(typeof name !== 'string') {
if (name instanceof Template) {
tmpl = name;
}
else if(typeof name !== 'string') {
throw new Error('template names must be a string: ' + name);
}

for (var i = 0; i < this.loaders.length; i++) {
var _name = this.resolveTemplate(this.loaders[i], parentName, name);
tmpl = this.loaders[i].cache[_name];
if (tmpl) break;
else {
for (var i = 0; i < this.loaders.length; i++) {
var _name = this.resolveTemplate(this.loaders[i], parentName, name);
tmpl = this.loaders[i].cache[_name];
if (tmpl) break;
}
}

if(tmpl) {
Expand Down
44 changes: 44 additions & 0 deletions tests/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,23 @@
finish(done);
});

it('should import template objects', function(done) {
var tmpl = new Template('{% macro foo() %}Inside a macro{% endmacro %}' +
'{% set bar = "BAZ" %}');

equal('{% import tmpl as imp %}' +
'{{ imp.foo() }} {{ imp.bar }}',
{ tmpl : tmpl },
'Inside a macro BAZ');

equal('{% from tmpl import foo as baz, bar %}' +
'{{ bar }} {{ baz() }}',
{ tmpl : tmpl },
'BAZ Inside a macro');

finish(done);
});

it('should import templates with context', function(done) {
equal('{% set bar = "BAR" %}' +
'{% import "import-context.html" as imp with context %}' +
Expand Down Expand Up @@ -629,6 +646,23 @@
finish(done);
});

it('should inherit template objects', function(done) {
var tmpl = new Template('Foo{% block block1 %}Bar{% endblock %}' +
'{% block block2 %}Baz{% endblock %}Whizzle');

equal('hola {% extends tmpl %} fizzle mumble',
{ tmpl: tmpl },
'FooBarBazWhizzle');

equal('{% extends tmpl %}' +
'{% block block1 %}BAR{% endblock %}' +
'{% block block2 %}BAZ{% endblock %}',
{ tmpl: tmpl },
'FooBARBAZWhizzle');

finish(done);
});

it('should conditionally inherit templates', function(done) {
equal('{% if false %}{% extends "base.html" %}{% endif %}' +
'{% block block1 %}BAR{% endblock %}',
Expand Down Expand Up @@ -697,6 +731,16 @@
finish(done);
});

it('should include template objects', function(done) {
var tmpl = new Template('FooInclude {{ name }}');

equal('hello world {% include tmpl %}',
{ name: 'thedude', tmpl: tmpl },
'hello world FooInclude thedude');

finish(done);
});

it('should throw an error when including a file that does not exist', function(done) {
render(
'{% include "missing.html" %}',
Expand Down