Plim — наиболее полный порт шаблонизатора Slim на Python

    Определённо, первые реализации 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-синтаксиса.

    Чтобы окончательно прояснить ситуацию, ниже представлен список всех внесённых изменений в синтаксис:

    1. Slim поддерживает следующие индикаторы строк — " ' ", " =' " и " ==' ". В Plim, апостроф (одинарная кавычка) была заменена на запятую:
      , value
      =, value
      ==, value
      

      Данное изменение было продиктовано тем фактом, что одинарная кавычка является допустимым символом в начале произвольного Python-выражения. Поэтому, следующие plim-выражения будут иметь неоднозначную трактовку (что всегда плохо, когда речь идёт об автоматической трансляции кода):
      / Является ли следующее выражение пустой python-строкой, 
        или оно должно трактоваться как синтаксическая ошибка, 
        связанная с незакрытой одинарной кавычкой?
      
      =''
      
      
      / Является ли следующее выражение python-строкой из одного 
        символа ('u''' - это корректное python-выражение) или оно должно 
        трактоваться как синтаксическая ошибка, связанная с незакрытой 
        тройной кавычкой юникодной строки?
      
      ='u'''
      


      В то же время, символ запятой недопустим в начале любой корректной python-строки, поэтому при его использовании мы получаем однозначную трактовку выражений:
      / Синтаксическая ошибка в runtime, связанная с некорректным 
        mako-выражением ${'} - незакрытая одинарная кавычка.
        Явная ошибка верстальщика.
      
      =,'
      
      
      / Корректная и однозначная конструкция. Генерирует mako-выражение с 
        пустой юникод-строкой, за которым следует один символ пробела.
      
      =,u''
      

    2. В отличие от 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']
      

    3. Как вы могли заметить в прошлом примере, Plim поддерживает динамические выражения в кратких формах тегов (#id.class). Вы также можете переносить выражения в скобках на другую строчку:
      / Внутри скобок отступы не имеют значения
      
      #m${
              c.message.id
      }.msg${
          (
              "test"
          )
      } = do_something_real(
      	'with', 'the', 
      	real, 
      arguments)
      

    4. В Plim, все теги должны использовать нижний регистр букв. Это ограничение было введено для того, чтобы иметь возможность включить в язык поддержку «неявных» литеральных строк, о которых — в следующем пункте списка. Но вы можете догадаться что это такое по следующему примеру:
      doctype 5
      html
        head
          title Page Title
        body
          p
            | Привет! Я - явный текстовый контент, который не нужно парсить.
          p
            Привет! Я - неявный текстовый контент, и меня тоже не нужно парсить.
      

    5. В отличие от 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-диапазона, то вам даже не обязательно
        использовать заглавную букву в начале блока.
      

    6. Вам не нужно использовать символ "|" (пайп — индикатор явного литерала) в тегах style и script;
    7. Plim не делает различий между управляющими конструкциями и фильтрами.
      Например, в Slim вы должны писать "-if", "-for" и так далее — для любой управляющей конструкции, но «coffee:» (без минуса в начале, но с двуеточием в конце) — для любого из доступных фильтров. В Plim, вы используете один и тот же синтаксис: "-if", "-for" и "-coffee".
    8. 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 сменили своё местоположение.
    Поделиться публикацией
    Похожие публикации
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 10
    • +1
      Может шаблонизатор и лаконичен, но как-то добавляет лишнего мусора в текст да и только.
      Иногда
      {% открывающий %}{% закрывающий %}
      

      добавляет читабельности.
      • +2
        нет
        • –3
          Вы один из тех, кто переменные называет p[], а не messagesFromClient[]
      • +1
        Статья вызвала только одно желание: «хочу пощупать и прямо сейчас»!
      • +2
        Статья вызвала только одно желание продолжать юзать django templates и jinja :)
        • 0
          Сначала обрадовался а потом огорчился когда увидел что python 3 не поддерживается. Я тут и mako не смог нормально на 3.2 поставить. Поставился с ошибками, так вроде работает но всё таки не уверен
          • 0
            На уровне бизнес-логики и Mako, и Plim поддерживают Python 3. В случае с Plim проблема состоит в том, что StringIO теперь является субмодулем io. На этой неделе у меня не было времени протестировать пакет в других окружениях, кроме Python 2.7, на котором работают все мои текущие проекты. Я обещаю, что в скором времени сделаю нормальный импорт модулей, который будет работать во всех ветках и отпишу вам в личку.
            • 0
              Ок, ну вообще странно. Я то до сих пор так и не понял как-там установки работают.

              Просто скопировал папку mako в dist-packajes — даже form mako import template не делается, ошибки какие-то. Запустил dist.._setup.py, он мне типа setuptools поставил, с ошибками естественно, после этого запустил setup.py install, тоже завершилось с ошибками но модуль импортился и какие-то базовые операции работали. Не стал на этом работать и просто снёс
              • 0
                Обычно все сторонние пакеты ставятся в site-packages. Но таким ручным способом пакеты устанавливались очень давно. Сейчас все пользуются виртуальными средами virtualenv и специальным менеджером python-пакетов pip. На Хабре было несколько статей по их настройке и использованию, попробуйте найти их через поиск на сайте. После настройки virtualenv и pip, вы сможете автоматически устанавить пакеты всего одной командой:
                pip install Mako, Plim
                

                А для апгрейда до новых версий достаточно будет добавить флаг "--upgrade":
                pip install --upgrade Mako, Plim
                

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.