Определённо, первые реализации Haml и Slim должны были появиться на Python. Или, по крайней мере, так было бы справедливее.
Cложно представить себе более «питоничный» подход к написанию HTML-разметки, чем тот, который в своё время был предложен этими языками. Синтаксис, основанный на отступах, отсутствие закрывающих символов, общая лаконичность — не эти ли слова можно услышать из уст среднестатистического программиста, рассказывающего кому-то в первый раз о Python?
Но реальность оказалась другой и моё первое знакомство со Slim случилось в тот момент, когда в одном из своих проектов я начал использовать Chef и по этому поводу взялся изучать Ruby. С тех самых пор и до самого последнего времени я ждал, когда в мире Python появится хоть что-то, что по своему качеству приближалось бы к текущей реализации Slim. Но так и не дождавшись, принялся писать своё.
Мотивация
Для Python существует уже достаточно большое количество пакетов, реализующих Haml-подобные языков разметки. Вот лишь некоторые из них:
Так или иначе, все эти проекты уступают оригинальному Slim в степени своей проработанности:
— одни имеют врождённые недостатки синтаксиса, которые уже не исправить, так как проекты имеют сложившуюся аудиторию с большой кодовой базой;
— другие пытаются писать кросс-компиляторы для всех существующих «больших» python-шаблонизаторов, в результате чего одинаково плохо поддерживают синтаксис каждого из них;
— у всех остальных — слишком наивные реализации. Даже slimish-jinja2 (который, по идее, должен поддерживать весь синтаксис Slim) реализован весьма скромно. Обратите внимание, что для парсинга атрибутов тега используется очень наивное регулярное выражение, которое сработает неверно практически с любой python-строкой, содержащей символ "=". Это явно не тот проект, который сегодня можно внедрять в свой отлаженный процесс разработки.
Выходило, что даже при таком объёмном списке пакетов, нам не из чего выбирать, если речь заходит о production-системе. В результате такого неутешительного заключения, было решено написать собственный, production-ready порт оригинального шаблонизатора Slim.
Реализация
Plim — это наиболее полная реализация синтаксиса Slim на Python, созданная поверх шаблонного движка Mako. По своей сути, Plim — это простой препроцессор, который ничего не знает о контексте выполнения (runtime), но который умеет правильно транслировать slim-разметку в корректный mako-шаблон, который затем может быть скомпилирован в Python-модуль и закеширован движком Mako.
Под «наиболее полной реализацией» подразумевается поддержка большинства управляющих конструкций Slim. Однако, следует сразу же уточнить, что Plim — не точный порт языка! Некоторые элементы синтаксиса были убраны, другие были значительно дополнены, а в некоторые конструкции была внесена ясность и однозначность. Но, тем не менее, бОльшая часть синтаксиса не претерпела никаких изменений, поэтому при работе с Plim вы можете использовать существующие плагины для подсветки slim-синтаксиса.
Чтобы окончательно прояснить ситуацию, ниже представлен список всех внесённых изменений в синтаксис:
- Slim поддерживает следующие индикаторы строк — " ' ", " =' " и " ==' ". В Plim, апостроф (одинарная кавычка) была заменена на запятую:
, value =, value ==, value
Данное изменение было продиктовано тем фактом, что одинарная кавычка является допустимым символом в начале произвольного Python-выражения. Поэтому, следующие plim-выражения будут иметь неоднозначную трактовку (что всегда плохо, когда речь идёт об автоматической трансляции кода):
/ Является ли следующее выражение пустой python-строкой, или оно должно трактоваться как синтаксическая ошибка, связанная с незакрытой одинарной кавычкой? ='' / Является ли следующее выражение python-строкой из одного символа ('u''' - это корректное python-выражение) или оно должно трактоваться как синтаксическая ошибка, связанная с незакрытой тройной кавычкой юникодной строки? ='u'''
В то же время, символ запятой недопустим в начале любой корректной python-строки, поэтому при его использовании мы получаем однозначную трактовку выражений:
/ Синтаксическая ошибка в runtime, связанная с некорректным mako-выражением ${'} - незакрытая одинарная кавычка. Явная ошибка верстальщика. =,' / Корректная и однозначная конструкция. Генерирует mako-выражение с пустой юникод-строкой, за которым следует один символ пробела. =,u''
- В отличие от Slim, Plim не поддерживает квадратные и фигурные скобки для выделения атрибутов тегов. Вы можете использовать только круглые скобки.
Данное ограничение упрощает логику алгоритмов некоторых компонентов парсера и вносит в синтаксис некоторый уровень стандартизации, при этом абсолютно не уменьшая его функциональность:/ Для выделения атрибутов вы можете использовать только круглые скобки. p(title="Link Title") h1 class=(item.id == 1 and 'one' or 'unknown') Title / Квадратные и фигурные скобки разрешены только как часть mako- или python-кода a#idx-${item.id} href=item.get_link( **{'argument': 'value'}) = item.attrs['title']
- Как вы могли заметить в прошлом примере, Plim поддерживает динамические выражения
в кратких формах тегов (#id.class). Вы также можете переносить выражения в скобках на другую строчку:/ Внутри скобок отступы не имеют значения #m${ c.message.id }.msg${ ( "test" ) } = do_something_real( 'with', 'the', real, arguments)
- В Plim, все теги должны использовать нижний регистр букв. Это ограничение было введено для того, чтобы иметь возможность включить в язык поддержку «неявных» литеральных строк, о которых — в следующем пункте списка. Но вы можете догадаться что это такое по следующему примеру:
doctype 5 html head title Page Title body p | Привет! Я - явный текстовый контент, который не нужно парсить. p Привет! Я - неявный текстовый контент, и меня тоже не нужно парсить.
- В отличие от Slim, Plim имеет поддержку неявных текстовых блоков. Текстовый блок будет считаться «неявным литералом», если его первая строка начинается с одной из следующих последовательностей символов:
- заглавная латинская буква;
- любая буква из диапазона, не входящего в таблицу ASCII-символов;
- любая цифра, перед которой не символов "+" или "-", которые являются зарезервированными;
- любой закодированный в &-форму HTML-символ. Например —
- mako-выражение, начинающееся с последовательности символов "${";
- открывающая квадратная скобка "[";
- открывающая круглая скобка "(";
- любой юникод-символ, не входящий в диапазон кодов U0021 — U007E (т.е. вне диапазона ASCII 33 — 126, который является зарезервированным парсером).
Вот пример применения неявных текстовых блоков:
p | pipe is the explicit literal indicator. It is required if your line starts with the non-literal character. p I'm the implicit literal, because my first letter is in uppercase. p 1. Digits 2. are 3. the 4. implicit 5. literals 6. too. p ${raw_mako_expression} indicates the implicit literal line. p If subsequent lines do not start with implicit literal indicator, you must indent them | or you can use the "explicit" pipe. p если ваш блок текста написан на русском, или любом другом языке, не использующим символы из ASCII-диапазона, то вам даже не обязательно использовать заглавную букву в начале блока.
- Вам не нужно использовать символ "|" (пайп — индикатор явного литерала) в тегах style и script;
- Plim не делает различий между управляющими конструкциями и фильтрами.
Например, в Slim вы должны писать "-if", "-for" и так далее — для любой управляющей конструкции, но «coffee:» (без минуса в начале, но с двуеточием в конце) — для любого из доступных фильтров. В Plim, вы используете один и тот же синтаксис: "-if", "-for" и "-coffee". - Plim поддерживает HTML-теги! Вам следует только не забывать закрывать их. Внутри тегов работают те же правила парсинга, что и для «чистой» plim-разметки. Эта функциональность бывает особенно полезной, когда вы пытаетесь реализовать что-то похожее на следующий пример:
- if edit_profile / обернуть весь интерфейс в редактируемый блок <div id="edit-profile"> - include new_or_edit_interface.html - if edit_profile / не забываем закрыть тег </div>
Вследствие наличия поддержки HTML-тегов, в Plim не был реализован эквивалент инструкции "/!", с помощью которой Slim генерировал HTML-комментарии. Решение о бесполезности такой конструкции в Plim было принято по причине того, что HTML-комментарии на сегодняшний день используются практически только для conditional-хаков Internet Explorer. Такая незначительная область применения не оправдывает внедрения дополнительных синтаксичечских конструкций в язык разметки, который имеет встроенную поддерживает «нативных» HTML-комментариев.
Как видите, изменения вносились максимально бережно по отношению к оригинальному языку и только в тех местах, где как я считал, присутствовала ненужная «строгость» правил.
Бонусы
Помимо основного синтаксиса, в Plim реализованы:
- Встроенная поддержка CoffeeScript, SCSS/SASS, Markdown и reStructuredText;
- поддержка операторов -unless и -until;
- поддержка булевских атрибутов в виде attr=(bool_dynamic_expr)?;
- краткие формы для всех mako-тегов и управляющих конструкций.
Мета-информация
Подробную и актуальную документацию по всем управляющим конструкциям языка вы можете найти на платформе ReadTheDocs.org (английская версия, есть pdf и epub).
Все предложения и сообщения об ошибках приветствуются в трекере на GitHub.
P.S. Текущая версия тестировалась только на ветке 2.7. Я не уверен (нет необходимого окружения для тестов), но всё должно прекрасно работать и в 2.6. А вот 3.x на данный момент не поддерживается точно. Но это связано лишь с тем, что некоторые пакеты из стандартной библиотеки в Py3K сменили своё местоположение.
Автор: Ghostwriter