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 и выложу исходный код.
Этакая смесь phpBB и smarty.
Комментарий для lusever.ru:
Smarty — это бесполезный кусок говна. А phpBB тут причём?
А джанговский (djangoproject.com) шаблонный движок вы не смотрели?
Так же как джанго и питон делают php и абсолютно любые существующие фреймворки на нем — куском говна, так же и джанговский шаблонизатор кхм... интересен.
Класс с __set, __get, __toString-методами? Прикольно.
Интересна реализация подстановок в текстах шаблонов.
yet another template language. Хотел дать ссылку на статью о том, почему _не нужно_ писать энжайны шаблонов (особенно на пхп), да потерял. Ну и бог с ней.
Комментарий для Евгения Степанищева:
В phpbb цикл по массивам реализуется с помощь <!-- ... -->
Комментарий для web.moikrug.ru:
Смотрел. Я не понимаю стремления написать ещё один язык программирования для шаблонов.
Комментарий для ninjacolumbo.ya.ru:
Скоро будет видно :)
Комментарий для unamentem.ya.ru:
Да, бог с ней. Я прочитал немало таких статей. У меня другая точка зрения.
Комментарий для lusever.ru:
Т. е. у меня секции делаются HTML-комментарием, а в phpBB «циклы тоже» делаются HTML-комментарием? Вы мою статью-то читали?
Комментарий для Евгения Степанищева:
Видимо не так понял.
Комментарий для lusever.ru:
Не поздно перечитать :)
Мне нравится Haml.
Идея в том, чтобы объединить HTML и язык шаблона в единый, более удобный язык, в котором не будет ни визуального шума HTML, ни синтаксической «разности импедансов» между языком шаблона и XML-подобной разметкой.
http://en.wikipedia.org/wiki/Haml
Комментарий для alisey.myopenid.com:
Мне нравится скорость обработки. И я не понимаю зачем нужен голый HTML, если всё равно не видно как это выглядит. Например, циклы не видны.
Комментарий для Евгения Степанищева:
Мне тут прекрасно виден цикл:
#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, ассемблер в конце концов.
Комментарий для alisey.myopenid.com:
Он не виден в HTML, поэтому я не понимаю зачем мне нужен язык шаблонизатора, который выглядит как HTML.
Шаблонизаторы пишутся для того, чтобы было удобно менять оформление сайта. Если шаблонизатор был написан так, что он тормозит у меня на shared-хостинге, я его использовать не буду.
Комментарий для Евгения Степанищева:
Вы утверждаете что Haml тормозит на Shared-хостинге? По моему это такое же голословное утверждение, как если бы я сказал что не тормозит.
И, если это сразу не было понятно, я говорил только про синтаксис. Ваша заметка про синтаксис, правильно?
Замечание про «язык шаблонизатора, который выглядит как HTML» я не понял.
Комментарий для lusever.ru:
Бессмысленно сравнивать этот Akyn со Smarty. Они же для совершенно разных ситуаций.
Smarty предполагает ситуацию, когда верстальщик и программер — это два абсолютно разных человека, один из которых боится увидеть код PHP, а другого уже тошнит от HTML. Ради такой заточки в Smarty стольким пожертвовано, что просто ужат. Smarty — это круто, когда сайт ведут между делом, на бегу, а когда сайт тщательно и вдумчиво сопровождает специалист, все плюсы Smarty становятся минусами.
Комментарий для astur.net.ru:
Как человеку, знакомому с PHP, мне Smarty кажется куда более страшным языком программирования (а не шаблонизации), чем PHP :)
Комментарий для alisey.myopenid.com:
Alisey, Haml — это какой-то извращённый еРуби, собственно уши рельс там во всех мантрах видны.
Одно дело, когда язык программирования эмбедят в хтмл шаблоны (когда эмбедят пхп в язык шаблонов пхп — это к Болку хехе), но когда парадигму эмбеднутого руби переносят в отдельный темплейт язык, который потом переносят в другие языки — это какой-то совершенный анальный мазохизм. Особенно если учесть, что руби — ну никак не самый лучший пример для подражания.
Комментарий для unamentem.ya.ru:
Ваши «доводы» сводятся к тому, что Haml говно и Руби говно. Какие-то нифига не убедительные доводы, спробуйте ще.
Конструкция <{$hide}b><{$!hide}i>Текст<{$!hide>/i><{$hide}/b> не очень хорошо читается.
Проблема с ней в том, что $hide — по сути одно условие. А в коде это 4 отдельных условия.
У подхода есть и хорошая сторона, но плохая, на мой взгляд перевешивает.
Комментарий для alisey.myopenid.com:
Да, знаю, что не очень хорошо, именно её и хочется изменить, но пока не знаю как.
Комментарий для alisey.myopenid.com:
Руби не говно, просто он, мягко говоря, «слабо логичен». Например, параноидально классифицируя и объектно-ориентируя всё вокруг, запросто засовывает типичный функциональный код в notoriously известный метод inject. И не слушает заветы старого лингвиста Ларри Уолла: мы не будем совать в языковые примитивы «предложения» — пишите их сами. Haml же — карго-культ вокруг рельсов, которые построены на карго-культе языка руби. Ещё более смешными выглядят попытки «портирования» этого «руби-независимого еРуби» в языки типа PHP, т. е. заточеные _СПЕЦИАЛЬНО_ для эмбеда кода в шаблоны.
Комментарий для alisey.myopenid.com:
Данное условие отражает недостаки Akyn — HTML не парсится, значит найти парный тег невозможно.
Комментарий для Евгения Степанищева:
Болк, замени на: <? if( $hide ) { ?><b><? } else { ?><i><? } ?>Тест<? if( $hide ) { ?></b><? } else { ?></i><? } ?>
Комментарий для unamentem.ya.ru:
Нет.
Комментарий для unamentem.ya.ru:
На PHP, кстати, можно написать понятнее:
<?if ($hide):?><b><?else:?><i><?endif?>Тест<?if ($hide):?></b><?else:?></i><?endif?>
или (сюрприз!) вот так:
<?=$hide ? ’<b>Текст</b>’ : ’<i>Текст</i>’?>
Я в курсе про наличие там тернари оператора, но учить премудрости пхп в своё время не стал (слава богу).
Вот смотри, какое количество минусов в таком куске кода. Во-первых, текст мы пишем два раза — отстой. Ду нот репит ёселф, блаблабла. Следовательно, тебе нужно что-то рубевского блока или кложуры из других языков (далее идёт псевдокод): <?= $hide ? «<b>#{yield}</b>» : «<i>#{yield}</i>» do?>Текст<?end?>
Но мы опять повторяемся. Во-первых, дважды впрыскиваем текст, во-вторых, сам бог велел создать хтмл с повторением тэга, т. е. оборачивающим наш текст. Логично написать так: <?= wrap_with_tag( $hide ? ’b’ : ’i’ ) do?>Текст<?end?>
Фактически, это уже тот самый каргокульт еруби/хамла, потому что от рельсов его почти ничего не отличает. Основная проблема же этого куска — это не хтмл. Проблема номер два — не дай бог нам потребуется добавить атрибут тагу — нужно переписывать хелпер, чтобы он понимал атрибуты.
Чё я хотел сказать-то. В основе любого энжайна темплейтов должна лежать парадигма. Идеология. Практическая задача, требующая уникального решения. В чём парадигма твоего акына?
Коллега, у меня есть шаблонизатор, который развивает твою идею — шаблон вообще не содержит логики, весь HTML содержится в шаблонах и остаётся валидным HTML’ем для IDE и браузеров. Хочу тебе его показать. А? )
Комментарий для Евгения Степанищева:
я считаю что шаблон должен содержать логику. всю логику которая связана с отображением. т. е. движок должен поддерживать и математику, и циклы, и работу со строками, все что хочешь, если этого требует отображение.
пример: я не хочу на уровне кода думать как отобразить список страниц. это не моя проблема как разработчика бизнесс логики. я говорю шаблону что всего страниц 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.
Комментарий для unamentem.ya.ru:
Мы ушли в сторону. Причём в какую-то совершенно не интересную мне область.
Комментарий для vomixamxam.ya.ru:
Давай :) Но я не закончил описывать Акын :)
Комментарий для alexeit.myopenid.com:
Если вам нужен язык шаблонов, поддерживающий математику, логику и т. д., могу порекомедовать PHP, Perl, Ruby, мне очень нравится Python.
Твой хитрый username должен работать: меня иногда комментирует _dofin_, всё ок.
Наверное и сейчас зажигают костры трением со спичками в кармане, те, кому так удобней. Пардон, за иронию.
Комментарий для alexanderich.livejournal.com:
Рассматривать надо задачу, а не сферического коня в вакууме. Вы же исходите из каких-то своих знаний о моей задаче.
Комментарий для Евгения Степанищева:
Болк, так не видно задачи. Есть какие-то рамки, которые выглядят условными — «хочу чтобы мининимум логики». Что такое минимум логики? Почему минимум такой, а не такой? Почему не использовать минимум логики, меняя CSS, например?
Я привёл пример такой логики выше, а не ушёл в сторону. Ты же рассказываешь, как у тебя хитро (но не совсем правильно) работаю в акыне переменные. Вопрос в том, нахрена они вообще?! И почему только переменные? Почему не циклы? Не обычные условия? (Ты ведь даже в своём примере очень криво пытаешься имитировать условие if-then, при этом не признаваясь в себе, что ты, в виду условных рамок, под переменными подразумеваешь в том числе и условный оператор, хоть и крайне неудобный — внятно изложил?)
Комментарий для unamentem.ya.ru:
Давай я до конца всё изложу, а там посмотрим какие вопросы возникнул. Я же объяснил — это первая часть изложения.
Самая здравая мысль была здесь: http://bolknote.ru/all/1929#n5228
Через некоторое время использования самописного шаблонизатора приходит понимание (скорости, гибкости и возможножностей уже не хватает), что лучший шаблонизатор -- это сам PHP, если уметь его грамотно использовать.
Несколько лет тому назад я показал, как это можно делать в шаблонизаторе PHPTemplate: http://forum.dklab.ru/viewtopic.php?t=16364
Комментарий для rin-nas.moikrug.ru:
Видел я проекты на «PHP-шаблонизаторах», один из них — WackoWiki ( http://ru.wikipedia.org/wiki/WackoWiki ), который мне сейчас приходится по работе поддерживать. Никому не пожелаю.
Комментарий для rin-nas.moikrug.ru:
Мне удобно живётся со своим шаблонизатором, я его никому не навязываю. Люди попросили показать что там у меня, я показываю. Обсуждать что-то тут нет никакого смысла, разве что в пределах концепции почему так, а не иначе, но не саму концепцию.
Комментарий для Евгения Степанищева:
Евгений, пусть кажый пользуется тем, что ему удобнее :)
Некоторые мысли в пределах вашей концепции. :)
В прошлом я делал шаблонизатор (похожий на ваш), специально заточеный под HTML -- он автоматически квотирует значения, в зависимости от контекста, обрабатывает условные блоки и даже умеет вставлять и вырезать параметры из URL! Вместо проверки на null у меня идет проверка конструкцией strval($value) === ’’ (удобно использовать значения из $_REQUEST, получается, что ’’, null и false это одно и тоже), а для условного парсинга тага используется служебный атрибут if. Парные таги вместе с содержимым (блоки) вырезаются/невырезаются с помощью служебного атрибута @if в парном таге. На практике пользоваться такой штукой оказалось очень удобно, но пришлось отказаться и вернуться к PHP, т. к. скорость меня не устроила.
Комментарий для rin-nas.moikrug.ru:
«Пусто» у меня это пусто, а null — удаление атрибута/тега, вещи разные :)
Я посмотрел сегодня свои исходники -- с состоянием NULL я слукавил. :)
Поведение для удаления атрибута тага / параметра URL у меня такое же -- удаляется только для NULL. Иначе невозможно послать на сервер пустое значение из поля ввода формы, что неправильно.