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 и выложу исходный код.
11 ноября 2008 22:19

lusever.ru (lusever.ru)
11 ноября 2008, 22:57

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

bolk (bolknote.ru)
11 ноября 2008, 23:25, ответ предназначен lusever.ru:

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

web.moikrug.ru (web.moikrug.ru)
11 ноября 2008, 23:52

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

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

ninjacolumbo.ya.ru (ninjacolumbo.ya.ru)
11 ноября 2008, 23:56

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

unamentem.ya.ru (unamentem.ya.ru)
12 ноября 2008, 00:10

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

lusever.ru (lusever.ru)
12 ноября 2008, 08:47, ответ предназначен bolk (bolknote.ru):

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

bolk (bolknote.ru)
12 ноября 2008, 09:49, ответ предназначен web.moikrug.ru:

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

bolk (bolknote.ru)
12 ноября 2008, 09:50, ответ предназначен ninjacolumbo.ya.ru:

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

bolk (bolknote.ru)
12 ноября 2008, 09:50, ответ предназначен unamentem.ya.ru:

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

bolk (bolknote.ru)
12 ноября 2008, 09:51, ответ предназначен lusever.ru:

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

lusever.ru (lusever.ru)
12 ноября 2008, 10:42, ответ предназначен bolk (bolknote.ru):

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

bolk (bolknote.ru)
12 ноября 2008, 10:53, ответ предназначен lusever.ru:

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

Alisey (alisey.myopenid.com)
12 ноября 2008, 12:13

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

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

bolk (bolknote.ru)
12 ноября 2008, 12:46, ответ предназначен Alisey (alisey.myopenid.com):

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

Alisey (alisey.myopenid.com)
12 ноября 2008, 14:23, ответ предназначен bolk (bolknote.ru):

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

    #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, ассемблер в конце концов.

bolk (bolknote.ru)
12 ноября 2008, 16:27, ответ предназначен Alisey (alisey.myopenid.com):

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

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

Alisey (alisey.myopenid.com)
12 ноября 2008, 18:54, ответ предназначен bolk (bolknote.ru):

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

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

astur (astur.net.ru)
12 ноября 2008, 19:10, ответ предназначен lusever.ru:

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

bolk (bolknote.ru)
12 ноября 2008, 19:14, ответ предназначен astur (astur.net.ru):

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

unamentem.ya.ru (unamentem.ya.ru)
12 ноября 2008, 20:20, ответ предназначен Alisey (alisey.myopenid.com):

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

Alisey (alisey.myopenid.com)
12 ноября 2008, 20:52, ответ предназначен unamentem.ya.ru:

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

Alisey (alisey.myopenid.com)
12 ноября 2008, 21:07

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

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

bolk (bolknote.ru)
12 ноября 2008, 23:43, ответ предназначен Alisey (alisey.myopenid.com):

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

unamentem.ya.ru (unamentem.ya.ru)
12 ноября 2008, 23:51, ответ предназначен Alisey (alisey.myopenid.com):

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

bolk (bolknote.ru)
12 ноября 2008, 23:51, ответ предназначен Alisey (alisey.myopenid.com):

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

unamentem.ya.ru (unamentem.ya.ru)
13 ноября 2008, 00:00, ответ предназначен bolk (bolknote.ru):

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

bolk (bolknote.ru)
13 ноября 2008, 00:09, ответ предназначен unamentem.ya.ru:

Нет.

bolk (bolknote.ru)
13 ноября 2008, 00:11, ответ предназначен unamentem.ya.ru:

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

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

unamentem.ya.ru (unamentem.ya.ru)
13 ноября 2008, 00:29

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

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

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

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

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

vomixamxam (vomixamxam.ya.ru)
13 ноября 2008, 03:23

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

alexeit.myopenid.com (alexeit.myopenid.com)
13 ноября 2008, 05:33, ответ предназначен bolk (bolknote.ru):

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

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

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

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

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

bolk (bolknote.ru)
13 ноября 2008, 09:19, ответ предназначен unamentem.ya.ru:

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

bolk (bolknote.ru)
13 ноября 2008, 09:19, ответ предназначен vomixamxam (vomixamxam.ya.ru):

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

bolk (bolknote.ru)
13 ноября 2008, 09:21, ответ предназначен alexeit.myopenid.com:

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

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

alexanderich.livejournal.com (alexanderich.livejournal.com)
13 ноября 2008, 09:49

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

bolk (bolknote.ru)
13 ноября 2008, 11:14, ответ предназначен alexanderich.livejournal.com:

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

unamentem.ya.ru (unamentem.ya.ru)
13 ноября 2008, 13:13, ответ предназначен bolk (bolknote.ru):

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

bolk (bolknote.ru)
13 ноября 2008, 14:17, ответ предназначен unamentem.ya.ru:

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

rin-nas.moikrug.ru (rin-nas.moikrug.ru)
14 ноября 2008, 19:07

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

bolk (bolknote.ru)
15 ноября 2008, 00:19, ответ предназначен rin-nas.moikrug.ru:

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

bolk (bolknote.ru)
15 ноября 2008, 00:20, ответ предназначен rin-nas.moikrug.ru:

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

rin-nas.moikrug.ru (rin-nas.moikrug.ru)
15 ноября 2008, 17:29, ответ предназначен bolk (bolknote.ru):

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

bolk (bolknote.ru)
15 ноября 2008, 22:41, ответ предназначен rin-nas.moikrug.ru:

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

rin-nas.moikrug.ru (rin-nas.moikrug.ru)
20 ноября 2008, 10:22

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

Ваше имя или адрес блога (можно OpenID):

Текст вашего комментария, не HTML:

Кому бы вы хотели ответить (или кликните на его аватару)