Best practices
Best practices for OneFuse templating
5 minute read
A template contains variables and/or Expressions, which get replaced with values when a template is rendered; and tags, which control the logic of the template.
{% ... %} for Control structures.
{{ ... }} for variables and/or expressions to print to the template output.
{# ... #} for comments not included in the template output.
Template variables are defined by the context properties passed to the template.
You can use a dot (.) to access attributes of a variable in addition to the syntax ([]).
The following two lines result in the same outcome:
{{ foo.bar }}
{{ foo["bar"] }}
The outer double-curly braces are not part of the variable, but the print statement. The outer double curly-braces are not necessary when you access variables inside tags.
If a variable or attribute does not exist, an undefined value will get returned and will evaluate to an empty string if printed by default.
Modify variables with Filters.
Filters are separated from the variable by a pipe symbol (|) and may have optional arguments in parentheses.
Multiple filters can be chained and the output of one filter is applied to the next.
Example:
{#
The example below uses the filter "first" to get the first letter of the variable.
Then, a second filter is applied "lower" to lowercase variable.
#}
{% set OS = "Linux" %}
{{ OS | first | lower }}
=> l
Tests are used to test a variable against a common expression. To test a variable or expression, add the is operator with the test after the variable.
Example:
{% if OS is defined %}
{% if Environment == "prod" %}
{# Naming Policy Name for prod #}
production
{% elif Environment == "dev" %}
{# Naming Policy Name for dev #}
development
{% elif Environment == "qa" %}
{# Naming Policy Name for qa #}
qa
{% else %}
{# Naming Policy Name default #}
global
{% endif %}
{% endif %}
Will return true or false depending on whether the OS variable is defined in the current properties input.
Use the comment syntax {# ... #} tag to comment-out a part of a line in a template.
Example:
{# My Comment #}
The Template Engine will start to handle delimiter starters unless you escape the characters or blocks, which may be necessary to ignore.
The easiest way to output a literal variable delimiter ({{) is by using a variable expression:
{{ '{{' }}
{# For bigger blocks of text, we recommend you to use raw tags #}
{% raw %}
my
block
of
text
{% endraw %}
Refer to Control structures: if.
Macros are comparable with functions in regular programming languages. They are useful to put often used idioms into reusable functions to not repeat yourself.
Below is a small example of a macro that renders the first lowercased letter from the variable:
{% macro firstLowercase(value='') -%}
{{ value | first | lower }}
{%- endmacro %}
If a macro name starts with an underscore (_), it is not exported and it cannot be imported.
The macro can then be called like a function in the namespace:
{% set OS = "Linux" %}
{% set Environment = "production" %}
{% set Application = "Web Servers" %}
{{ firstLowercase(OS) }}{{ firstLowercase(Environment) }}{{ firstLowercase(Application) }}
{# The above is equivalent to
{{ OS | first | lower }}{{ Environment | first | lower }}{{ Application | first | lower }}
#}
=> lpw
Inside macros, you have access to three special variables:
| Variable | Description |
|---|---|
varargs |
If more positional arguments are passed to the macro than accepted by the macro, they end up in the special varargs variable as a list of values. |
kwargs |
Like varargs but for keyword arguments. All unconsumed keyword arguments are stored in this special variable. |
caller |
If the macro was called from a call tag, the caller is stored in this variable as a callable macro. |
Macros also expose some of their internal details. The following attributes are available on a macro object:
| Attribute | Description |
|---|---|
name |
The name of the macro. {{ input.name }} will print input. |
arguments |
A tuple of the names of arguments the macro accepts. |
defaults |
A tuple of default values. |
catch_kwargs |
This is true if the macro accepts extra keyword arguments (i.e.: accesses the special kwargs variable). |
catch_varargs |
This is true if the macro accepts extra positional arguments (i.e.: accesses the special varargs variable). |
caller |
This is true if the macro accesses the special caller variable and may be called from a call tag. |
In some cases it can be useful to pass a macro to another macro. For this purpose, you can use the special call block.
The following example shows a macro that takes advantage of the call functionality and how it can be used:
{% macro render_dialog(title, class='dialog') -%}
<div class="{{ class }}">
<h2>{{ title }}</h2>
<div class="contents">
{{ caller() }}
</div>
</div>
{%- endmacro %}
{% call render_dialog('Hello World') %}
This is a simple dialog rendered by using a macro and a call block.
{% endcall %}
It is also possible to pass arguments back to the call block. This makes it useful as a replacement for loops. Generally speaking, a call block works exactly like a macro without a name.
Here’s an example of how a call block can be used with arguments:
{% macro get_users(users) -%}
<ul>
{%- for user in users %}
<li><p>{{ user.username|e }}</p>{{ caller(user) }}</li>
{%- endfor %}
</ul>
{%- endmacro %}
{% call(user) get_users(list_of_user) %}
<dl>
<dl>First Name</dl>
<dd>{{ user.first_name | e }}</dd>
<dl>Last Name</dl>
<dd>{{ user.last_name | e }}</dd>
</dl>
{% endcall %}
Best practices for OneFuse templating
OneFuse Property Sets overview
Quick reference examples for common OneFuse templating patterns
Reference for OneFuse Jinja2 expressions including literals, math, comparisons, logic, and operators
Reference for OneFuse Jinja2 control structures including for loops, if statements, and variable assignment
Reference for OneFuse Jinja2 tests used to evaluate variables and expressions
Reference for OneFuse Jinja2 filters used to transform and format variable values