Skip to content

Commit

Permalink
Merge pull request #581 from legutierr/master
Browse files Browse the repository at this point in the history
Allows compiled templates to be imported, included and extended.
  • Loading branch information
carljm committed Nov 11, 2015
2 parents 37cdf72 + 8e9ee66 commit dd06683
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 12 deletions.
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

0 comments on commit dd06683

Please sign in to comment.