Шаблонизатор VMX::Template — различия между версиями

Материал из YourcmcWiki
Перейти к: навигация, поиск
м
м
Строка 26: Строка 26:
  
 
Путь к переменной теперь может включать в себя числа. Это будут обращения к элементам массивов, в то время как всё остальное — обращения к элементам хешей.
 
Путь к переменной теперь может включать в себя числа. Это будут обращения к элементам массивов, в то время как всё остальное — обращения к элементам хешей.
 +
 +
=== Блоки ===
  
 
Вне блока {block} будет иметь значение ARRAY(0x…), то есть массив всех итераций блока block, а {block.0} будет иметь значение HASH(0x…), то есть первую итерацию блока block.
 
Вне блока {block} будет иметь значение ARRAY(0x…), то есть массив всех итераций блока block, а {block.0} будет иметь значение HASH(0x…), то есть первую итерацию блока block.
Строка 49: Строка 51:
 
К номеру итерации можно обратиться через '''<tt>{var#}</tt>'''.
 
К номеру итерации можно обратиться через '''<tt>{var#}</tt>'''.
  
'''Операторов нет''', но есть функции. Пример:
+
=== Функции ===
 +
 
 +
'''Операторов нет''', фильтров нет, есть функции. Пример:
  
 
<pre><!-- IF OR(function(block.key1),AND(block.key2,block.key3)) --></pre>
 
<pre><!-- IF OR(function(block.key1),AND(block.key2,block.key3)) --></pre>
Строка 69: Строка 73:
 
{s block.key}
 
{s block.key}
 
</pre>
 
</pre>
 +
 +
=== IF ===
  
 
Условный вывод:
 
Условный вывод:
Строка 78: Строка 84:
  
 
ELSIF эквивалентно ELSE IF и ELSEIF.
 
ELSIF эквивалентно ELSE IF и ELSEIF.
 +
 +
=== SET ===
  
 
Запись значения переменной:
 
Запись значения переменной:
Строка 85: Строка 93:
 
<!-- SET block.key = выражение -->
 
<!-- SET block.key = выражение -->
 
</pre>
 
</pre>
 +
 +
=== Включения ===
  
 
Включение другого шаблона также осталось:
 
Включение другого шаблона также осталось:
  
 
<pre><!-- INCLUDE another-file.tpl --></pre>
 
<pre><!-- INCLUDE another-file.tpl --></pre>
 +
 +
По «динамическому» имени шаблона включение производится функцией <tt>INCLUDE</tt> (она же <tt>PARSE</tt>).
  
 
== Функции ==
 
== Функции ==
Строка 100: Строка 112:
 
* I() — преобразует значение к целому числу.
 
* I() — преобразует значение к целому числу.
  
В качестве функции также можно использовать переданный в хеше данных coderef (замыкание, ссылку на функцию, или любое «[http://php.net/manual/en/function.is-callable.php is_callable]» в случае PHP). А если хочется вынести в «функцию» блок кода из шаблона — проще создать отдельный шаблон и вызывать его, предварительно делая <tt>&lt;!-- SET --></tt> именованных аргументов. Это действительно лучше, так как работает и кэширование.
+
Расширяемость в области функций:
 +
 
 +
;Run-time функции: В качестве функции можно использовать переданный в хеше данных coderef (замыкание, ссылку на функцию, или любое «[http://php.net/manual/en/function.is-callable.php is_callable]» в случае PHP). Если же хочется вынести в «функцию» блок кода из шаблона — проще создать отдельный шаблон и вызывать его, предварительно делая <tt>&lt;!-- SET --></tt> именованных аргументов. Это действительно лучше, так как позволяет оптимально работать кэшированию.
 +
;Compile-time функции: При создании объекта шаблона можно передать параметр <tt>compiletime_functions</tt>, равный хешу, в котором ключи — имена дополнительных функций, а значения — любые coderef’ы (Perl) или callable (PHP). Эти функции вызываются в контексте объекта шаблона с параметрами, равными '''коду для вычисления соответствующего аргумента''', и должны возвращать '''код для вычисления результата'''. То есть, они выполняются на этапе компиляции. (пока только PHP-версия)
  
 
=== OR, AND, NOT ===
 
=== OR, AND, NOT ===
Строка 118: Строка 133:
 
Действуют аналогично Perl операторам == eq > < >= <= gt lt ge le.
 
Действуют аналогично Perl операторам == eq > < >= <= gt lt ge le.
  
В PHP-версии на данный момент такого много-безобразия нет, есть просто EQ NE GT LT GE LE.
+
В PHP-версии на данный момент такого много-безобразия нет, есть просто EQ NE GT LT GE LE. Хотя это и имеет свои минусы - если хотя бы один аргумент принимается PHP как численный, сравнение становится численным.
  
 
=== COUNT, SUBARRAY=ARRAY_SLICE, SUBARRAY_DIVMOD ===
 
=== COUNT, SUBARRAY=ARRAY_SLICE, SUBARRAY_DIVMOD ===
Строка 133: Строка 148:
  
 
Соответственно в хеше атрибуты идут парами КЛЮЧ, ЗНАЧЕНИЕ, КЛЮЧ, ЗНАЧЕНИЕ и т.п. (специального синтаксиса "=>" нет).
 
Соответственно в хеше атрибуты идут парами КЛЮЧ, ЗНАЧЕНИЕ, КЛЮЧ, ЗНАЧЕНИЕ и т.п. (специального синтаксиса "=>" нет).
 +
 +
=== SORT ===
 +
 +
Сортировка массива по значениям.
 +
 +
=== ARRAY_MERGE ===
 +
 +
Слить массивы в один. Под Perl — только массивы (не хеши), под PHP — любые массивы.
  
 
=== GET, AGET, HGET ===
 
=== GET, AGET, HGET ===
Строка 138: Строка 161:
 
Получение элемента массива/хэша по «динамическому» ключу. По-моему, это лучше, чем зюки-хрюки Template Toolkit’а: <tt>hash.${hash2.$key}</tt> и т. п.
 
Получение элемента массива/хэша по «динамическому» ключу. По-моему, это лучше, чем зюки-хрюки Template Toolkit’а: <tt>hash.${hash2.$key}</tt> и т. п.
  
GET(откуда, что) автоматически решает, «откуда» — это массив или хеш, AGET служит только для массивов, а HGET только для хешей. В PHP-версии все три идентичны.
+
<tt>GET(откуда, что)</tt> автоматически решает, «откуда» — это массив или хеш, AGET служит только для массивов, а HGET только для хешей. В PHP-версии все три идентичны.
 +
 
 +
<tt>GET(что)</tt> — получение значения переменной верхнего уровня.
  
 
=== MAP ===
 
=== MAP ===
Строка 150: Строка 175:
 
=== STRLIMIT ===
 
=== STRLIMIT ===
  
(пока только PHP-версия, в Perl будет в будущем) Ограничение длины строки s максимальной длиной l — strlimit(s, l). Если строка превышает заданную длину, она обрезается предпочтительно по пробелу или Tab’у, а в конец добавляется «…» (троеточие).
+
Ограничение длины строки s максимальной длиной l — strlimit(s, l). Если строка превышает заданную длину, она обрезается предпочтительно по пробелу или Tab’у, а в конец добавляется «…» (троеточие).
  
=== S=HTML=HTMLSPECIALCHARS, T=STRIP, H=STRIP_UNSAFE ===
+
=== S=HTML=HTMLSPECIALCHARS, T=STRIP, H=STRIP_UNSAFE, NL2BR ===
  
 
Преобразование символов < > & " ' в HTML-сущности.
 
Преобразование символов < > & " ' в HTML-сущности.
Строка 159: Строка 184:
  
 
Удаление только запрещённых тегов.
 
Удаление только запрещённых тегов.
 +
 +
Преобразование переводов строк (\n) в HTML-тег <tt><nowiki><br /></nowiki></tt>.
  
 
=== URI_QUOTE=URIQUOTE=URLENCODE ===
 
=== URI_QUOTE=URIQUOTE=URLENCODE ===
Строка 169: Строка 196:
  
 
Конкатенация элементов массива через разделитель — join(строка, аргументы). Конкатенирует также все элементы всех переданных массивов.
 
Конкатенация элементов массива через разделитель — join(строка, аргументы). Конкатенирует также все элементы всех переданных массивов.
 +
 +
=== SUBSTR=SUBSTRING, STRLEN ===
 +
 +
Стандартная (для всех кроме жавистов стандартная) функция подстроки — substr(строка, начало, длина), или substr(строка, начало). Причём начало и длина могут быть отрицательными, тогда они считаются относительно длины строки.
 +
 +
Ну и функция «длина строки».
  
 
=== Q=QUOTE=ADDSLASHES, REQUOTE=RE_QUOTE=PREG_QUOTE ===
 
=== Q=QUOTE=ADDSLASHES, REQUOTE=RE_QUOTE=PREG_QUOTE ===
Строка 181: Строка 214:
  
 
Разделение строки по регулярному выражению и лимиту — split(RegExp, аргумент, лимит). Лимит необязателен. (см. [http://perldoc.perl.org/functions/split.html perldoc -f split])
 
Разделение строки по регулярному выражению и лимиту — split(RegExp, аргумент, лимит). Лимит необязателен. (см. [http://perldoc.perl.org/functions/split.html perldoc -f split])
 +
 +
=== DUMP, JSON ===
 +
 +
Вывод всех данных из структуры — Dumper в Perl’е и var_dump в PHP.
 +
 +
Форматирование структуры данных в формат JSON. (пока только PHP)
 +
 +
=== INCLUDE=PARSE ===
 +
 +
Включение файла с именем, переданным аргументом.
  
 
=== SUBST, SPRINTF, STRFTIME ===
 
=== SUBST, SPRINTF, STRFTIME ===

Версия 18:22, 29 июля 2010

Данный модуль представляет собой новую версию VMX::Template, построенную на некоторых новых идеях, ликвидировавшую безобразие и legacy-код, накопленный в старой версии, однако сохранившую высокую производительность и простоту.

Есть PHP-версия и Perl-версия шаблонизатора. Реализация, естественно, несколько отличается по причине различий языков — например, в Perl’е для кэширования кода используются coderef’ы, а в PHP предполагается, что кэшированием занимается какой-нибудь XCache или eAccelerator, ибо там сохранить coderef между запросами, по-видимому, невозможно.

Развивается то одна, то другая, в зависимости от проекта, над которым я работаю в моменте.

Также есть простенький (и кривоватенький) файл настроек синтаксиса шаблонов для Midnight Commander'а: tpl.syntax.

Про VMX::Template можно сказать «ох уж эти перлисты — что ни пишут, всё Template::Toolkit получается». Это к тому, что идея вообще-то схожая, но реализация гораздо проще и быстрее.

Идеи

Уйти от assign_vars(), assign_block_vars(). Передавать, как и в обычных движках, просто хеш с данными $vars. Как, например, в Template::Toolkit. При этом сохранить данные методы для совместимости.

Почистить синтаксис: ликвидировать «преобразования», «вложенный путь по переменной» (->key->index->key->и т. п.), специальный синтаксис для окончания SET, неочевидное обращение к счётчику block.#, tr_assign_* и т. п.

Переписать с нуля компилятор.

Добавить в употребление функции, но только самые необходимые.

Добавить обработку ошибок и диагностические сообщения.

Реализация

Маркеры начала и конца кода <!-- --> и подстановки { } могут быть заменены любыми другими. Если, например, вы привыкли к TT, можно установить [% %]. Маркеры подстановки можно вообще убрать, ибо подстановка тоже является кодом.

Путь к переменной теперь может включать в себя числа. Это будут обращения к элементам массивов, в то время как всё остальное — обращения к элементам хешей.

Блоки

Вне блока {block} будет иметь значение ARRAY(0x…), то есть массив всех итераций блока block, а {block.0} будет иметь значение HASH(0x…), то есть первую итерацию блока block.

<!-- BEGIN block -->

Теперь, внутри блока {block} теперь будет иметь значение HASH(0x…), то есть уже значение текущей итерации блока block, а {block.#} будет иметь значением номер текущей итерации блока, отсчитываемый с 0, а не с 1, как в старой версии.

<!-- END block -->

На <!-- END другоеимя --> после <!-- BEGIN block --> шаблонизатор выдаст ошибку, «ибо нефиг» (c). Если block в хеше данных — не массив, а хеш — это значит, что итерация у блока только одна, и тогда <!-- BEGIN block --> работает как for($expression) {} в Perl.

BEGIN ... END — это циклы в «старом стиле». А можно использовать и TT-подобный:

<!-- FOR var = block -->
...
<!-- END -->

Причём, var может быть само block'ом. Это, по сути, и есть то, что делает BEGIN: эквивалентно . Предыдущее значение переменной цикла после выхода из цикла всегда восстанавливается.

К номеру итерации можно обратиться через {var#}.

Функции

Операторов нет, фильтров нет, есть функции. Пример:

<!-- IF OR(function(block.key1),AND(block.key2,block.key3)) -->

Синтаксис вызова функции нескольких аргументов:

<!-- function(block.key, 0, "abc") -->

Подстановка:

{function(block.key, 0, "abc")}

Синтаксис вызова функции одного аргумента:

<!-- function(block.key) -->
<!-- function block.key -->
{block.key/s}
{s block.key}

IF

Условный вывод:

<!-- IF function(block.key) --><!-- ELSEIF ... --><!-- END -->
<!-- IF NOT block.key -->...<!-- END -->                      

ELSIF эквивалентно ELSE IF и ELSEIF.

SET

Запись значения переменной:

<!-- SET block.key -->...<!-- END --></nowiki>
<!-- SET block.key = выражение -->

Включения

Включение другого шаблона также осталось:

<!-- INCLUDE another-file.tpl -->

По «динамическому» имени шаблона включение производится функцией INCLUDE (она же PARSE).

Функции

Note.svg Первое, что обычно нужно — это S(), H(), T(), Q(), I(), то есть «фильтры» для различных преобразований строки:

  • S() — это htmlspecialchars(), экранирует HTML/XML-спецсимволы в строках.
  • H() — удаляет все HTML-теги, кроме «безопасных».
  • T() — удаляет все HTML-теги.
  • Q() — это addslashes(), экранирует символы для использования, например, в JS.
  • I() — преобразует значение к целому числу.

Расширяемость в области функций:

Run-time функции
В качестве функции можно использовать переданный в хеше данных coderef (замыкание, ссылку на функцию, или любое «is_callable» в случае PHP). Если же хочется вынести в «функцию» блок кода из шаблона — проще создать отдельный шаблон и вызывать его, предварительно делая <!-- SET --> именованных аргументов. Это действительно лучше, так как позволяет оптимально работать кэшированию.
Compile-time функции
При создании объекта шаблона можно передать параметр compiletime_functions, равный хешу, в котором ключи — имена дополнительных функций, а значения — любые coderef’ы (Perl) или callable (PHP). Эти функции вызываются в контексте объекта шаблона с параметрами, равными коду для вычисления соответствующего аргумента, и должны возвращать код для вычисления результата. То есть, они выполняются на этапе компиляции. (пока только PHP-версия)

OR, AND, NOT

Логические ИЛИ, И, НЕ, действующие аналогично Perl операторам ||, &&, !.

EVEN, ODD

Истина в случае, если аргумент чётный или нечётный соответственно.

INT=I, ADD, MUL, DIV, MOD, LOG

Преобразование к целому числу, арифметические операции и логарифм.

EQ, NE, SEQ, SNE, GT, LT, GE, LE, SGT, SLT, SGE, SLE

Действуют аналогично Perl операторам == eq > < >= <= gt lt ge le.

В PHP-версии на данный момент такого много-безобразия нет, есть просто EQ NE GT LT GE LE. Хотя это и имеет свои минусы - если хотя бы один аргумент принимается PHP как численный, сравнение становится численным.

COUNT, SUBARRAY=ARRAY_SLICE, SUBARRAY_DIVMOD

Количество элементов массива, или 0, если аргумент — не массив — count(аргумент).

Аналог функции array_slice из PHP.

Выбор из массива каждого div’того элемента, начиная с номера mod или нуля по умолчанию — subarray_divmod(массив, div, mod).

ARRAY, HASH

Создание массива или хэша из всех атрибутов.

Соответственно в хеше атрибуты идут парами КЛЮЧ, ЗНАЧЕНИЕ, КЛЮЧ, ЗНАЧЕНИЕ и т.п. (специального синтаксиса "=>" нет).

SORT

Сортировка массива по значениям.

ARRAY_MERGE

Слить массивы в один. Под Perl — только массивы (не хеши), под PHP — любые массивы.

GET, AGET, HGET

Получение элемента массива/хэша по «динамическому» ключу. По-моему, это лучше, чем зюки-хрюки Template Toolkit’а: hash.${hash2.$key} и т. п.

GET(откуда, что) автоматически решает, «откуда» — это массив или хеш, AGET служит только для массивов, а HGET только для хешей. В PHP-версии все три идентичны.

GET(что) — получение значения переменной верхнего уровня.

MAP

Применение функции, имя которой передано как первый аргумент, ко всем переданным аргументам и элементам всех переданных массивов — map(«имя_функции», аргументы).

LC=LOWER=LOWERCASE, UC=UPPER=UPPERCASE

Нижний и верхний регистр.

STRLIMIT

Ограничение длины строки s максимальной длиной l — strlimit(s, l). Если строка превышает заданную длину, она обрезается предпочтительно по пробелу или Tab’у, а в конец добавляется «…» (троеточие).

S=HTML=HTMLSPECIALCHARS, T=STRIP, H=STRIP_UNSAFE, NL2BR

Преобразование символов < > & " ' в HTML-сущности.

Удаление всех HTML/XML тегов.

Удаление только запрещённых тегов.

Преобразование переводов строк (\n) в HTML-тег <br />.

URI_QUOTE=URIQUOTE=URLENCODE

URL-кодирование строки (URI::Escape в Perl и urlencode() в PHP).

CONCAT, JOIN=IMPLODE

Конкатенация всех своих аргументов — concat(аргументы). Конкатенирует также все элементы всех переданных массивов.

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

SUBSTR=SUBSTRING, STRLEN

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

Ну и функция «длина строки».

Q=QUOTE=ADDSLASHES, REQUOTE=RE_QUOTE=PREG_QUOTE

Экранирование символов " ' \ и перевода строки бэкслэшем — quote(строка).

Экранирование символов, являющихся специальными в регулярных выражениях — re_quote(строка). (см. perldoc perlre).

REPLACE, SPLIT

Замена Perl- (соответственно PCRE- в PHP-версии) регулярного выражения в строке — replace(RegExp, замена, строка).

Разделение строки по регулярному выражению и лимиту — split(RegExp, аргумент, лимит). Лимит необязателен. (см. perldoc -f split)

DUMP, JSON

Вывод всех данных из структуры — Dumper в Perl’е и var_dump в PHP.

Форматирование структуры данных в формат JSON. (пока только PHP)

INCLUDE=PARSE

Включение файла с именем, переданным аргументом.

SUBST, SPRINTF, STRFTIME

Подстановка на места подстрок вида $ЧИСЛО соответствующих параметров функции или элементов переданного массива — subst(строка, $1, $2, …).

Sprintf — он и в Африке sprintf.

Форматирование даты и/или времени с помощью функции strftime — strftime(формат, дата [, часть_даты]). Формат strftime’овский (например, «%d %b %Y»). Дата может передаваться как один или два аргумента, если два — они конкатенируются через пробел. Далее дата разбирается способом, похожим на wfTimestamp() в MediaWiki. Принимается следующее:

  • UNIX время.
  • Времена типа MySQL DATE, MySQL DATETIME, EXIF, ISO 8601, MediaWiki, и любые другие, подпадающие под следующий формат: 1 группа из 4 или более цифр (год) и 2 (месяц, день) или 5 (месяц, день, часы, минуты, секунды) групп по 2 цифры, разделённые любыми нецифровыми символами и в конце — опционально временная зона — 2 цифры, предварённые пробелом, плюсом или минусом. Короче говоря,
    ^\D*(\d{4,})\D*(\d{2})\D*(\d{2})\D*(?:(\d{2})\D*(\d{2})\D*(\d{2})\D*([\+\- ]\d{2}\D*)?)?$
  • Оракловский формат даты-времени: ДД-Мес-ГГ[ГГ] ЧЧ.ММ.СС.
  • RFC 822.