Calling filters on an incorrect type like trying to capitalize an array or using invalid types for arguments will result in an error.
Filters are functions with the `fn(Value, HashMap<String, Value>) -> Result<Value>` definition and custom ones can be added like so:
```rust
tera.register_filter("upper", string::upper);
```
While filters can be used in math operations, they will have the lowest priority and therefore might not do what you expect:
```css
{{ 1 + a | length }}
// is equal to
{{ (1 + a) | length } // this will probably error
// This will do what you wanted initially
{{ a | length + 1 }}
```
Tera has many [built-in filters](@/docs/_index.md#built-in-filters) that you can use.
#### Filter sections
Whole sections can also be processed by filters if they are encapsulated in `{% filter name %}` and `{% endfilter %}`
tags where `name` is the name of the filter:
```jinja2
{% filter upper %}
Hello
{% endfilter %}
```
This example transforms the text `Hello` in all upper-case (`HELLO`).
Filter sections can also contain [`block` sections](@/docs/_index.md#inheritance) like this:
```jinja2
{% filter upper %}
{% block content_to_be_upper_cased %}
This will be upper-cased
{% endblock content_to_be_upper_cased %}
{% endfilter %}
```
### Tests
Tests can be used against an expression to check some condition on it and
are made in `if` blocks using the `is` keyword.
For example, you would write the following to test if an expression is odd:
```jinja2
{% if my_number is odd %}
Odd
{% endif %}
```
Tests can also be negated:
```jinja2
{% if my_number is not odd %}
Even
{% endif %}
```
Tests are functions with the `fn(Option<Value>, Vec<Value>) -> Result<bool>` definition and custom ones can be added like so:
```rust
tera.register_tester("odd", testers::odd);
```
Tera has many [built-in tests](@/docs/_index.md#built-in-tests) that you can use.
### Functions
Functions are Rust code that return a `Result<Value>` from the given params.
Quite often, functions will need to capture some external variables, such as a `url_for` global function needing
the list of URLs for example.
Here's an example on how to implement a very basic function:
```rust
fn make_url_for(urls: BTreeMap<String, String>) -> impl Function {
Box::new(move |args| -> Result<Value> {
match args.get("name") {
Some(val) => match from_value::<String>(val.clone()) {
Ok(v) => Ok(to_value(urls.get(&v).unwrap()).unwrap()),
Err(_) => Err("oops".into()),
},
None => Err("oops".into()),
}
})
}
```
You then need to add it to Tera:
```rust
tera.register_function("url_for", make_url_for(urls));
```
And you can now call it from a template:
```jinja2
{{/* url_for(name="home") */}}
```
You can also implement the [trait](https://docs.rs/tera/1.5.0/tera/trait.Function.html) directly if you have more
complex requirements.
Currently functions can be called in two places in templates:
- variable block: `{{/* url_for(name="home") */}}`
- for loop container: `{% for i in range(end=5) %}`
Tera comes with some [built-in functions](@/docs/_index.md#built-in-functions).
## Control structures
### If
Conditionals are fully supported and are identical to the ones in Python.
```jinja2
{% if price < 10 or always_show %}
Price is {{ price }}.
{% elif price > 1000 and not rich %}
That's expensive!
{% else %}
N/A
{% endif %}
```
Undefined variables are considered falsy. This means that you can test for the
presence of a variable in the current context by writing:
```jinja2
{% if my_var %}
{{ my_var }}
{% else %}
Sorry, my_var isn't defined.
{% endif %}
```
Every `if` statement has to end with an `endif` tag.
### For
Loop over items in a array:
```jinja2
{% for product in products %}
{{loop.index}}. {{product.name}}
{% endfor %}
```
Or on characters of a string:
```jinja2
{% for letter in name %}
{% if loop.index % 2 == 0%}
<span style="color:red">{{ letter }}</span>