Это сайт — моя персональная записная книжка. Интересна мне, по большей части, история, своя жизнь и немного программирование.

Akyn: синтаксис (переменные)

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

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

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

<!--имя секции-->
HTML-код секции
<!--/имя секции-->

Самое простое, что есть в шаблоне — переменные. Они записываются как {$name}. Переменная уникальна в своей секции или шаблоне (если шаблон без секций). Установить переменную можно присвоив шаблону свойство с её именем. У меня открытие шаблона сделано в глобальном toolkit и всё описанное выглядит вот так:

$t = rt::t('menu', 'меню сверху');
$t->link = '/';
echo $t;

В данном примере в секции «меню сверху» шаблона «menu» переменной link я присвоил значение ’/’. Шаблон выполнится при любом преобразовании объекта в string (например, когда я сделаю echo). Если переменной присвоить null, то атрибут тега, в котором она находится пропадёт. А если переменная входит в тег, то удалится сам тег. В следующем шаблоне, если я присвою переменной «hide» null, пропадёт тег «b» и атрибут title тега «a»:

<a href="/" title="{$hide}"><{$hide}b>текст<{$hide}/b>

Минимальная логика, которая есть в шаблоне на данный момент — возможность подстановки значения переменных из списка и отрицание переменной. Выглядит это вот так: {$var?value1?value2?value3}, значений valueN может быть сколько угодно, нумерация начинается с нуля, значения выбираются по номеру (для тех кто в теме — и по модулю длины выбираемой последовательности). Пустое значение считается null-значением, со всеми его свойствами, которые я рассмотрел выше.

Частный случай такой конструкции — конструкция {$!var}, которая на значение эквивалентное false вернёт пусто (не null), а на значение эквивалентное true — null.

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

<{$hide}b><{$!hide}i>Текст<{$!hide>/i><{$hide}/b>

тут, в зависимости от состояния переменной hide, появится либо тег «b», либо «i».

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

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

44 комментария
lusever.ru 2008

Этакая смесь phpBB и smarty.

Евгений Степанищев (bolknote.ru) 2008

Комментарий для lusever.ru:

Smarty — это бесполезный кусок говна. А phpBB тут причём?

web.moikrug.ru 2008

А джанговский (djangoproject.com) шаблонный движок вы не смотрели?

Так же как джанго и питон делают php и абсолютно любые существующие фреймворки на нем — куском говна, так же и джанговский шаблонизатор кхм... интересен.

ninjacolumbo.ya.ru 2008

Класс с __set, __get, __toString-методами? Прикольно.
Интересна реализация подстановок в текстах шаблонов.

unamentem.ya.ru 2008

yet another template language. Хотел дать ссылку на статью о том, почему _не нужно_ писать энжайны шаблонов (особенно на пхп), да потерял. Ну и бог с ней.

lusever.ru 2008

Комментарий для Евгения Степанищева:

В phpbb цикл по массивам реализуется с помощь <!-​-​ ... -​-​>

Евгений Степанищев (bolknote.ru) 2008

Комментарий для web.moikrug.ru:

Смотрел. Я не понимаю стремления написать ещё один язык программирования для шаблонов.

Евгений Степанищев (bolknote.ru) 2008

Комментарий для ninjacolumbo.ya.ru:

Скоро будет видно :)

Евгений Степанищев (bolknote.ru) 2008

Комментарий для unamentem.ya.ru:

Да, бог с ней. Я прочитал немало таких статей. У меня другая точка зрения.

Евгений Степанищев (bolknote.ru) 2008

Комментарий для lusever.ru:

Т. е. у меня секции делаются HTML-комментарием, а в phpBB «циклы тоже» делаются HTML-комментарием? Вы мою статью-то читали?

lusever.ru 2008

Комментарий для Евгения Степанищева:

Видимо не так понял.

Евгений Степанищев (bolknote.ru) 2008

Комментарий для lusever.ru:

Не поздно перечитать :)

Alisey (alisey.myopenid.com) 2008

Мне нравится Haml.
Идея в том, чтобы объединить HTML и язык шаблона в единый, более удобный язык, в котором не будет ни визуального шума HTML, ни синтаксической «разности импедансов» между языком шаблона и XML-подобной разметкой.

http://en.wikipedia.org/wiki/Haml

Евгений Степанищев (bolknote.ru) 2008

Комментарий для alisey.myopenid.com:

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

Alisey (alisey.myopenid.com) 2008

Комментарий для Евгения Степанищева:

Мне тут прекрасно виден цикл:

    #content
      — @entries.each do |entry|
        .entry
          %h3.title= entry.title
          %p.date= entry.posted.strftime(«%A, %B %d, %Y»)
          %p.body= entry.body

Шаблонизаторы пишутся для удобства программирования и чтения, а не для того чтоб ускорить код. Ну а скорость — это OCalm, C, ассемблер в конце концов.

Евгений Степанищев (bolknote.ru) 2008

Комментарий для alisey.myopenid.com:

Он не виден в HTML, поэтому я не понимаю зачем мне нужен язык шаблонизатора, который выглядит как HTML.

Шаблонизаторы пишутся для того, чтобы было удобно менять оформление сайта. Если шаблонизатор был написан так, что он тормозит у меня на shared-хостинге, я его использовать не буду.

Alisey (alisey.myopenid.com) 2008

Комментарий для Евгения Степанищева:

Если шаблонизатор был написан так, что он тормозит у меня на shared-хостинге, я его использовать не буду.

Вы утверждаете что Haml тормозит на Shared-хостинге? По моему это такое же голословное утверждение, как если бы я сказал что не тормозит.
И, если это сразу не было понятно, я говорил только про синтаксис. Ваша заметка про синтаксис, правильно?

Замечание про «язык шаблонизатора, который выглядит как HTML» я не понял.

astur (astur.net.ru) 2008

Комментарий для lusever.ru:

Бессмысленно сравнивать этот Akyn со Smarty. Они же для совершенно разных ситуаций.
Smarty предполагает ситуацию, когда верстальщик и программер — это два абсолютно разных человека, один из которых боится увидеть код PHP, а другого уже тошнит от HTML. Ради такой заточки в Smarty стольким пожертвовано, что просто ужат. Smarty  — это круто, когда сайт ведут между делом, на бегу, а когда сайт тщательно и вдумчиво сопровождает специалист, все плюсы Smarty становятся минусами.

Евгений Степанищев (bolknote.ru) 2008

Комментарий для astur.net.ru:

Как человеку, знакомому с PHP, мне Smarty кажется куда более страшным языком программирования (а не шаблонизации), чем PHP :)

unamentem.ya.ru 2008

Комментарий для alisey.myopenid.com:

Alisey, Haml — это какой-то извращённый еРуби, собственно уши рельс там во всех мантрах видны.
Одно дело, когда язык программирования эмбедят в хтмл шаблоны (когда эмбедят пхп в язык шаблонов пхп — это к Болку хехе), но когда парадигму эмбеднутого руби переносят в отдельный темплейт язык, который потом переносят в другие языки — это какой-то совершенный анальный мазохизм. Особенно если учесть, что руби — ну никак не самый лучший пример для подражания.

Alisey (alisey.myopenid.com) 2008

Комментарий для unamentem.ya.ru:

Ваши «доводы» сводятся к тому, что Haml говно и Руби говно. Какие-то нифига не убедительные доводы, спробуйте ще.

Alisey (alisey.myopenid.com) 2008

Конструкция <{$hide}b><{$!hide}i>Текст<{$!hide>/i><{$hide}/b> не очень хорошо читается.
Проблема с ней в том, что $hide — по сути одно условие. А в коде это 4 отдельных условия.

У подхода есть и хорошая сторона, но плохая, на мой взгляд перевешивает.

Евгений Степанищев (bolknote.ru) 2008

Комментарий для alisey.myopenid.com:

Да, знаю, что не очень хорошо, именно её и хочется изменить, но пока не знаю как.

unamentem.ya.ru 2008

Комментарий для alisey.myopenid.com:

Руби не говно, просто он, мягко говоря, «слабо логичен». Например, параноидально классифицируя и объектно-ориентируя всё вокруг, запросто засовывает типичный функциональный код в notoriously известный метод inject. И не слушает заветы старого лингвиста Ларри Уолла: мы не будем совать в языковые примитивы «предложения» — пишите их сами. Haml же — карго-культ вокруг рельсов, которые построены на карго-культе языка руби. Ещё более смешными выглядят попытки «портирования» этого «руби-независимого еРуби» в языки типа PHP, т. е. заточеные _СПЕЦИАЛЬНО_ для эмбеда кода в шаблоны.

Евгений Степанищев (bolknote.ru) 2008

Комментарий для alisey.myopenid.com:

Данное условие отражает недостаки Akyn — HTML не парсится, значит найти парный тег невозможно.

unamentem.ya.ru 2008

Комментарий для Евгения Степанищева:

Болк, замени на: <? if( $hide ) { ?><b><? } else { ?><i><? } ?>Тест<? if( $hide ) { ?></b><? } else { ?></i><? } ?>

Евгений Степанищев (bolknote.ru) 2008

Комментарий для unamentem.ya.ru:

Нет.

Евгений Степанищев (bolknote.ru) 2008

Комментарий для unamentem.ya.ru:

На PHP, кстати, можно написать понятнее:

<?if ($hide):?><b><?else:?><i><?endif?>Тест<?if ($hide):?></b><?else:?></i><?endif?>
или (сюрприз!) вот так:
<?=$hide ? ’<b>Текст</b>’ : ’<i>Текст</i>’?>

unamentem.ya.ru 2008

Я в курсе про наличие там тернари оператора, но учить премудрости пхп в своё время не стал (слава богу).

Вот смотри, какое количество минусов в таком куске кода. Во-первых, текст мы пишем два раза — отстой. Ду нот репит ёселф, блаблабла. Следовательно, тебе нужно что-то рубевского блока или кложуры из других языков (далее идёт псевдокод): <?= $hide ? «<b>#{yield}</b>» : «<i>#{yield}</i>» do?>Текст<?end?>

Но мы опять повторяемся. Во-первых, дважды впрыскиваем текст, во-вторых, сам бог велел создать хтмл с повторением тэга, т. е. оборачивающим наш текст. Логично написать так: <?= wrap_with_tag( $hide ? ’b’ : ’i’ ) do?>Текст<?end?>

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

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

vomixamxam (vomixamxam.ya.ru) 2008

Коллега, у меня есть шаблонизатор, который развивает твою идею — шаблон вообще не содержит логики, весь HTML содержится в шаблонах и остаётся валидным HTML’ем для IDE и браузеров. Хочу тебе его показать. А? )

alexeit.myopenid.com 2008

Комментарий для Евгения Степанищева:

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

пример: я не хочу на уровне кода думать как отобразить список страниц. это не моя проблема как разработчика бизнесс логики. я говорю шаблону что всего страниц 20, сейчас открыта страница номер 7, ссылка на страницу следующая « http://example.com/users.php?page=%22​. дальше шаблон уже сам думает или нарисовать это вот так
12 ... 6[7]8 ... 19 20, или сделать дропдаун, или сделать 1 next >.

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

сам использую php -> xml * xslt -> html

ps: где-то пол года ждал когда же я смогу тут комментировать используя мой хитрый юзернейм из ЖЖ (_alexei_). не работает поддержка таких open id у тебя. сколько раз уже хотел прокоментировать, но забивал, сегодня решил сделать наконец простой open id.

Евгений Степанищев (bolknote.ru) 2008

Комментарий для unamentem.ya.ru:

Мы ушли в сторону. Причём в какую-то совершенно не интересную мне область.

Евгений Степанищев (bolknote.ru) 2008

Комментарий для vomixamxam.ya.ru:

Давай :) Но я не закончил описывать Акын :)

Евгений Степанищев (bolknote.ru) 2008

Комментарий для alexeit.myopenid.com:

Если вам нужен язык шаблонов, поддерживающий математику, логику и т. д., могу порекомедовать PHP, Perl, Ruby, мне очень нравится Python.

Твой хитрый username должен работать: меня иногда комментирует _dofin_, всё ок.

alexanderich.livejournal.com 2008

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

Евгений Степанищев (bolknote.ru) 2008

Комментарий для alexanderich.livejournal.com:

Рассматривать надо задачу, а не сферического коня в вакууме. Вы же исходите из каких-то своих знаний о моей задаче.

unamentem.ya.ru 2008

Комментарий для Евгения Степанищева:

Болк, так не видно задачи. Есть какие-то рамки, которые выглядят условными — «хочу чтобы мининимум логики». Что такое минимум логики? Почему минимум такой, а не такой? Почему не использовать минимум логики, меняя CSS, например?
Я привёл пример такой логики выше, а не ушёл в сторону. Ты же рассказываешь, как у тебя хитро (но не совсем правильно) работаю в акыне переменные. Вопрос в том, нахрена они вообще?! И почему только переменные? Почему не циклы? Не обычные условия? (Ты ведь даже в своём примере очень криво пытаешься имитировать условие if-then, при этом не признаваясь в себе, что ты, в виду условных рамок, под переменными подразумеваешь в том числе и условный оператор, хоть и крайне неудобный — внятно изложил?)

Евгений Степанищев (bolknote.ru) 2008

Комментарий для unamentem.ya.ru:

Давай я до конца всё изложу, а там посмотрим какие вопросы возникнул. Я же объяснил — это первая часть изложения.

rin-nas.moikrug.ru 2008

Самая здравая мысль была здесь: http://bolknote.ru/all/1929#n5228
Через некоторое время использования самописного шаблонизатора приходит понимание (скорости, гибкости и возможножностей уже не хватает), что лучший шаблонизатор -​-​ это сам PHP, если уметь его грамотно использовать.
Несколько лет тому назад я показал, как это можно делать в шаблонизаторе PHPTemplate: http://forum.dklab.ru/viewtopic.php?t=16364

Евгений Степанищев (bolknote.ru) 2008

Комментарий для rin-nas.moikrug.ru:

Видел я проекты на «PHP-шаблонизаторах», один из них — WackoWiki ( http://ru.wikipedia.org/wiki/WackoWiki ), который мне сейчас приходится по работе поддерживать. Никому не пожелаю.

Евгений Степанищев (bolknote.ru) 2008

Комментарий для rin-nas.moikrug.ru:

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

rin-nas.moikrug.ru 2008

Комментарий для Евгения Степанищева:

Евгений, пусть кажый пользуется тем, что ему удобнее :)

Если переменной присвоить null, то атрибут тега, в котором она находится пропадёт. А если переменная входит в тег, то удалится сам тег.

Некоторые мысли в пределах вашей концепции. :)
В прошлом я делал шаблонизатор (похожий на ваш), специально заточеный под HTML -​-​ он автоматически квотирует значения, в зависимости от контекста, обрабатывает условные блоки и даже умеет вставлять и вырезать параметры из URL! Вместо проверки на null у меня идет проверка конструкцией strval($value) === ’’ (удобно использовать значения из $_REQUEST, получается, что ’’, null и false это одно и тоже), а для условного парсинга тага используется служебный атрибут if. Парные таги вместе с содержимым (блоки) вырезаются/невырезаются с помощью служебного атрибута @if в парном таге. На практике пользоваться такой штукой оказалось очень удобно, но пришлось отказаться и вернуться к PHP, т. к. скорость меня не устроила.

Евгений Степанищев (bolknote.ru) 2008

Комментарий для rin-nas.moikrug.ru:

«Пусто» у меня это пусто, а null — удаление атрибута/тега, вещи разные :)

rin-nas.moikrug.ru 2008

Я посмотрел сегодня свои исходники -​-​ с состоянием NULL я слукавил. :)
Поведение для удаления атрибута тага / параметра URL у меня такое же -​-​ удаляется только для NULL. Иначе невозможно послать на сервер пустое значение из поля ввода формы, что неправильно.