Введение

МегаФон — динамичная технологическая компания, работа которой не ограничивается исключительно предоставлением услуг связи. Например, среди наших активов есть большое количество интернет-сайтов, на которых клиенты получают различную информацию и услуги. В рамках проекта по совершенствованию и развитию наших веб-проектов мы, в том числе, создаём продукты, которые могут быть полезны и другим разработчикам. Сегодня мы хотели бы представить первый из них — шаблонизатор Histone, который является opensource-проектом, распространяемым по лицензии Apache Software License 2.0. Но обо всём по порядку.

Что такое Histone?

Многие из вас при создании веб-приложений используют различные шаблонные движки. Ситуация, когда из данных, представленных в определенном формате, вам необходимо сгенерировать некий HTML-код при помощи шаблона, задающего правила преобразования, встречается повсеместно. Несколько лет назад шаблонизаторы активно использовались для генерации HTML-кода на сервере (Smarty, FreeMarker, Velocity), сегодня все чаще и чаще возникает необходимость производить генерацию HTML-кода непосредственно в браузере. В качестве примера таких шаблонизаторов можно привести: TrimPath templates, Mustache, Google Closure Templates и т. д.

При всем разнообразии решений, созданных для работы на разных платформах, шаблонизаторов, которые могли бы быть запущены одновременно и на сервере, и в веб-браузере, существует не так много. У каждого из них есть как свои плюсы, так и существенные минусы. Некоторые из этих минусов, по нашему мнению, являются критичными, что не позволяет в полной мере насладиться всеми преимуществами шаблонного движка, работающего как на сервере, так и в веб-браузере.

Проект «Histone» — это попытка создать новый кроссплатформенный шаблонизатор с открытым исходным кодом в реализациях для языков Java, JavaScript и PHP. Прежде чем приступить к разработке собственного решения, мы изучили преимущества и недостатки уже существующих кроссплатформенных шаблонизаторов. Мы анализировали только популярные шаблонизаторы, широко используемые для построения современных веб-приложений, и не рассматривали решения, у которых нет хотя бы двух из трех интересующих нас реализаций (Java, JavaScript, PHP).
Плюсы Минусы
Google Closure Templates — Исходный код шаблона компилируется в JavaScript, что ускоряет его обработку. — Для использования шаблона его необходимо предварительно обработать с помощью специальной утилиты. Это существенно усложняет разработку браузерных приложений, поскольку при внесении любого изменения в шаблон он должен быть перекомпилирован.

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

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

— Нет PHP-версии
Mustache — Существует во всех возможных вариациях для множества языков программирования. — Нетрадиционный синтаксис, сложный для понимания дизайнерами шаблонов.

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

— Механизм расширения очень плохо документирован.

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

  • Один шаблон — множество имплементаций шаблонизатора. Синтаксис шаблона не зависит от языка программирования, который используется для его обработки. Это необходимо для того, чтобы одни и те же шаблоны можно было обрабатывать как на сервере, так и в браузере и получать при этом один и тот же результат.
  • Традиционный и интуитивно понятный синтаксис. Конструкции, обрабатываемые шаблонизатором, помещаются между разделителями {{ и }}, все остальное попадает в результат обработки шаблона «as is».
  • Невозможность выполнения кода напрямую из шаблона. Многие шаблонизаторы могут выполнять код соответствующего языка программирования напрямую из шаблона. Это не позволяет использовать такой шаблон со вставками кода специфического языка в имплементациях на других языках. Поэтому такая возможность в Histone полностью исключена.
  • Простота расширения. Вне зависимости от языка программирования, который используется для обработки шаблона, предоставляемый API позволяет добавить новую функцию или свойство для её использования в шаблоне в целях удовлетворения потребностей любого проекта.
  • Возможность использования одного источника данных для шаблонов, обрабатываемых на разных платформах. Универсальным форматом данных, для поддержки которого в Histone существует все необходимое, является JSON. Вне зависимости от того, каким набором типов данных обладает язык имплементации, язык шаблона позволяет работать с подмножеством типов данных, определенных для формата JSON.
  • Предоставление шаблону данных об окружении, в котором он запущен. Шаблону предоставляется специфическая информация о платформе, на которой происходит его обработка. К примеру, в случае обработки в браузере, шаблону доступна информация о разрешении экрана или размере окна браузера, а в случае обработки на сервере шаблон может получить данные об операционной системе или серверных заголовках запроса.
  • Кроссплатформенность и простота портирования. Реализации для языков JavaScript, Java и PHP доступны «из коробки». Отказ от использования специфических внешних библиотек наравне с логичной организацией кода позволяет произвести портирование реализации Histone на любой другой язык программирования, к примеру, C++, Ruby, Objective-C, ActionScript и т. д.
  • Производительность. В отличие от Google Closure Templates, Histone не производит преобразование кода шаблона в исходный код того языка программирования, на котором планируется его обработка. Вместо этого существует возможность с помощью специальной утилиты, входящей в состав продукта, скомпилировать исходный код шаблона в форму, исполнение которой будет происходить, минуя этап его разбора и парсинга (самой дорогостоящей операции). Кроме того, на данном этапе происходит выполнение тех частей шаблона, которые не зависят от функций, свойств и переменных, определенных извне.

Архитектура

В составе шаблонизатора можно выделить три взаимосвязанных компонента:

  • Лексический анализатор. Производит разбор строки шаблона на токены (последовательности символов исходной строки, объединённые в группы). Создан с использованием встроенного в язык реализации движка регулярных выражений.
  • Синтаксический анализатор. Производит синтаксический анализ строки шаблона, результатом которого является абстрактное синтаксическое дерево, отражающее синтаксическую структуру входной последовательности. Создан при помощи алгоритма рекурсивного спуска.
  • Интерпретатор. Производит исполнение инструкций абстрактного синтаксического дерева, в ходе которого генерируется результат обработки шаблона. Самая главная часть шаблонизатора, которая производит арифметические операции, вызовы функций, чтение свойств и т. д.

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

Синтаксис шаблонов

Шаблон — это текстовый документ со вставками специальных шаблонных тэгов, содержимое которых будет выполнено шаблонизатором в процессе обработки шаблона. Шаблонные тэги — это конструкции языка шаблонов, заключенные между символами {{ и }}. Фрагменты текстового документа вне этих символов будут переданы в результат обработки шаблона без изменений.

Основы синтаксиса
Описание Пример
Комментарии {{* комментарий *}}
Предотвращение обработки {{% {{2 * 2}} %}}
Вывод значений свойств или переменных {{myValue}}
{{myProp.foo.bar}}
{{myObject[«foo»].bar}}
Вызов функций и макросов {{loadText(«file.txt»)}}
{{global.min(10, 20, 30)}}
{{myMacro(«foo», «bar»)}}
Вызов методов {{«string».toUpperCase()}}
{{123.isNumber()}}

Типы данных
Описание Пример
Значение не определено {{undefined}}
Значение отсутствует {{null}}
Булевы {{true}}
{{false}}
Числа {{10}}
{{3.14}}
{{12E-4}}
Строки {{«string»}}
{{'string'}}
Массивы {{[1, 2, 3]}}
{{[«foo»: «bar»]}}

Операции
Описание Пример
Сложение {{10 + 2}}
Вычитание {{10 — 2}}
Умножение {{10 * 2}}
Деление {{10 / 2}}
Остаток от деления {{10 mod 2}}
Унарный минус {{-10}}
Равно {{10 is 10}}
Не равно {{10 isNot 2}}
Больше {{10 > 2}}
Меньше {{2 < 10}}
Больше либо равно {{10 >= 2}}
Меньше либо равно {{2 <= 10}}
Логическое «ИЛИ» {{true or false}}
Логическое «И» {{true and false}}
Логическое «НЕ» {{not true}}
Тернарный оператор {{true? true: false}}

Конструкции
Описание Пример
Объявление переменной {{var myVar = 10}}

{{var myVar}}

{{/var}}
Условие {{if true}}

{{elseif 42}}

{{else}}

{{/if}}
Цикл {{for value in values}}

{{/for}}

{{for key:value in values}}

{{/for}}
Макросы {{macro myMacro(arg1, arg2)}}

{{/macro}}
Импорт шаблона {{import «common.tpl»}}
Вызов функции или макроса {{call myProc(«arg1», «arg2»)}}
arg3
{{/call}}

Заключение

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

Вы можете принять активное участие в развитии проекта и применить его в своих ресурсах. Наша команда с радостью ответит на все возникшие вопросы.

Ссылки