Pull to refresh

Шаблонизатор. Обрамление конструкций

Reading time4 min
Views1.7K
Складывается впечатление, что стандарт синтаксиса шаблона – это то, что мы используем в качестве обрамления управляющих конструкций (скобочки, процентики, вопросики). Это неверно. Символы, в которые мы заключаем ту или иную запись шаблона, это всего лишь способ связать данные с логикой. Тут сложно установить какой-то стандарт. А вот логика воспроизведения той или иной конструкции должна быть заранее оговорена, и именно тогда мы сможем делать совместимые друг с другом шаблоны для разных языков программирования.

Но сегодня мы всё же поговорим про эти самые скобочки. Не забудем и про сигилы для переменных.

Примеров ограничения конструкций шаблонизатора превеликое множество. Угловые, фигурных, квадратные, круглые скобки в сочетаниях друг с другом и с такими символами как %, ?, $, #… В общем вы знаете, что специальных символов достаточно много, а комбинаций их использования еще больше.

<...>


Для наглядного отличия конструкций шаблона от html тэгов лучше использовать не угловые скобки. Но в конструкциях наподобие HTML::Template есть свой шарм, который ценят в определенных кругах. Нужно как-то ограничивать такую группу людей? Не думаю.

[...]


Квадратные скобки неплохо бы использовать в управляющих структурах, например для задания среза массива. В таком случае, в сочетании с [%...%] некоторые управляющие конструкции (например, срез массива) будут терять наглядность:
[% myobj => data.source [3..5] %]

(...)


Круглые скобки мы привыкли использовать для смыслового объединения и разделения фраз. Думается, это будет один из самых неудачных вариантов. Кроме того, наверняка в условных операторах нам придется составлять сложные выражения, и там будет ситуация, аналогичная примеру выше.

{...}


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

<p>{title}</p>
{if expr}
	<span>true</span>
{else}
	<span>false</span>
{endif}

Мы попросту можем нарваться на ситуацию, когда в тексте шаблона встретится {title}, в то время, когда нам не нужно считать это конструкцией шаблона. Сегодня реализации шаблонизаторов предлагают различные решения этой проблемы, вот, например, Django:

{% if expr %}
	<span>true {{title}}</span>
{% else %}
	<span>false {{theme}}</span>
{% endif %}

Но это обилие скобок и процентов восторга не вызывает, особенно когда непривычно по два раза набивать один и тот же символ.

А как же фломастеры?


Как не спорь и не убеждай, а если кто-то привык видеть [%...%], то и не нужно говорить что это плохо. Это вам плохо от двух столовых ложек сахара в чае, а кому-то хорошо. Допустим, что есть возможность использовать одновременно различные варианты обрамления конструкций. Главное соблюдать алгоритм работы шаблона, после обработки его парсером.

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

Сигилы переменных


Префикс-сигилы используются далеко не во всех языках программирования. Кто-то к ним привык, для кого-то это дико. Давайте обозначим один момент. Вот пример кода на perl:
# Наши статические конфигурационные данные
my %cfg = ( 'host' => "http://host"); 
# получаем экземпляр класса шаблонизатора
my $tpl = new MyTpl();
# формируем первый хэш данных; в шаблоне будут использованы конфигурационные даные
my %d1 = ( 'list' => [{},{}], 'cfg' => \%cfg );
# получаем html ...
my $html1 = $tpl->get( 'tpl_name1', \%d1 );
# формируем второй хэш данных, и тоже с использованием конфига
my %d2 = ( 'comments' => [{},{}], 'cfg' => \%cfg );
# получаем очередной кусок html
my $html2 = $tpl->get( 'tpl_name2', \%d2 );

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

<ul>
	{%comments}
		<li>Пользователь {#name} оставил комментарий на сайте {$cfg.domain}</li>
	{/%comments}
</ul>

Где {#name} переменная, принадлежащая итерируемому объекту comments, а переменная {$cfg.domain} взята из конфига. Мы выделили переменную конфига сигилом $, а простую переменную сигилом#Так же можно обратить внимание на то, что в качестве сигила объекта данных (массив хэшей) был использован сигил %.

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

Многие языки программирования поддерживают укороченную запись if / else, что-то наподобие expr? true: false. Немного усовершенствуем и посмотрим что получается в шаблоне:

{? #i > 0}
	{&listarticles}
{|}
	<span>Пусто</span>
{/?}


Такие конструкции уже показали свою практичность, примеры реализации можно посмотреть в приведенном ранее хабратопике Javascript шаблонизатор с серверной частью на perl.

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

Далее мы будет рассматривать уже методы обработки конструкций шаблона. В какие алгоритмы должны превращаться те или иные конструкции. Именно эти алгоритмы воспроизведения конструкций в код должны быть стандартизированы. А уже по ним можно будет писать собственно шаблонизатор. Но прежде неплохо бы узнать, что тут упущено, что нужно скорректировать?
Tags:
Hubs:
Total votes 15: ↑9 and ↓6+3
Comments0

Articles