Skip to content
高新成 edited this page Jan 17, 2019 · 6 revisions

Introduce

hunt framework view module is runtime render template engine, easy to use, like twig / jinja2.

How to use

render string

example:

my-template.html:

<div>Hello, {{ name }}!</div>

Dlang code:

@Action
string test()
{
    view.assign("name", "Brian");

    return view.render("my-template");
}

result:

<div>Hello, Brian!</div>

Syntax

Default delimiters:
  • Statements {% ... %}
  • Expressions {{ ... }}
  • Comments {# ... #}
  • Line statements #, comments ##
Variables:
  • Variable itself: foo
  • Variable's field: foo.bar or foo['bar']
  • Variables array: foos[2]
Expressions:
  • Integer number: 42
  • Floating number 42.2
  • String: "Some string", 'Another string'
  • Boolean: true/false, True/False
  • Array: [1, 'string', false]
  • List: (1, 'string', false) note: internal list representation still is array
  • Dictionary: {'a': 10, 'b': true} or {a: 10, b: true} note: keys in dictionary can only be strings
  • Math Operators: **, *, /, //, %, +, -
  • Logic operators: ( ... ), not, and, or
  • Comparison operators: ==, !=, >=, <=, >, <
  • Other operators: in, is, |, ~, ...(...)
  • Ternary if: ... if ... else ...
Statements:
  • If: if/elif/else/endif
  • For: for/else/endfor
  • Macros: macro/endmacro
  • Call: call/endcall
  • Set: set
  • Filter: filter
  • Extending: extends, block/endblock
  • Import: import
  • Include: include
  • With: with/endwith note: without assignment
Whitespace control:

Space control with - operator allowed only for statements: {%- ... -%}

Functions:

Most of global functions / tests / filters are not implemented at the moment. Must be done later.

  • Implemented functions: range, length/count, namespace
  • Implemented test: defined, undefined, number, list, dict
  • Implemented filters: default/d, escape/e, upper, sort, keys

2. Main differences

Assignment scope behavior:

Unlike original Jinja it is possible to set variables inside a block and have them show up outside of it. This means that the following example will work as expected.

{% set iterated = false %}
{% for item in seq %} ## non-empty sequence
    {{ item }}
    {% set iterated = true %}
{% endfor %}
{% if not iterated %} did not iterate {% endif %} ## will not be printed (iterated == true)

3. Additional features

1. Set variable fields / array members

It is possible to set variable field and member of array:

{% set foo = {} %}
{% set foo.bar = 10 %}
{{ foo.bar }} ## 10
{% set foos = [1, 2, 3] %}
{% set foos[2] = 30 %}
{{ foos }} ## [1, 2, 30]
2. UFCS

It is possible to use Uniform Function Call Syntax for variables like in D:

{% set foo = [1, 1, 1, 1, 1] %}
{{ range(length(foo)) }} ## [0, 1, 2, 3, 4]
{{ foo.length.range }}   ## [0, 1, 2, 3, 4]
3. Macro return expression

You can return value from user defined macros due to return keyword in endmacro statement:

{% macro sum(numbers) %}
    {% sum = 0 %}
    {% for num in numbers %}
        {% sum = sum + num %}
    {% endfor %}
{% endmacro return sum %}

{{ sum([1, 2, 3, 4]) * 10 }} ## 100
4. Macro as function / test / filter

Since macros can return value, you can use them as functions / filters / tests:

{% macro sum(numbers) %}
    {% sum = 0 %}
    {% for num in numbers %}
        {% sum = sum + num %}
    {% endfor %}
{% endmacro return sum %}

{{ [0, 1, 2, 4] | sum | e }} ## 7
{% macro large(l) %}
{% endmacro return l is list and l.length > 10 %}

{{ 'yes' if [0, 1, 2] is large else 'no' }} ## no
5. Macro as closure

It is possible to define macro inside another macro and inner macro has link to external contexts.

{% set a = 1 %}
{% macro m1 %}  ## variables `a`, `b` are available inside 
    {% set b = 2 %}
    {% macro m2 %}  ## variables `a`, `b`, `c` are available inside
    	{% set c = 3 %}
    {% endmcaro %}
{% endmcaro %}
{% set counter = 0 -%}

{%- macro inc() -%}
    {% set counter = counter + 1 %}
{%- endmacro return counter -%}

{{ inc() }} ## 1
{{ inc() }} ## 2
{{ inc() }} ## 3
{{ inc() }} ## 4
6. For

Loop over each item in a sequence. For example, to display a list of users provided in a variable called users:

<h1>Members</h1>
<ul>
{% for user in users %}
  <li>{{ user.username|e }}</li>
{% endfor %}
</ul>

As variables in templates retain their object properties, it is possible to iterate over containers like dict:

<dl>
{% for key, value in my_dict.iteritems() %}
    <dt>{{ key|e }}</dt>
    <dd>{{ value|e }}</dd>
{% endfor %}
</dl>

Inside of a for-loop block, you can access some special variables: | Variable | Description | | ------ | ------ | ------ | | loop.index | The current iteration of the loop. (1 indexed) | | loop.index0 | The current iteration of the loop. (0 indexed) | | loop.revindex|The number of iterations from the end of the loop (1 indexed)| |loop.revindex0|The number of iterations from the end of the loop (0 indexed)| |loop.first|True if first iteration.| |loop.last|True if last iteration.| |loop.length|The number of items in the sequence.| |loop.depth |Indicates how deep in a recursive loop the rendering currently is. Starts at level 1| |loop.depth0 | Indicates how deep in a recursive loop the rendering currently is. Starts at level 0| |loop.previtem| The item from the previous iteration of the loop. Undefined during the first iteration.| |loop.nextitem | The item from the following iteration of the loop. Undefined during the last iteration.|

Clone this wiki locally