15. Выражения и шаблоны

Две вкладки окна аргумента, в которых значение не берётся готовым, а вычисляется. Язык вычислений — серверный: редактор его подсвечивает и проверяет, но не исполняет (Выражение, Функция).

Редактор выражения

Редактор выражений с деревом функций
Figure 1. Вкладка «Выражение»

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

Имя переменной пишется в квадратных скобках: [dtmf], [sitedomain]. Строки — в двойных кавычках. Всё остальное — функции и операторы.

Одинарные кавычки — не замена двойным. Синтаксис языка в основе своей эрланговский, и текст в одинарных кавычках становится атомом. Атомы на сервере ограничены и по количеству, и по длине: короткая строка пройдёт, а большой JSON в одинарных кавычках разместить не удастся.

Правило простое: строки — только в двойных кавычках.

Дерево функций

Дерево функций
Figure 2. Раскрытая группа функций

Дерево устроено по разделам: переменные этого сценария, общие функции по темам (математика, строки, дата и время, преобразования, хеши, файлы, доступ), константы и символы, функции конкретного вида сценария.

Рядом с каждой группой — сколько в ней функций. У каждой функции показаны имя и типы параметров: substr (str,int,int). Клик вставляет вызов в текст на место курсора.

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

Переменные сценария лежат в дереве первым разделом. Вставлять их оттуда надёжнее, чем печатать руками: имя подставится ровно так, как оно записано, вместе со скобками.

Переменная без значения

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

Отсюда следствие, о котором стоит знать заранее: сравнить переменную с «ничем» нельзя. [x] == null не работает, потому что до сравнения дело не доходит — падает уже [x].

Наличие значения проверяет отдельная функция, и берёт она имя переменной строкой, а не саму переменную:

check_variable("x")

Истина — если переменная с таким именем существует и содержит значение. Имя здесь пишется строкой в двойных кавычках, а не в квадратных скобках: скобки как раз и означали бы обращение к значению, ради которого всё и затевалось.

В том же семействе есть ещё две функции, которые часто избавляют от проверки вовсе:

  • get_variable_value("x", "") — значение переменной, а если значения нет, второй аргумент. Выражение не падает: вместо исключения возвращается умолчание.

  • set_variable_value_if_undefined("x", "") — задаёт переменной значение, если его ещё нет; заданное не трогает. Одна такая строка в начале избавляет от проверок во всех выражениях после неё.

На практике это встречается реже, чем можно подумать. Компонент Старт по умолчанию заводит переменные с пустыми значениями их типов — ровно для того, чтобы выражения не падали. Проверка нужна там, где это поведение изменено настройкой компонента.

Шаблон

Редактор шаблонов
Figure 3. Вкладка «Шаблон»

Шаблон — это обычный текст, в котором участки в двойных фигурных скобках вычисляются как выражения:

Здравствуйте, {{ str([name]) }}. Ваш баланс {{ str([sum]) }} рублей.

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

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

Запись шаблона

Подстановка — только участок в двойных фигурных скобках. Всё остальное — текст как есть: одинарные фигурные скобки, кавычки, косая черта (путь C:\dir пишется как есть). Тело запроса в формате JSON пишется без всякого экранирования:

{ "code": 200, "text": "{{ str([text]) }}" }

Части шаблона склеиваются строкой: 1{{ [n] }} при n = 2 даёт «12», а не 3. Подстановка вычисляется целиком: x{{ [n] + [m] }} — это «x» и сумма. Две скобки подряд в тексте записываются с косой чертой: \{\{ и \}\}; без неё }} в тексте — ошибка разбора.

Шаблоны прежних версий

Шаблоны, сохранённые прежними версиями, сервер выполняет так же, как прежние версии (до 1.11 — одинарная запись { … }, косая черта как экранирование: \[, \{). Если версии читали шаблон по-разному, он выполняется как до 1.11 (см. ниже).

Открыв такой шаблон, редактор показывает его уже в нынешней записи с тем же значением, и полоса над полем говорит об этом. Переписан шаблон будет, только если вы его измените или выберете, как он задуман, — открыть и закрыть окно можно без последствий.

Иногда прежнее значение неоднозначно, и редактор попросит выбрать, как шаблон задуман:

  • Как до 1.11 или Как в 1.11 — до 1.11 косая черта в тексте была экранированием, в 1.11 — обычным символом. Подсказка под вопросом опирается на время последней записи сценария;

  • Это подстановки или Это текст — шаблон не вычислялся ни в одной версии, а скобки в нём не похожи ни на выражение, ни на JSON.

Пока выбор не сделан, сервер выполняет шаблон так, как отмечено подсказкой у варианта (как до 1.11 или как подстановки), кнопка Сохранить окна недоступна, поле доступно только для чтения, другие вкладки закрыты, а Отменить оставляет шаблон как был. Так же — только чтение и закрытые вкладки — пока шаблон переводится. Если перевести его не удалось, поле шаблона только для чтения, но аргумент можно заменить значением или выражением на другой вкладке; пустое значение там шаблон не стирает.

Что делает редактор

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

Полоса состояния формата шаблона
Figure 4. Полоса над полем: в двойных скобках JSON, а не выражение

Полоса объясняет положение и предлагает правку, но сама текст не трогает. Она держится, пока держится причина, и гаснет, как только шаблон исправлен — в том числе если вы поправили его руками. Полос две:

  • жёлтая — сервер откажется разбирать шаблон (}} в тексте, незакрытая {{) или содержимое двойных скобок выражением не является, например JSON;

  • спокойная — выражение в одинарных скобках: сервер оставит его текстом, а подстановку можно сделать одним нажатием.

Окно с разницей
Figure 5. Окно «Формат шаблона»

Кнопка полосы открывает окно «Формат шаблона»: слева шаблон, каким он сейчас, справа — каким станет, оба тела копируются. Каждая правка меняет смысл намеренно — текст становится подстановкой или подстановка текстом, — и окно говорит об этом прямо.

Отменить возвращает к правке, ничего не изменив. Применить выполняет правку — одним шагом, который отменяется обычным CTRL + Z.

Если вы нажали Сохранить, а жёлтая полоса на экране, окно откроется само и добавит третью кнопку — Оставить как есть. Сохранить шаблон нетронутым можно всегда: последнее слово за вами.

В этом окне появляется и флажок «Так же поступить с остальными шаблонами сценария». Он снят по умолчанию, и это осознанно: правку лучше делать там, где вы её видите. Шаблонов прежних версий флажок не касается.

Проверка на сервере

Свои правила разбора редактор не выдумывает: язык принадлежит серверу, и проверяет выражение он же.

Ошибка проверки выражения
Figure 6. Сервер вернул ошибку

Проверка идёт, когда вы уходите из поля, и ещё раз — при сохранении значения. Ошибка показывается так, как её сформулировал сервер: рамка поля краснеет, под ним появляется сообщение.

Что важно знать:

  • ошибка не запрещает сохранить. Редактор предупреждает, а не сторожит: бывает, что сервер отвечает не то, а работа стоять не должна;

  • при обрыве связи проверки нет. Ответ не пришёл — сообщение не показывается. Отсутствие ошибки при потерянной связи ничего не доказывает;

  • ответ запоминается. Открыв то же выражение снова, вы увидите уже известную ошибку без нового запроса.

Несколько действий в одном выражении

У языка эрланговский синтаксис, и операторы в нём разделяются запятыми. Значением выражения становится последний из них. Это открывает приём, о котором стоит знать заранее, — функцию component.

component выполняет прямо внутри выражения типизированный компонент сценария со свойствами, заполненными здесь же, в редакторе выражений, дожидается его завершения и передаёт управление следующему оператору. То есть кусок сценария можно записать не квадратами на карте, а последовательностью внутри одного аргумента.

Это глубокий приём, а не повседневный. Он уместен там, где рисовать на карте три квадрата ради одного технического шага дороже, чем написать строку, — и неуместен там, где логику потом придётся читать глазами: на карте она видна, внутри выражения нет.

Ограничения тоже есть: произвольные внешние методы эрланга из выражения не вызываются — для этого нужна отдельная настройка разрешений на сервере. Подробности — Выражение и Функция.

Что стоит помнить

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

  • Приведение типов явное: str(…​) для строки, num(…​) для числа. Молчаливого приведения не будет.

  • Переменная без значения роняет выражение, а не даёт ложь: [x] == null не работает. Проверяйте check_variable("x") или берите значение с умолчанием — get_variable_value("x", "").

  • Длинное выражение — повод завести переменную и разбить вычисление на два шага. Читать сценарий будете вы же.

◀ 14. Аргумент

16. Меню и переводы ▶