вторник, 26 апреля 2011 г.

Движок шаблонов для Clojure

Появилось желание делать сайты на Clojure. Разработка веб-приложений на этом языке отличается тем, что здесь нет унифицированной инфраструктуры, как, например, в J2EE или Ruby on Rails. Каждый волен сам выбирать себе сервер, движок шаблонов, способ доступа к БД и т.д. И если с сервером в основном понятно (это, как правило, ring-based Compojure или Mustache), то с движком шаблонов ситуация не очень. Наиболее известные и используемые в Clojure-комьюнити: hiccup, enlive и fleet. Из всех троих больше всего мне пришелся по душе enlive, но он довольно сложен в освоении и использовании. Особенно портит ситуацию почти полное отсутствие вменяемой документации. Поэтому я решил использовать библиотеку StringTemplate.
Подключить и освоить ее оказалось делом очень простым.
1. Качаем с сайта stringtemplate.org последнюю версию stringtemplate, а с antlr.org -- последнюю версию antlr.
2. Создаем проект leiningen: lein new st-test.
3. В project.clj добавляем зависимости.
         [stringtemplate/stringtemplate "4.0"]
         [antlr/antlr "3.3"]
4. Если сделать сейчас lein deps, то, естественно,библиотеки эти не найдутся. Зато leiningen предложит их добавить в локальный репозиторий (смотри полный вывод команды). Например, в моем случае добавление выглядело так:
mvn install:install-file -DgroupId=antlr -DartifactId=antlr -Dversion=3.3 -Dpackaging=jar -Dfile=/path/to/file
Аналогично и для stringtemplate.
5. Теперь можно выполнить lein deps.
6. Подключим библиотеку:
(ns st-test.core
  (import [org.antlr.stringtemplate StringTemplate]))

(defn template [^String txt  ^java.util.Map context]
  (let [t (StringTemplate. txt)]
    (.setAttributes t context)
    (.toString t)))

7. Сгенерим шаблон:

(template
 "Hello, $name$!
   This is a $if(really_true)$really true $else$ falsy $endif$ test!
   And here is a list: $mylist:{n| <li>$n$</li> }$"
  {"name" "World", "really_true" true, "mylist" ["first" "second"]})

В примере демонстрируется использование как простой замены (name), так и условной (if (really_true)), a также использование foreach для переменной mylist.

Выход функции:
"Hello, World! This is a really true test! And here is a list: <li>first</li> <li>second</li>"

По-моему, очень удобно.

4 комментария:

  1. А Closure Templates от Google не нравятся?

    ОтветитьУдалить
  2. Посмотрел Closure Templates. По-моему, примерно то же самое.

    ОтветитьУдалить
  3. Есть мнение что возможностей StringTemplate недостаточно для серьезного проекта на Clojure http://steve.vinoski.net/pdf/IC-Clojure_Templating_Libraries_Fleet_and_Enlive.pdf

    ОтветитьУдалить
  4. С одной стороны -- да, возможностей у библиотеки не так уж и много. Но вот переходить из-за этого на Enlive или Fleet (с обеими я уже успел наиграться), пожалуй не стану. У Enlive проблема -- ее сложно изучить и использовать. У Fleet: он, вроде, уже не развивается; а кроме того он добавляет слишком много логики в представление.
    Интерес, пожалуй, представляет Google Closure Templates (узнал о ней с подачи archimag'а). Скорее всего, попробую что-нибудь на ней.
    И еще о StringTemplate. Стюарт Сиерра, автор "Practical Clojure" использовал ее для разработки сайта AltLaw.org (на сегодняшний момент сайт уже закрыт). Пруфлинк: https://github.com/stuartsierra/altlaw-template. В последующих обсуждениях движков шаблонов Стюарт неоднократно поддерживал использование StringTemplate для генерации html; Рич Хикки тоже ставил ее в пример всем движкам шаблонов. Пруфлинк: http://groups.google.com/group/clojure/browse_thread/thread/ab7a6a7a14575a96/55565925939312b3.
    Одним словом, думаю, что достаточно хорошая библиотека.

    ОтветитьУдалить