zem_template_design

Инструкция по написанию шаблонов

ООО «КОДЖЕЗ» (COGEZ LTD), 2025

Продукт: «Code Generation Zemlya» -
мультифункциональная универсальная система генерации кода/текста

  • 3.4.x

Терминология

Идентификатор - им может считаться последовательность
символов, начинающаяся с буквы латинского алфавита или символа
подчёркивания «_», и состоящая из символов подчёркивания, букв
латинского алфавита и цифр. Примеры: «my_ident», «__MyIdent42»,
«_123». Не могут содержать символы кирилицы, спецсимволы, пробелы
или начинаться с цифры. Идентификаторы не заключаются в кавычки.
Примеры невалидных идентификаторов: «123_asd», «"Моя переменная"».

Пустое значение - В нашем случае, нет "пустоты", как в других
языках (пустые указатели и так далее). Есть признак, что значение
отсутствует - null (или Null), но, это тоже является значением.
Ради совместимости с другими языками, в контексте значение null ещё
представлено ключевым словом none (как в Python), можно с большой
буквы None (движок понимает). Null можно сравнивать с другим
Null - выражение None == Null вернёт true.

Аргумент - То, что передаётся в скобках при вызове Функций,
Фильтров, Тестеров. Синоним: Параметр.

Массив - Последовательность элементов. Хранить может любые
значения. Синонимы: Список, Array, Вектор (Vec, Vector), List.

Маппинг - Объект, хранящий пары "ключ: значение" (key: value).
Значение может быть чем угодно (строка, число, Массив, другой Маппинг
и т.д.). Ключами могут выступать строки, целые числа (отрицательные
пока не поддерживаются) и булевы значения. Доступ к не строковым
ключам возможен только через функцию get. При конвертации в JSON не
строковые ключи автоматически преобразуются в строки (формат JSON не
поддерживает). Подробности описаны ниже. Синонимы: Объект (англ.
Object), Мапа (англ. Map, Mapping), Словарь (англ. Dict, Dictionary).

Фильтр - Принимает значение self и может быть использован
только после символа канала «|». Возвращает какое-то значение (в
большинстве вариантов модифицированный self).

Тестер - Похож на Фильтр, только возвращает логический тип -
значение true/false. В основном, используются в конструкциях if
для проверки значений. Перед тестером ставится ключевое слово is.

Функция - Не принимает self, то есть, её нельзя использовать
после символа канала «|», вызывается самостоятельно, принимает
аргументы (не обязательно) и что-то возвращает (может возвращать
пустое значение (null), но производить какие-либо действия).

Синтаксис шаблонизации

Основы

Существует всего 3 вида разделителей:

  • «{{» и «}}» - для выражений (результат выражения выводится на
    печать), далее будем использовать термины "напечатать" или
    "отобразить"
  • «{%» и «%}» - для операторов управления, объявлений, директив
    (результат на печать не выводится)
  • «{#» и «#}» - для комментариев (ни на что не влияют, на печать
    не выводятся)

Сырой блок

{% raw %}Привет {{ name }}!{% endraw %}

Будет напечатано «Привет {{ name }}!», то есть, как есть, без
вычислений и подстановок. Не представляет особого интереса,
используется в редких случаях.

Контроль пустых пространств

Добавьте минус «-» в разделитель: используйте «{%-» если вы хотите
удалить все пробелы и переносы строк (пустое пространство) перед
оператором, и «-%}», если вы хотите удалить всё пустое пространство
после оператора. Это поведение также работает с выражениями, используя
«{{-» и «-}}», и с комментариями, используя «{#-» и «-#}».

Например, давайте посмотрим на следующий шаблон:

{% set my_var = 42 %}
{{ my_var }}

Будет напечатано:

пустая_строка_сверху
42

"пустая_строка_сверху" - просто обозначение пустой строки.

Если мы хотим избавиться от пустой строки сверху, можем написать
следующее:

{% set my_var = 42 -%}
{{ my_var }}

Или:

{% set my_var = 42 %}
{{- my_var }}

В обоих случаях, пустая строка исчезнет. Пустое пространство удаляется
до первого "значащего" символа.

Комментарии

Чтобы закомментировать часть шаблона, перенесите его в «{#» и
«#}». Все, что находится между этими тегами, отображаться не будет.

{# Это комментарий, он не влияет на печать шаблона. #}
{% set my_var = 42 %}{# Это тоже коментарий. #}
{{- my_var }}
{#-
Это многострочный комментарий.
* Всё, что написано в коментариях никогда не попадёт на печать.
-#}

Заведите привычку писать комментарии - это полезно. Через месяц можно
не вспомнить, что это за переменная или на что влияет представленное
выражение.

Типы данных

Их всего несколько:

  • логический тип (bool, boolean), это только true (истина) или
    false (ложь), третьего не дано ("не задано" не бывает), так же
    движок понимает True/False (с большой буквы)
  • целочисленный тип (int, integer), просто отрицательное или
    положительное число без дробной части (без точки «.»)
  • целочисленный тип без знака (uint, uinteger), просто положительное
    число (без знака и без точки «.»)
  • число с плавающей точкой (float), оно может содержать дробную часть
    и иметь знак
  • строка (str, string), любой текст, обрамлённый одинарными кавычками
    «'строка'» или двойными кавычками «"строка"», либо вот такими
    кавычками «`строка`» (в левом углу клавиатуры под клавишей
    «Esc»)
  • массивы, список литералов или идентификаторов окружённых квадратными
    скобками «[» и «]», запятая в конце допускается, подробнее в
    примерах ниже
  • маппинги, хранят пары - ключи и их значения (key: value),
    допускается создание маппингов, как и в других языках
    программирования, по синтаксису похож на словарь в Python, который
    создаётся с помощью фигурных скобок, например:
    {% set my_map = {"key": "value", 42: 23, true: false, } %}
  • пустое значение - null, оно имеет несколько синонимов в языке,
    которые воспринимаются движком одинаково, это: null, Null,
    none, None

Переменные

Переменные определяются контекстом, заданным при рендеринге
(отрисовке) шаблона. Контекст, это и есть те данные из входных файлов,
которые переданы на рендеринг. Вы можете задать переменную с помощью
{% set my_name_is = "Alex" %}, и она появится в контексте. Вы можете
отобразить переменную с помощью {{ my_name_is }}. Можете
использовать переменную где угодно далее в шаблоне
{% if my_name_is == "Alex" %}...{% endif %}. Но, помните! Попытка
получить доступ к переменной, которой не существует, или отобразить
ее, приведет к ошибке. Есть способы определить существует (задана ли)
переменная - это будет разобрано далее.

Задание переменных

Вы можете присваивать значения переменным в процессе рендеринга.
Назначения в циклах for и макросах ограничены их собственным
контекстом (область видимости переменных), но назначения вне их будут
задаваться в глобальном контексте. Кроме того, назначения в цикле
for действительны только до конца текущей итерации. Примеры:

{% set my_var = "hello" %}
{% set my_var = 1 + 4 %}
{% set my_var = some_var %}
{% set my_var = macros::some_macro() %}
{% set my_var = global_fn() %}
{% set my_var = [1, true, some_var | round, ] %}

Есть способ присвоить значение переменной в глобальном контексте во
время выполнения цикла for или в теле макроса, это делается через
set_global:

{% set_global my_var = "hello" %}
{% set_global my_var = 1 + 4 %}
{% set_global my_var = some_var %}
{% set_global my_var = macros::some_macro() %}
{% set_global my_var = global_fn() %}
{% set_global my_var = [1, true, some_var | round, ] %}

Вне цикла for или вне макроса, set_global работает точно также,
как set.

Внимание! При объявлении уже существующей переменной, её значение
будет перезаписано, а старое значение безвозвратно потеряно.

Получение доступа через точку «.»

Если вы имеете дело с Маппингом, и ключи в нём в нормальной форме, то
есть, начинаются с символа подчёркивания, либо латинской буквы и далее
состоят из латинских букв/цифр и символов подчёркивания без каких-либо
спецсимволов и пробелов, то есть, соответствуют правилам,
установленным для идентификаторов, то вы можете получить доступ к
содержимому ключа по упрощённой форме через точку «.». Пример:

{{ product.name }}

С Массивами всё проще - можно получать доступ к элементам также (через
точку «.»), но по индексу элемента (порядковый номер начиная с
нуля):

{{ my_array.0 ~ my_array.1 }}
{# Символ тильды `~` работает как конкатенация строк, то есть,
объединяет строки. Будет разобран далее. #}

Если ключ или индекс не найден - будет ошибка. Как получить значение
безопасным способом - описано ниже (смотри «get» и «nth»).

Использование квадратных скобок «[» и «]»

Более эффективная альтернатива точки «.». Доступ к значению по ключу
{{ product['name'] }} или {{ product["name"] }} для Маппингов. Или
доступ к значению по индексу {{ list[0] }} для Массивов.

{# Для Маппинга, через переменную: #}
{% set my_key = `name` %}
{{ product[my_key] }}
{# Или более кратко: #}
{{ product['name'] }}
{# И для Массива, тоже самое. #}
{% set my_index = 42 %}
{{ my_array[my_index] }}
{# Или более кратко: #}
{{ my_array[42] }}

Внимание! Если элемент не заключен в кавычки, он будет обрабатываться
как идентификатор (переменная), предполагая, что у вас есть эта
переменная в контексте (если нет, то будет ошибка рендеринга).

В качестве индекса для Массива могут использоваться только переменные,
преобразующиеся в строку или целое число соответственно. Всё
остальное будет ошибкой. То есть, теоретически и с Массивом можно
работать так: {{ my_array["42"] }}. Но, лучше так не делать -
дополнительные проверки при преобразовании к числу скажутся на
быстродействии, и это реальный шанс внести ошибки.

Важно! Если значение не будет найдено по ключу или по индексу (выход
за диапазон Массива или отсутствие такого ключа в Маппинге), то будет
ошибка. Как получить значение безопасным способом, описано ниже
(см. «get» и «nth»).

Выражения

Выражение - это некоторая последовательность каких-то
вычислений/вызовов. Выражения допускаются практически везде.

Математика

Вы можете выполнять некоторую базовую математику, но не следует
злоупотреблять ей, за исключением случая +1 и подобных.
Математические операции разрешены только с числами, их использование с
любыми другими значениями приведет к ошибке. Вы можете использовать
следующие операторы:

  • «+» - складывает 2 значения, {{ 1 + 1 }} выведет 2
  • «-» - выполняет вычитание, {{ 2 - 1 }} выведет 1
  • «/» - выполняет деление, {{ 10 / 2 }} выведет 5
  • «*» - выполняет умножение, {{ 5 * 2 }} выведет 10
  • «**» - выполняет возведение в степень, {{ 2 ** 3 }} выведет 8
  • «%» - выполняет преобразование по модулю (остаток от деления),
    {{ 2 % 2 }} выведет 0, {{ 3 % 2 }} выведет 1
  • «//» - выполняет целочисленное деление (сколько раз число делится
    на делитель), {{ 10 // 3 }} выведет 3

Приоритет операций следующий:

  • «*» и «**» и «/» и «%» и «//» - умножение, деление и т.д.
    в первую очередь
  • «+» и «-» - сложение и вычитание во вторую

Другими словами, сначала будут производиться операции деления,
умножения и т.д., затем сложения и вычитания. Используйте скобки для
управления последовательностью операций:
{{ (((4 + 1) / (7 - 5)) + 2) * 2 }}.

Сравнения

  • «==» - true, если значения равны, иначе false
  • «!=» - true, если значения НЕ равны, иначе false
  • «>=» - true, если левое значение равно или больше правого,
    иначе false
  • «<=» - true, если правое значение равно или больше левого,
    иначе false
  • «>» - true, если левое значение больше правого, иначе false
  • «<» - true, если правое значение больше левого, иначе false

Логика

  • «and» - true, если левый И правый операнды имеют значение true
  • «or» - true, если левый ИЛИ правый операнды имеют значение
    true
  • «not» - отрицание выражения, то есть true превращается в
    false, а false превращается в true (используется как приставка
    перед операндом)

Используёте скобки для объединения в группы: (... or ...) and (...).

Объединение (конкатенация)

Вы можете объединить несколько строк/чисел/идентификаторов, используя
оператор «~» (тильда). На клавиатуре он находится под клавишей Esc
(в английской раскладке с нажатым Shift).

{{ "hello " ~ 'world' ~ `!` }}
{{ an_ident ~ " and a string" ~ another_ident }}
{{ an_ident ~ another_ident ~ 42 }}

Идентификатор, преобразующийся во что-то отличное от строки или числа,
вызовет ошибку.

Важно!!! Оператор объединения «~» имеет более высокий приоритет, чем
другие операторы, поэтому используйте скобки для группировки:

{{ an_ident ~ "\"" ~ ( 42 + 42 ) ~ "\n" ~ ( another_ident | upper ) }}

Оператор «in»

Вы можете проверить, содержится ли левая сторона в правой стороне,
используя «in» оператор.

{{ some_var in [1, 2, 3] }}
{{ 'Great' in product.categories }}
{{ an_ident not in an_obj }}

В правой части поддерживаются только литералы/переменные, приводящие к
Массиву, Строке (тоже, своего рода, Массив из символов) и Маппингу
(проверить существование ключа), всё остальное вызовет ошибку. В левой
части поддерживаются любые значения, но в пределах разумного (не стоит
искать null или цифру в строке - это вызовет ошибку).

Фильтры

Вы можете изменять переменные с помощью фильтров. Фильтры отделяются
от переменной или значения символом канала |, и могут иметь
именованные аргументы в круглых скобках. Несколько фильтров могут быть
объединены в цепочку - выходные данные одного фильтра переходят к
следующему.

Например, {{ name | lower | replace(from="junior", to="jun.") }}
примет переменную с именем name, преобразует в нижний регистр, а
затем заменит все junior на jun.. Вся цепочка фильтров выполняется
последовательно.

Вызов фильтров для неправильного типа приведет к ошибке. Каждый фильтр
предусмотрен для каких-то определённых типов, например, lower и
replace работают только со строковыми значениями. Но, фильтры у
которых есть аргумент default, являются исключением - при указании
default они не вызовут ошибку, а вернут указанное в аргументе
default значение.

Хотя фильтры можно использовать в математических операциях, они будут
иметь самый низкий приоритет и, следовательно, могут не
соответствовать вашим ожиданиям:

{% set a = [1, 2, 3, ] %}
{{ 1 + a | length }}{# Ошибка! #}
{# Эквивалентно следующей записи #}
{{ ( 1 + a ) | length }}{# Это приведет к ошибке
(сложение числа с Массивом). #}
{# Определить длинну массива `a` и прибавить к результату единицу.
Вот такой вариант позволит сделать то, что вы хотели изначально. #}
{{ ( a | length ) + 1 }}
Фильтрация разделов

Целые разделы также могут обрабатываться фильтрами, если они заключены
в теги {% filter name %} и {% endfilter %} , где name - название
фильтра:

{% filter upper %}
Hello
{% endfilter %}

В этом примере весь блок с текстом Hello преобразуется полностью в
верхний регистр (HELLO). Это, пожалуй, единственная возможность
использования фильтров не после символа канала «|».

Тестеры

Тесты могут использоваться после выражения или переменной для проверки
некоторого условия, и выполняются в if блоках с использованием
ключевого слова is. Например, вы могли бы написать следующее, чтобы
проверить, является ли выражение или переменная нечетным числом:

{% if my_number is odd %}
число НЕчётное
{% endif %}

Тесты также могут быть логически перевёрнуты с помощью not:

{% if my_number is not odd %}
число чётное
{% else %}
число НЕчётное
{% endif %}
{# И так тоже можно.
`not` можно ставить как перед фильтром, так и перед выражением. #}
{% if not my_number is odd %}
число чётное
{% else %}
число НЕчётное
{% endif %}

Также тесты можно использовать не только в выражениях «if»,
например:

{% set is_odd = my_number is odd %}

Если my_number не чётное число, то переменная is_odd будет равна
true (логический тип), иначе false.

Все тестеры возвращают только булевое значение, то есть true или
false.

Функции

Функции принимают аргументы и возвращают какое-то (в зависимости от
логики) значение. Например, функция range(end=5) вернёт Массив из
пяти элементов [0, 1, 2, 3, 4]. Можно использовать, например, в
цикле:

{% for i in range(end=5) %}
{{ i }}
{% endfor %}

Структуры управления

Оператор ветвления

Условные выражения полностью поддерживаются и идентичны тем, что есть
в Python.

{% if price < 10 or always_show %}
Price is {{ price }}.
{% elif price > 1000 and not rich %}
That's expensive!
{% else %}
N/A
{% endif %}

Неопределенные переменные считаются ложными. Это означает, что вы
можете проверить наличие переменной в текущем контексте, написав:

{% if my_var %}
{{ my_var }}
{% else %}
Sorry, my_var isn't defined.
{% endif %}

Каждый if оператор должен заканчиваться endif - закрывающим тегом.
Блоки elif и else не обязательны.

Важно! Если в оператор if передано просто значение, пример
{% if value %}...{% endif %}, то оно, проверяется на существование
в контексте (если не существует, то false), если значение
существует, то оно проверяется на тип, для булевых значений всё
более-менее ясно, а вот пустые значения в виде пустой строки, числа
ноль, пустых Массивов и Маппингов, тоже будут считаться false,
то есть, if 0, if "", if [] и подобные вернут false и
переведут выполнение сразу на блок elif/else. В общем, всё как в
Python (неоднозначно и запутано, но так исторически сложилось,
приходится соответствовать). В сложных ситуациях не используйте
краткую запись, а пользуйтесь чёткими условиями
if value is defined, if value is undefined,
if value is defined and value == 0 (мы вернёмся ещё к этому ниже,
просто запомните, что это место неоднозначно, и лучше писать более
ясные условия в операторе if во избежание сюрпризов).

Также в синтаксисе поддерживаются тернарные операторы. Это своего
рода выражения, которые возвращают значения. Например:
{{ "Ok" if my_var is defined else "Fail" }}, это легко читается как:
если my_var представлена в контексте, то печатается «Ok», иначе
«Fail». Тернарные операторы можно использовать практически везде,
где ожидаются выражения.

Оператор цикла

Перебирайте элементы в Массиве:

{%- for product in products %}
{{- loop.index }}. {{ product.name }} - {{ product.price }}
{%- endfor %}

Или по символам строки:

{%- for letter in name %}
{%- if loop.index % 2 == 0 %}
{{- letter | upper }}
{%- else %}
{{- letter | lower }}
{%- endif %}
{%- endfor %}

Внутри циклов for доступно несколько специальных переменных:

  • loop.index - текущая итерация начиная с единицы
  • loop.index0 - текущая итерация начиная с нуля
  • loop.first - признак является ли это первой итерацией
  • loop.last - признак является ли это последней итерацией

Каждый for оператор должен заканчиваться endfor - закрывающим
тегом.

Вы также можете перебрать Маппинг, используя следующий синтаксис:

{% for key, value in products %}
{{ key }}. {{ value.name }}
{% endfor %}

key и value могут быть привязаны к каким угодно переменным, их
просто нужно указать после for и разделить запятой. То есть,
for k, v in product, for x, y in product и так далее.

Вы также можете применить фильтры к источнику данных:

{% for product in products | reverse %}
{{loop.index}}. {{product.name}}
{% endfor %}

Вы также можете выполнять итерации с литеральными Массивами или
Мапингами:

{% for a in [1, 2, 3, ] %}
{{ a }}
{% endfor %}

Наконец, вы можете установить поведение по умолчанию для отображения,
когда источник данных пуст с помощью необязательной директивы
{% else %}:

{% for product in products %}
{{ loop.index }}. {{ product.name }}
{% else %}
Data no present.
{% endfor %}
Управление циклом

Внутри цикла, break и continue могут использоваться для управления
итерацией.

Остановить итерацию при достижении значения переменной target_id:

{% set target_id = 100 %}
{% for product in products %}
{% if product.id == target_id %}{% break %}{% endif %}
{{ loop.index }}. {{ product.name }}
{% endfor %}

Пропустить элементы с четными номерами:

{% for product in products %}
{% if loop.index is even %}{% continue %}{% endif %}
{{- loop.index }}. {{ product.name }}
{% endfor %}

Вложенность

Вы можете вставить дочерний шаблон для отображения с использованием
текущего контекста с помощью тега include.

{% include "inner/path/childred.jinja" %}

Путь к шаблону должен быть статичной строкой. Такое недопустимо:

{% include "inner/path/" ~ name ~ ".jinja" %}{# Ошибка! #}

Нужно понять следующее. Движок должен заранее знать о подключаемых
шаблонах. Они должны быть статично заданы и заранее известны. Если у
вас есть желание использовать условия для подключения шаблонов, то
пользуйтесь инструкцией if, пример:

{% if product in ['inner', 'extra'] %}
{% include "inner/child.jinja" %}
{% elif product == `outer` %}
{% include "outer/child.jinja" %}
{% else %}
{# Функция `throw` будет описана ниже. #}
{{ throw(message='missing include template: product "' ~ product ~
'" unknown') }}
{% endif %}

Движок передаёт глобальный пользовательский контекст в директиву
include. Хотя вы и можете использовать set значения во вложенных
шаблонах, эти значения существуют только во время рендеринга конкретно
этого подшаблона. Но они передаются и доступны в дочерних (вложенных)
шаблонах ниже по иерархии. В общем, шаблон-родитель не видит
переменных дочернего шаблона, но дочерний шаблон видит всё, что было
объявлено в родительском.

Компоненты

Компоненты - это по сути встроенные функции.

Компоненты могут быть определены, где угодно. Желательно в отдельной
поддиректории и в отдельных файлах. Импортировать не требуется.
Движок автоматически и самостоятельно их найдёт и подключит.

Текущий синтаксис (может немного измениться):

Определение компонента:

{% component func(greeting: string, age: integer, data: map = {})
{"ref": "./ref.json"} %}
{{ greeting }}: {{ body }}{# Да, у компонента есть доступ к телу
при блочном вызове -#}
{% endcomponent %}

Mетаданные (вот эти: {"ref": "./ref.json"}) необязательны.

Вызовы:

  • встроенный:

{{ :func() }}

  • c телом (блочный вызов):
{% :func(greeting="Hello") %}
Anything in there will be available in the component as {{ null -}}
the `body` variable
{% endcomponent :func %}{# Конечное имя необязательно #}

Пока компоненты находятся в процессе разработки, лучше использовать
вложения (include).
TODO: описаны компоненты будут подробнее позже, когда закончится
их разработка

Функционал шаблонизации

Встроенные Фильтры

Напоминаем, фильтры принимают self, то есть, стоят после символа
канала «|» (через этот символ, они получают значение с которым
работают).

lower, upper

Преобразует строку, соответственно, в нижний или верхний регистр.
Если self не является строкой, то эти фильтры вернут ошибку,
подавить ошибку можно задав аргумент default.

trim, trim_start, trim_end

Удаляет пустые пространства (пробелы, переносы строк, непечатаемые
символы), если переменная является строкой. Соответственно, с обоих
концов - trim, с начала - trim_start, с конца - trim_end.
Имеется не обязательный аргумент pat - это подстрока для удаления.
Если аргумент pat не указан, то удаляется пустое пространство.
Если self не является строкой, то эти фильтры вернут ошибку,
подавить ошибку можно задав аргумент default.

capitalize

Возвращает строку со всеми ее символами в нижнем регистре за
исключением первого символа, который будет в верхнем регистре.

title

Преобразует строку в нижний регистр, а первую букву каждого слова
делает заглавной.

replace

Производит замену в строке. Два параметра:

  • from - фрагмент строки, который нужно заменить
  • to - на что менять

Пример:

{{ name | replace(from="Alex", to="Алексей") }}
addslashes

Добавляет слэши «\» перед кавычками, переносами строк, возвратами
каретки, табуляциями и слэшами (экранирование). Пример:

{%- set value = `"\\"'\n'"\r"'\t'`%}
До экранирования:
{{ value }}
После экранирования:
{{ value | addslashes }}
Экранирование блоком:
{% filter addslashes -%}
{{ value }} ''""\
{%- endfilter %}

Вывод:

До экранирования:
"\"'
'"
"' '
После экранирования:
\"\\\"\'\n\'\"\r\"\'\t\'
Экранирование блоком:
\"\\\"\'\n\'\"\r\"\'\t\' \'\'\"\"\\
get

Используется для получения значений по ключу из Маппинга. Ключом может
быть: строка, булево значение или целое число (даже отрицательное).

{# если не найдёт такого ключа, то будет ошибка #}
{{ my_map | get(key="My Key number 42") }}
{# если не найдёт, то вернёт "default 42" #}
{{ my_map | get(key="My Key number 42/content 1",
default="default 42") }}
{# если не найдёт, то вернёт 42 (число) #}
{{ my_map | get(key="My Key number 42/content 2", default=42) }}

Если ключ строковый, и содержит пробелы, спецсимволы и всякую другую
экзотику, то его нельзя использовать как идентификатор. Например:

{{ my_arr.My Key number 42/content 2 }}{# вызовет ошибку парсинга #}
{{ my_arr."My Key number 42/content 2" }}{# тоже вызовет ошибку #}

Есть только два варианта работы с подобными ключами в Маппинге -
воспользоваться квадратными скобками
{{ my_arr.["My Key number 42/content 2"] }} или через get. Через
get безопаснее, если указать default значение.

nth

Возвращает элемент Массива по индексу (отсчёт начинается с нуля).
Пример: {{ my_array | nth(n=0) }}. Фильтр nth вызовет ошибку, если
индекс указанный в аргументе n вышел за пределы диапазона. Чтобы
подавить эту ошибку, используёте аргумент default, который может
быть любым значением. Также, позволяется указывать отрицательный
аргумент n, тогда отсчёт начинается с конца Массива.

insert, append, delete

Операции над маппингами. Вставка единичного "ключа: значения",
обогащение другим Маппингом и удаление по ключу (списку ключей).

Примеры использования лучше показать кодом:

{# Все операции над Маппингами не изменяют исходный маппинг,
а лишь возвращают новый модифицированный Маппинг, который
можно сохранить, как новое значение, или использовать на месте.
Примечание: Да, создание клона Маппинга и операции над
ним немного сказываются на быстродействии и расходуют
память, но, если вы не сохраняете результаты в переменную,
то, они удаляются сразу после использования. Согласитесь,
удобно без опаски манипулировать исходными Маппингами,
например, до итерации в цикле (что-то добавить или убрать).
Это как конструктор - можно из кубиков собрать
то, что нужно и если это нужно далее, то сохранить, а
если не нужно, то оно само рассыпется на кубики, и кубики
не пострадают. Это удобно.
-#}
{% set map0 = {"key0": 0, } -%}
{% set map1 = {"key1": 1, "key2": 2, true: false, 42: 43, } -%}
map0 append return: {{ map0 | append(values=map1) }}
=> возвратился `map0` обогащённый значениями из `map1`
map0 after append: {{ map0 }} => исходный `map0` не изменился
map1 after append: {{ map1 }} => исходный `map1` не изменился
map0 insert return: {{ map0 | insert(key=1, value=42) }}
=> возвратился `map0` с вставленным одним `key: value`
map0 after insert: {{ map0 }} => исходный `map0` не изменился
map0 delete return: {{ map0 | delete(keys="key0") }}
=> возвратился `map0` с удалённым ключём `key0`
map0 after delete: {{ map0 }} => исходный `map0` не изменился
{% set map2 = map0 | append(values=map1)
| insert(key="key3", value=[1, 2, 3, 42, ])
| delete(keys=42) | delete(keys=true) | delete(keys="key0") -%}
map2 after: {{ map2 }}
{# В `delete` можно указывать один ключ, либо список ключей.
Напоминание: ключами в Маппинге могут быть только строки,
целые числа или логические значения (`true`/`false`). -#}
{% set map2 = map0 | append(values=map1)
| insert(key="key3", value=[1, 2, 3, 42, ])
| delete(keys=[42, true, "key0", ]) -%}
map2 after: {{ map2 }}
map0 after all: {{ map0 }} => исходный `map0` не изменился

Результат:

map0 append return: {"key0": 0, "key1": 1, "key2": 2, true: false, 42: 43}
=> возвратился `map0` обогащённый значениями из `map1`
map0 after append: {"key0": 0} => исходный `map0` не изменился
map1 after append: {"key1": 1, "key2": 2, true: false, 42: 43}
=> исходный `map1` не изменился
map0 insert return: {"key0": 0, 1: 42}
=> возвратился `map0` с вставленным одним `key: value`
map0 after insert: {"key0": 0} => исходный `map0` не изменился
map0 delete return: {} => возвратился `map0` с удалённым ключом `key0`
map0 after delete: {"key0": 0} => исходный `map0` не изменился
map2 after: {"key1": 1, "key2": 2, "key3": [1, 2, 3, 42]}
map2 after: {"key1": 1, "key2": 2, "key3": [1, 2, 3, 42]}
map0 after all: {"key0": 0} => исходный `map0` не изменился
truncate

Обрезает строку до указанной длины. Если длина строки меньше, то
строка возвращается, как есть. Пример:
{{ value | truncate(len=42) }}. По умолчанию фильтр добавит
многоточие (...) в конце, если текст был обрезан. Вы можете изменить
добавляемую строку, задав аргумент fill. Например:
{{ value | truncate(len=42, fill="") }} - ничего не добавит в конце.
Есть возможность задать отрицательную длинну, то есть,
{{ value | truncate( len = -42 ) }} - отрежет последние 42 символа
и добавит многоточие (...) уже в начале строки (или то, что указано
в аргументе fill).

join

Массив в строку с разделителями:

{%- set my_array = [1, 2, 3] -%}
{{- my_array | join(sep=", ") -}}

Выведет: 1, 2, 3.

length

Возвращает количество элементов. Применяется к Массивам, Маппингам и
строкам.

reverse

Переворачивает (задом наперёд). Применяется к Массиву или строке.

sort

Сортирует Массив (только Массив) в соответствии с правилами. Если
Массив из чисел, то от наименьшего к наибольшему. Если из строк, то в
соответствии с номерами символов в кодовой таблице UTF-8 (побуквенно).
Если Массив состоит из других Массивов или Маппингов, то
руководствуется длинной каждого Массива/Маппинга (от наименьшего к
наибольшему). Если массив состоит из булевых значений, то true=0,
а false=1. Если Массив вперемешку, то результат будет не очень. В
общем, каждому элементу Массива будет присвоен индекс, в соответствии
с правилами изложенными выше, далее они выстраиваются по индексам.
Сортировка - сложная тема при данных, которые могут быть разнородны.
Пользуйтесь осторожно.

Если вы уверены, что Массив состоит из однородных объектов, например,
из Массивов или заранее известных структур (Маппингов, например), то
можно сортировать по какому-то атрибуту или Массиву атрибутов
(аргумент attribute):

{# Если Массив состоит из Маппингов, и сортировка по ключу `name` #}
{{ people | sort(attribute="name") }}{# Сортировка по именам #}
{# Или состоит из Маппингов, в которых точно есть ключ `age` #}
{{ people | sort(attribute="age") }}{# Сортировка по возрасту #}
{# Множественая сортировка #}
{# Сортировка сначала по полу, внутри по возрасту и далее по имени #}
{{ people | sort(attribute=["sex", "age", "name", ]) }}
unique

Убирает дубликаты в Массиве. Только при полной идентичности объектов
дубликаты будут убраны.

slice

Фрагментирует Массив по заданным параметрам start и end. Оба
параметра необязательны, и при их опущении будет возвращен один и тот
же Массив. Используйте аргумент start, чтобы определить, с чего
начать (включительно, по умолчанию - ноль (0)) и end аргумент,
определяющий, где остановиться, не включая элемент с этим индексом
(по умолчанию равен длине Массива). start и end проиндексированы
с нуля (0).

{% set my_arr = [0, 1, 2, 3, 4, 5] %}
{# До 3 элемента не включая его - [0, 1, 2] #}
{% for i in my_arr | slice(end=3) %}...{% endfor %}
{# Всё, за исключением первого элемента - [1, 2, 3, 4, 5] #}
{% for i in my_arr | slice(start=1) %}...{% endfor %}
{# Выдаст - [1, 2, 3] #}
{% for i in my_arr | slice(start=1, end=4) %}...{% endfor %}

Вы также можете использовать отрицательные значения индекса для ссылки
на Массив с последнего элемента. -1 относится к последнему индексу,
-2 относится к предпоследнему индексу и так далее. Например:

{# Всё, за исключением 2-х последних элементов - [0, 1, 2, 3] #}
{% for i in my_arr | slice(end=-2) %}...{% endfor %}
{# Два последних элемента - [4, 5] #}
{% for i in my_arr | slice(start=-2) %}...{% endfor %}
group_by

Группирует Массив, используя attribute аргумент. Фильтр принимает
Массив и возвращает Маппинг, где ключами являются значения attribute
преобразованное к строке, а значениями будут Массивы из элементов
исходного Массива, имеющие значение attribute. Значения, в которых
отсутствует значение attribute или где attribute равно null,
будут отброшены.

{# В результате получим Маппинг с ключами, по возрасту
преобразованными к строке, а значениями будут Массивы из Маппингов
с этими персонами. #}
{{ persons | group_by( attribute = "age" ) }}
filter

Фильтрует значения Массива, возвращая только те значения, где
attribute равно value. Значения, в которых отсутствует
attribute или где attribute равен null, будут отброшены.

{# Выбрать всех сорокадвухлетних #}
{{ persons | filter( attribute = "age", value = 42 ) }}
{# Выбрать всех с именем Alex #}
{{ persons | filter( attribute = "name", value = "Alex" ) }}

attribute - обязательный аргумент. Если аргумент value не задан,
то будут отброшены элементы, в которых нет заданного attribute или
он равен null. Сформулируем иначе - останутся элементы, в которых
есть заданный attribute, и там есть значение, отличное от null.

map

Извлекает атрибут из каждого объекта в Массиве. Аргумент attribute
является обязательным и указывает, что извлекать.

{% set ages = persons | map(attribute="age") | unique | sort %}

Для наглядности применяем ещё фильтры unique и sort (описанные
ранее). В результате, в переменной ages будет отсортированный
список из возрастов всех персон (не повторяющийся список, другими
словами - уникальный).

concat

Фильтр принимает Массив и возвращает новый Массив со значениями из
атрибута with.

{% set persons = [pers1, pers2, pers3,] %}
{% set persons = persons | concat(with=[pers4, pers5, pers6,]) %}
{% set persons = persons | concat(with=[pers7,] ) %}
{{ persons | concat(with=[pers8,]) | concat(with=[pers9,]) }}

Фильтр concat никак не влияет на исходный Массив, а только
возвращает новый объединённый Массив.

abs

Возвращает абсолютное значение. Пример: {{ negative_number | abs }}.
Если negative_number равно -1, вывод будет равен 1. Если
negative_number равно -3.25, вывод будет равен 3.25.

round

Возвращает число, округленное в соответствии с указанным методом.
Метод по умолчанию - common, который округляется до ближайшего
целого числа. ceil и floor доступны в качестве альтернативных
методов. ceil - округляет в меньшую сторону, floor - в большую.
Для выбора точности округления доступен другой необязательный
аргумент - precision. По умолчанию используется значение 0, которое
округляет до ближайшего целого числа, но вы можете указать до
скольких знаков после запятой округлять.

{{ 42.42 | round }}
{# результат 42 (ближайшее целое) #}
{{ 42.424242 | round(method="ceil", precision=2) }}
{# результат 42.42 #}
{{ -42.424242 | round(method="ceil", precision=2) }}
{# результат -42.43 #}

Обратите внимание на последнюю строку, где результат -42.43. Это не
опечатка автора. Метод округления ceil округляет в МЕНЬШУЮ сторону
(-42.43 меньше чем -42.42). С отрицательными числами метод
работает наоборот, так же как и метод floor, который вернул бы
округлив в большую сторону: 42.43 и -42.42.

date

Преобразует временную метку из строки даты/времени или из числа. По
умолчанию используется формат YYYY-MM-DD. Синтаксис форматирования
времени заимствован из strftime, а полная информация доступна на
сайте:

chrono:format

Пример: {{ ts | date }} {{ ts | date(format="%Y-%m-%d %H:%M") }}

Если вы используете строки даты ISO 8601 или временную метку UTC,
вы можете дополнительно указать часовой пояс для даты, в которой
будет отображаться. Пример:

{{ "2019-09-19T13:18:48.731Z" | date(timezone="Europe/Moscow") }}
{{ "2019-09-19T13:18:48.731Z"
| date(format="%Y-%m-%d %H:%M", timezone="Asia/Shanghai") }}
{{ 1648252203 | date(timezone="Europe/Berlin") }}

Может быть указан язык (за исключением случаев, когда вводится
временная метка без аргумента часового пояса), по умолчанию
используется POSIX.

Пример:

{{ 1648252203
| date(
format = "%A %-d %B",
timezone = "Europe/Paris",
)
}}

Для конвертации даты-времени из одного формата в другой можно
использовать параметр out_format (формат на выходе).

Пример:

{{ "05051972" | date(format="%d%m%Y", out_format="%Y-%m-%d") }}
{# Как результат напечатается `1972-05-05` #}
escape_html

Экранирует символы в строке в соответствии со спецификацией HTML.

  • «&» => &amp;
  • «<» => &lt;
  • «>» => &gt;
  • «"» (double quote) => &quot;
  • «'» (single quote) => &#39;
escape_xml

Экранирует символы в строке в соответствии со спецификацией XML.

  • «&» => &amp;
  • «<» => &lt;
  • «>» => &gt;
  • «"» (double quote) => &quot;
  • «'» (single quote) => &apos;
escape_ipc

Экранирует символы в строке в соответствии со спецификацией XML
специально для Informatica PC. На символ экранирования \ (слэш)
"ругается" в строковых значениях, пришлось добавить код символа:

  • «&» => &amp;
  • «<» => &lt;
  • «>» => &gt;
  • «"» => &quot;
  • «'» => &apos;
  • «\» => &#x5c;
split

Разделяет строку по заданным разделителям (аргумент pat).
Возвращает Массив из строк (частей входящей строки).

{{ path | split(pat="/") }}

Обратите внимание. Предположим, что path равен //, то результат
будет таким ["", "", ""]. То есть, в результате будут пустые строки.

Аргумент pat не обязательный, то есть, по умолчанию фильтр split
разбивает строку по "пустому пространству".

int

Преобразует значение в целое число. Аргумент default может
использоваться для указания значения, которое будет возвращено при
ошибке преобразования, аргумент base может использоваться для
указания способа интерпретации числа - основания 2, 8 и 16 -
двоичные, восьмиричные и шеснадцатиричные числа (понимает
префиксы 0b, 0o, 0x соответственно).

Если аргумент default не указан, то ошибка преобразования остановит
процесс генерации (рендеринга). Не забываем,default может быть не
только числом, но и любым другим типом.

float

Преобразует значение в число с плавающей точкой. Аргумент default
может использоваться для указания значения, которое будет возвращено
при ошибке.

Если аргумент default не указан, то ошибка пойдёт уровнем вверх, и
процесс генерации (рендеринга) будет прерван.

str

Возвращает строковое представление заданного значения. То есть,
форматирует переданный объект, преобразуя его в строку. Можно просто
вывести объект на печать - происходит точно такое же преобразование
объекта к строке.

Внимание! Это не сериализует объект, как это делает фильтр to_json,
а только приводит к строковому виду. Результаты могут отличаться.
Гарантий, что это будет строка JSON не даётся. Используйте фильтр
to_json, если вам требуется корректный JSON.

default

Возвращает значение по умолчанию, если переменная отсутствует в
контексте (не определена).

{{ value | default(value=0) }}

Это краткая запись для такого выражения:

{% if value is defined %}{{ value }}{% else %}0{% endif %}

Важно!!! Фильтр default проверяет только существование значения в
контексте, в отличие от if, который проверяет не только
существование значения в контексте, но и само значение на логическое
(true/false), пустоту (null), пустую строку (""), на ноль
(0) (если значение является числом), на пустой Массив или Маппинг.
То есть, {{ "" | default(value="Значение не задано.") }} -
напечатает пустую строку (""), так как, пустая строка тоже
значение, и оно задано. Также и в случае с
{{ null | default(value=42) }} - напечатает null, т.е.
напечатает НИЧЕГО, так как, значение null существует в контексте.
Не забываем - null это тоже значение!

write

Записывает self в указанный файл. Если self является строкой, то
записывает эту строку в файл. Если self НЕ(!!!) строка, то
преобразует значение к строке в формате JSON (с форматированием и
переносами (pretty)) и записывает в файл. Единственный и обязательный
аргумент (путь к файлу) - file (тип: строка).

Внимание! Этот фильтр возвращает то же значение, что получил. То есть,
записал значение в файл и передал значение неизменным дальше по
цепочке. Его можно без опаски вставлять в любую цепочку из каналов
«|» (для "просто посмотреть").

{# Просто посмотреть, что там внутри my_map #}
{{ my_map | write(file="work/rendered/out.txt") | get(key="key 42") }}
{# Или преобразовать значение в YAML, записать в файл и снова
преобразовать (из строки YAML) в объект (на выходе получается
тот же самый объект, что и на входе) #}
{% set first_element = my_arr
| to_yaml
| write(file="work/rendered/out.yaml")
| from_yaml
| get(key=42) %}
to_json, to_yaml, to_toml, from_json, from_yaml, from_toml

Фильтры преобразования в строку (to_...) и обратно из строки
(from_...). Другими словами, сериализация (преобразование в
строку)/десериализация(из строки в объект). Это можно делать не только
со словарями и списками, но и с любыми значениями.

Например:

{# Преобразуем объект `d` в строку json.
Параметр `pretty` по умолчанию `false`, то есть, в одну строку,
если поставить в `true`, то будет форматирование с переносами
(human-readable format - удобочитаемый формат). #}
{% set d_string = d | to_json(pretty=true) %}
{# Преобразуем обратно из строки в объект #}
{% set d_object = d_string | from_json %}
{# Теперь d_object полноценный объект #}

Примечание: параметр pretty характерен только для функции
преобразования объекта в строку JSON, остальные форматы итак
human-readable (удобочитаемы), то есть, с форматированием.

exist

Фильтр проверяет self (что стоит слева от символа | канала(пайпа))
на существование. Аргументы:

  • empty - Массив, содержащий значения, которые нужно считать
    пустыми. Это может быть пустая строка, пустой объект (словарь),
    пустой Массив, числа, строки и любые другие значения, с которыми
    будет сравниваться self.
  • yes - Всё что угодно, любое значение, которое возвратится, если
    self успешно пройдёт проверку на существование (НЕ найдётся
    соответствия в списке empty).
  • no - Всё что угодно, любое значение, которое будет возвращено, в
    случае если self НЕ пройдёт проверку на существование (найдётся
    соответствие в списке empty).

Все аргументы не обязательны, и могут следовать в любом порядке. Если
аргумент empty не указан, то, по умолчанию он будет содержать
массив с элементами: null, пустой Массив, пустой Маппинг, пустая
строка. И, обратите внимание, если вы указываете список значений
empty, то дефолтные значения уже не будут работать (не забудьте
указать их самостоятельно). Если аргумент yes не указан, то он
будет равен self. Если аргумент no не указан, то он по умолчанию
будет равен null.

{{ 1 | exist( empty = [1,2,3], yes = "Yes", no = "No" ) }}
{# напечатается "No", потому что, единичка входит в список `empty` #}
substr

Фильтр принимает self только типа string и возвращает "срез" (часть
строки). Нет обязательных параметров, все не обязательные. Параметры:

  • start - с какой позиции начать, целое число (по умолчанию ноль
    0)
  • end - где остановиться, целое число (по умолчанию равно длине
    строки)
  • count - сколько символов вырезать, целое ПОЛОЖИТЕЛЬНОЕ число
  • default - любое значение, которое будет возвращено, если не
    получилось сделать срез

Вернёт ошибку в случаях:

  • исходная строка пуста, считается ошибкой данных или логики (спасёт
    параметр default)
  • точка старта находится за точкой останова, считается ошибкой логики
    (спасёт параметр default)
  • исходная строка (self) не является строкой, считается ошибкой
    данных или логики (default не спасает, делайте предварительные
    проверки)
  • использование одновременно параметров end и count, ну, тут точно
    ошибка в логике, так как совершенно не понятно, что имеется ввиду,
    относительная или абсолютная точка останова (default не спасает)

Повторим. Если start не указан, то считается, что с начала строки
(по умолчанию 0), если end не указан, то считается, что до конца
строки (по умолчанию равен длине строки). Проиллюстрируем работу
фильтра на примерах:

Оригинальный text >> "0123456789"
{{ text | substr }} >> "0123456789"
{{ text | substr() }} >> "0123456789"
{{ text | substr(start=0) }} >> "0123456789"
{{ text | substr(start=1) }} >> "123456789"
{{ text | substr(start=5) }} >> "56789"
{{ text | substr(start=1000) }} >> ""
{{ text | substr(start=-1) }} >> "9"
{{ text | substr(start=-5) }} >> "56789"
{{ text | substr(start=-1000) }} >> "0123456789"
{{ text | substr(end=0) }} >> ""
{{ text | substr(end=1) }} >> "0"
{{ text | substr(end=5) }} >> "01234"
{{ text | substr(end=1000) }} >> "0123456789"
{{ text | substr(end=-1) }} >> "012345678"
{{ text | substr(end=-5) }} >> "01234"
{{ text | substr(end=-1000) }} >> ""
{{ text | substr(count=0) }} >> ""
{{ text | substr(count=1) }} >> "0"
{{ text | substr(count=5) }} >> "01234"
{{ text | substr(count=1000) }} >> "0123456789"
{{ text | substr(start=1, count=4) }} >> "1234"
{{ text | substr(start=1, count=1000) }} >> "123456789"
{{ text | substr(start=-7, count=4) }} >> "3456"
{{ text | substr(start=-7, end=4) }} >> "3"
{{ text | substr(start=-5, end=4,
default=null()) }} >> ""
// Вот тут! ^^^^^^^^^^^^^^ Обратите внимание!
// Если `default` не указать, то генерация остановится с ошибкой,
// потому что точка старта находится за точной останова.
// Не однозначная ситуация, видимо ошибка в логике.
// В данном случае, может спасти указание дефолтного значения.
{{ text | substr(start=2, end=-2) }} >> "234567"
{{ text | substr(start=-4, end=-2) }} >> "67"
{{ text | substr(start=-7, count=4) }} >> "3456"
{{ text | substr(start=-7, count=1000) }} >> "3456789"

Обратите внимание, что если start или end указать далеко за
пределами строки, то ошибки не будет (они будут автоматически
приведены к началу и/или концу строки соответственно). Это вполне
нормальная ситуация - просто вернётся пустая строка. Но, если вы
указываете одновременно и start и end, то будьте осторожны!
Следите за тем, чтоб точка старта всегда стояла до точки останова.

Примечание: end и count нельзя использовать вместе. Либо одно,
либо другое. Это считается грубой ошибкой, и никакой default тут
не поможет.

regex_replace

Фильтр возвращает строку, где подменяет символы, в соответствии с
регулярным выражением. Аргументы:

  • reg - регулярное выражение, захватывающее последовательности
    символов для последующей замены.
  • to - последовательность символов, на которые будут заменены
    захваченные регуляркой последовательности символов.
{#- Строка #}
{%- set str =
"_123_ $%^#asdf$&@123gh$^&jkl_123;:,.__$%^&#_ab[]{}$%_876^@" %}
Исходная строка:
"{{ str }}"
{#- Символ-разделитель #}
{%- set separator = "_" %}
{#- Регулярное выражение, которое захватывает с начала строки все
символы, отличные от латинских букв в верхнем и нижнем регистре.
И в конце строки все символы, которые отличны от латинских букв,
цифр и символа-разделителя (захваченное мы будем заменять). #}
{%- set reg_trim = "^[^A-Za-z]+|[^A-Za-z0-9" ~ separator ~ "]+$" %}
{#- Регулярное выражение, которое захватывает все последовательности
символов, отличные от латинских букв и цифр. #}
{%- set reg_clear = "[^A-Za-z0-9]+" %}
{#- Очищаем строку от конечных пробелов и спецсимволов, заменяя все
последовательности одним сепаратором. #}
{%- set str = str | regex_replace(reg=reg_trim, to="")
| regex_replace(reg=reg_clear, to=separator) %}
{#- Печатаем результат #}
Очищенная строка:
"{{ str }}"

Вывод:

Исходная строка:
"_123_ $%^#asdf$&@123gh$^&jkl_123;:,.__$%^&#_ab[]{}$%_876^@"
Очищенная строка:
"asdf_123gh_jkl_123_ab_876"

Подробнее по поддерживаемому синтаксису тут:

crate regex: syntax

get_bool

Проверяет self на эквивалент переданному списку в параметре
true_arr, если значение присутствует, возвращает true, иначе -
проверяет на эквивалент переданному списку в параметре false_arr,
если находит соответствие, возвращает false. Также есть параметр
default, который возвращается, если значение не нашлось ни в одном
из списков. Параметр default может быть только true или false,
если что-то другое, то будет считаться, что false.

Параметры могут быть не указаны вообще или частично, значения по
умолчанию для параметров:

  • true_arr = [ true, ]
  • false_arr = [ false, ]
  • default = false

Если self является строкой, то она автоматически очистится от
лидирующих и конечных пробелов перед поиском по спискам. Этот фильтр
удобно использовать для преобразования различных строковых значений в
логические, например:

{% set my_bool_property = my_val | get_bool(
true_arr = [],
false_arr = [0, false, "false", "False", "No",
"no", "N", "n", "Нет", "нет"],
default = true
) %}
{# То есть, если активного несогласия не обнаружено, то считаем,
что согласен и точка #}

Встроенные Тестеры

Тесты отличаются от всего остального тем, что всегда возвращают булево
значение. В любом случае возвращается либо true либо false.

defined и undefined

defined - вернёт true, если значение определено в контексте

undefined - логический перевёртыш, то есть, вернёт true, если
значение НЕ определено в контексте (аналог value is not defined)

odd и even

odd - вернёт true, если число НЕ чётное

even - вернёт true, если число чётное

divisible_by

Возвращает true, если данное выражение делится без остатка на
заданный аргумент divisor.

{% if rating is divisible_by(divisor=2) %}
Divisible
{% endif %}
iterable

Возвращает true, если данная переменная является итерируемой,
то есть, Массив или Маппинг.

starting_with и ending_with

Проверяют строку, на "начинается с" или "заканчивается на",
соответственно.

{% if path is starting_with(pat="x/") %}
In section x
{% endif %}
containing

По-русски "содержит". Проверяет для:

  • строк - содержится ли в строке данная подстрока
  • массивов - содержится ли такой элемент в массиве
  • маппингов - содержится ли такой ключ в маппинге
{% if username is containing(pat="xXx") %}
User is Bad
{% endif %}
matching

Возвращает true, если данная переменная является строкой и
соответствует регулярному выражению в аргументе.

{% set name = "king Artur" -%}
{% if name is matching(pat="^[Qq]ueen") %}
Her Royal Highness, {{ name }}!
{% elif name is matching(pat="^[Kk]ing") %}
His Royal Highness, {{ name }}!
{% else %}
Hi {{ name }}!
{% endif %}

Подробное описание синтаксиса регулярных выражений можно найти на этом
ресурсе:

crate regex: syntax

uinteger, integer, float, number
  • uinteger - Проверяет значение на то, что это целое положительное
    число (unassigned integer), те есть, целое без знака (целое
    положительное число).
  • integer - Проверяет значение на то, что это целое число (знак уже
    не играет роли, то есть, отрицательное целое число тоже пройдёт
    проверку).
  • float - Проверяет значение на то, что это число с плавающей
    точкой (если попадётся целое число, то оно не пройдёт проверку,
    пройдут только числа с плавающей точкой).
  • number - Проверяет значение на то, что это число (любое число,
    знак или плавающая точка - не играют роли).
map, array, string, boolean, null

Вернут true, если значение является соответственно: Маппингом,
Массивом, строкой, логическим (true/false), пустым значением
(null).

{% set d = {"key1": "value1"} %}
{{ d is map }}{# напечатает true #}
{{ d is array }}{# напечатает false, так как `d` не является
Массивом #}

Встроенные Функции

range

По-русски "диапазон". Возвращает Массив целых чисел, созданный с
использованием приведенных аргументов. Есть 3 аргумента, все целые
числа:

  • end - остановиться перед, обязательный аргумент (должен быть
    больше чем аргумент start)
  • start - с чего начать, по умолчанию 0
  • step_by - на какое число увеличивать значение, по умолчанию 1
now

По-русски "сейчас". Возвращает локальную дату-время в виде строки или
временную метку в виде целого числа (если запрошено).

Есть 2 не обязательных аргумента, оба логические (true/false) и
оба по умолчанию false:

  • timestamp - возвращать ли временную метку в виде числа вместо
    datetime
  • utc - возвращать ли дату и время UTC вместо локального

Форматирование не встроено в глобальную функцию, но вы можете
использовать date фильтр, подобно этому now() | date(format="%Y")
если вы хотите получить текущий год. Подробнее по формату смотрите
фильтр date.

Если передать timestamp=true, то параметр utc уже не работает.
Он всегда по Гринвичу, и не содержит временной зоны. Поэтому,
эти два параметра взаимоисключающие.
Таймстэмп всегда целое число в секундах, прошедших с даты 1970-01-01,
И, как все целые числа, поддерживает математические операции. Если
вам нужно оперировать с датой, то работайте с ней именно, как с
таймстемпом.

Примеры:

{{ now() }}
напечатает >> 2024-10-17T14:42:48.907501289+03:00
{{ now( timestamp = true ) }}
напечатает >> 1729165368
{{ now( utc = true ) }}
напечатает >> 2024-10-17T11:42:48.907506441+00:00
{{ now( timestamp = true, utc = true ) }}
напечатает >> 1729165368
{{ now( timestamp = true, utc = false ) }}
напечатает >> 1729165368
{{ now() | date() }}
напечатает >> 2024-10-17
{{ now() | date( format = "%Y" ) }}
напечатает >> 2024
{{ now() | date( format = "%d/%m/%Y %H:%M:%S%.6f" ) }}
напечатает >> 17/10/2024 14:42:48.907523
{{ now() | date( format = "%Y%m%d%H%M%S%.6f" ) }}
напечатает >> 20241017144248.907528
{{ now() | date( format = "%Y-%m-%dT%H:%M:%S%.6f" ) }}
напечатает >> 2024-10-17T14:42:48.907532
{{ "2019-09-19T13:18:48.731Z" |
date(format="%Y-%m-%d %H:%M:%S%.6f", timezone="Europe/Moscow") }}
напечатает >> 2024-10-17 17:39:40.511000
{{ "2019-09-19T13:18:48.731Z" |
date(format="%Y-%m-%d %H:%M:%S%.6f", timezone="Asia/Shanghai") }}
напечатает >> 2024-10-17 22:39:40.511000
{{ "2024-10-17T14:39:40.511687132+03:00" |
date(format="%Y-%m-%d %H:%M:%S%.6f", timezone="Europe/Moscow") }}
напечатает >> 2024-10-17 14:39:40.511687
{{ "2024-10-17T14:39:40.511687132+03:00" |
date(format="%Y-%m-%d %H:%M:%S%.6f", timezone="Asia/Shanghai") }}
напечатает >> 2024-10-17 19:39:40.511687
{{ 1648252203 |
date(format="%Y-%m-%d %H:%M:%S%.6f", timezone="Europe/Berlin") }}
напечатает >> 2022-03-26 00:50:03.000000
{{ 0 | date(format="%Y-%m-%d %H:%M:%S%.6f",
timezone="Europe/Moscow") }}
напечатает >> 1970-01-01 03:00:00.000000
{{ now() | date(format="%Y-%m-%d %H:%M:%S%.6f",
timezone="Europe/Moscow") }}
напечатает >> 2024-10-17 14:42:48.907556 <- сейчас в Москве
{{ now() | date(format="%Y-%m-%d %H:%M:%S%.6f",
timezone="Asia/Shanghai") }}
напечатает >> 2024-10-17 19:42:48.907560 <- сейчас в Шанхае
{{ now() | date(format="%Y-%m-%d %H:%M:%S%.6f",
timezone="Europe/Berlin") }}
напечатает >> 2024-10-17 13:42:48.907563 <- сейчас в Берлине
{{ now(timestamp=true)+7*24*60*60 |
date(format="%Y-%m-%d %H:%M:%S%.6f", timezone="Europe/Moscow") }}
напечатает >> 2024-10-24 14:42:48.000000
(+7 дней к текущей дате/времени по Московскому)
log

Два аргумента:

  • message - сообщение в лог, может быть строковым значением, тогда
    выводится как есть, или может быть любым другим значением, тогда
    оно преобразуется в формат JSON с переносами (pretty), после чего
    выводится в лог
  • level - по сути - уровень логирования, варианты: "trace", "debug",
    "info", "warn", "error". Этот параметр не обязателен, по умолчанию
    равен "info"

Для безопасности (чтоб не "завалить" журнал лога), значение message
обрезается до первых 10 000 символов. Если вы хотите больше, то
используйте вывод в файл с помощью фильтра write.

throw

По-русски "бросок, выброс". При столкновении с этой функцией,
рендеринг будет остановлен с выбросом ошибки. Существует только один
строковый аргумент:

  • message - сообщение, отображаемое как ошибка рендеринга
get_random

Возвращает случайное целое число в заданном диапазоне. Есть 2
аргумента, оба целые числа:

  • end - обязательный аргумент
  • start - по умолчанию равно 0, если отсутствует

start является инклюзивным (то есть, может быть возвращен), а end
является эксклюзивным (то есть, не включённым в диапазон - строго
"до").

get_env

Возвращает значение переменной окружения процесса для указанного
имени. Если переменная окружения не найдена, и значение по умолчанию
не задано, то будет ошибка.

  • name - имя переменной среды окружения для поиска, обязательный
    параметр
  • default - значение по умолчанию, на случай, если переменная среды
    окружения не найдена

Если переменная среды окружения найдена, она всегда будет строкой, в
то время, как по умолчанию (default) может быть любого типа.

null

Возвращает null, то есть, пустое значение. Соответствует значению
null в JSON. Можно использовать аналогичные предопределённые
константы: null, Null, none, None. Это всё синонимы "пустоты".

{# Это всё `null`-ы: -#}
{% set val1 = null() %}
{% set val2 = null %}
{% set val3 = Null %}
{% set val4 = none %}
{% set val4 = None %}

Но, лучше везде пользоваться null. Остальные синонимы для обратной
совместимости.

read

Читает файл и возвращает его содержимое в виде строки в кодировке
UTF-8.

{# Читаем файл и сразу парсим json (преобразуем содержимое в объект).
*** Фильтр from_json описан в разделе Фильтры. #}
{%- set data = read(file="something_directory/something_file.json")
| from_json -%}

Можно не только читать и парсить файлы. Фильтр write может
записывать объект в файл (его описание в разделе Фильтры).

nvl

Возвращает первое не пустое значение из переданного списка в аргумент
values. Пустые строки, строки состоящие только из пробелов,
переносов строк и других пустот - считаются пустыми. Также,
считаются пустыми Массивы и Маппинги нулевой длины.

{{ nvl(
values=[null(), "", " ", [], {}, 1.23, "Не пустая строка",]
) }}

Вернётся значение 1.23. Потому что, это первое по порядку не
пустое значение. Если все переданные аргументы пусты или их нет, то
вернётся пустое значение (null).


ООО "КОДЖЕЗ", 2025. Все права защищены.

COGEZ LTD, 2025. All right reserved.


Программа защищена авторским правом действующего законодательства
Российской Федерации, и имеет Свидетельство о государственной
регистрации программы для ЭВМ № 2024681535. Исключительные права
пренадлежат ООО «КОДЖЕЗ». Нелегальное использование, копирование и
распространение преследуется законом.