Библиотека сайта rus-linux.net
Фреймворк Yesod
Глава 22 из книги "Архитектура приложений с открытым исходным кодом", том 2.
Оригинал: Yesod
Автор: Michael Snoyman
Перевод: Н.Ромоданов
22.3. Шаблоны
В типичной парадигме Model-View-Controller (MVC), одной из целей является отделение логики обработки данных от представления данных. Часть этого разделения достигается за счет использования шаблонов языка. Однако, есть много разных способов решения этого вопроса. На одном конце спектра, например, в PHP / ASP / JSP вам разрешается вставлять в ваш шаблон произвольный код. На другом конце, у вас есть системы, такие как StringTemplate и QuickSilver, в которые передаются некоторые аргументы и нет никакого другого способа взаимодействия с остальной частью программы.
В каждой системе есть свои плюсы и минусы. Когда есть более мощная система шаблонов, то это может быть очень удобно. Нужно показать содержимое таблицы базы данных? Нет проблем, вытащите ее с помощью шаблона. Тем не менее, такой подход может быстро привести к запутанному коду, в котором обновления курсора базы данных перемежается с генерацией кода я с HTML. Это можно часто видеть в плохо написанных проектах ASP.
Хотя слабые системы шаблонов упрощают кодирование, они также заставляют делать очень много лишней работы. Часто вам будет нужно не только сохранить ваши исходные значения в типах данных, но и создавать словари значений, которые будут передаваться в шаблон. Поддержка такого кода является непростой задачей и, как правило, у компилятора нет никакого способа помочь вам.
Семейство Yesod языков шаблонов, Shakespearean (Шекспировских) языков, стремится к золотой середине. Используя стандартную в языке Haskell прозрачность ссылок, мы можем быть уверены, что наши шаблоны не дают побочных эффектов. Тем не менее, у них у всех все еще есть полный доступ ко всем переменным и функциям, доступным в коде Haskell. Кроме того, поскольку они во время компиляции полностью проверяются как на корректность и диапазон значений, так и на безопасность типов, вероятность наличия ошибок из-за опечаток гораздо менее вероятна, чем когда вы просто просматриваете код с целью выявить ошибки.
Почему Shakespeare (Шекспир)?
Язык HTML, Hamlet (Гамлет), был первым написанным языком, синтаксис которого базировался на языке Haml. Поскольку это было во времена «сокращенного варианта» Haml, язык Hamlet казался более подходящим. Когда мы добавили CSS и Javascript, мы решили продолжить тему именования и назвали варианты Cassius (Кассий) и Julius (Юлий). На данный момент, язык Hamlet не похож Haml, но, тем не менее, название прижилось.
Типы
Одной из важнейших тем в Yesod является правильное использование типов, что позволяет сделать жизнь разработчиков проще. В шаблонах Yesod у нас есть два основных примера:
- Все содержимое, внедренное в шаблон Hamlet (Гамлета), должно иметь тип
Html
. Как мы увидим позже, это заставляет нас, когда это необходимо, избегать использовать опасный код HTML, например, случайного двойного преобразования. - Вместо того, чтобы вставлять адрес URL непосредственно в наш шаблон, у нас есть типы данных, известные как типобезопасные адреса, которые представляют собой маршруты в нашем приложении.
В качестве реального примера, предположим, что пользователь отправляет в приложение с помощью формы свое имя. Эти данные будут представлены типом данных Text
. Теперь мы хотели бы отобразить на странице эту переменную, которая называется name
. Система типов во время компиляции предотвращает просто вставить ее в шаблон Hamlet, поскольку она не относится к типу Html
. Вместо этого мы должны ее как-то преобразовать. Для этого есть две функции преобразования:
- Преобразование toHtml, которое автоматически выбрасывает любые лишние вставки. Таким образом, если пользователь отправляет строку
<script src="http://example.com/evil.js"></script>
, символы «меньше чем» будут автоматически преобразованы в<
- Преобразование
preEscapedText
, с другой стороны, оставит содержимое в том виде, как оно есть.
Таким образом, в случае недопустимого ввода данных, сделанного, возможно, зловредным пользователем, в качестве рекомендуемого нами подхода будет использование преобразования toHtml
. С другой стороны, скажем, у нас есть несколько статических документов HTML, хранящихся на нашем сервере, которые мы хотели бы вставлять в некоторые страницы без всяких изменений. В этом случае, мы могли бы загрузить их в значение Text
, а затем применить преобразование preEscapedText
, что позволит нам избежать всяких преобразований.
По умолчанию, Hamlet будет использовать функцию toHtml
для любого контента, который вы пытаетесь вставить. Таким образом, вам нужно явно выполнить преобразование только в случае, если преобразование вам явно не нужно. Это следует изречению о том, что ошибиться лучше в сторону излишней осторожности.
name <- runInputPost $ ireq textField "name" snippet <- readFile "mysnippet.html" return [hamlet| <p>Welcome #{name}, you are on my site! <div .copyright>#{preEscapedText snippet} |]
Первым шагом в типобезопасных адресах URL является создание тип данных, который представляет все маршруты на вашем сайте. Скажем, у вас есть сайт для отображения чисел Фибоначчи. Сайт будет иметь отдельную страницу для каждого числа в последовательности и, плюс, домашнюю страницу. Это может быть сделано с помощью типа данных в языке Haskell следующим образом:
data FibRoute = Home | Fib Int
Затем мы могли бы создать страницу, например, следующим образом:
<p>You are currently viewing number #{show index} in the sequence. Its value is #{fib index}. <p> <a href=@{Fib (index + 1)}>Next number <p> <a href=@{Home}>Homepage
Тогда все, что нам нужно, это некоторая функция, которая преобразует типобезопасный URL в строковое представление. В нашем случае, это может выглядеть примерно так:
render :: FibRoute -> Text render Home = "/home" render (Fib i) = "/fib/" ++ show i
К счастью для разработчика , все шаблоны, определяющие и отображающие типы данных для типобезопасных адресов URL, обрабатывается в Yesod автоматически. Позже мы рассмотрим это более подробно.
Другие языки
В дополнение к языку Hamlet предлагаются еще три других языка: Julius (Юлий), Cassius (Кассий) и Lucius (Луций). Julius используется для Javascript, однако, это простой сквозной язык, который просто позволяет делать вставки. Другими словами, за исключением случайного использования синтаксиса вставок, любая часть Javascript может быть убрана из Julius и синтаксис останется действительным. Например, для тестирования производительности Julius, с помощью него был добавлен фреймворк Jquery и при этом не возникло никаких проблем.
Два других языка являются альтернативой синтаксису CSS. Те, кто знаком с разницей между Sass и Less увидят это различие немедленно: в Cassius в качестве разделителей используются пробелы, в то время как в Lucius использует фигурные скобки. Lucius, на самом деле, является расширением CSS, то есть все допустимые файлы CSS также будут допустимыми в Lucius. В дополнение к возможности вставки текста, есть некоторые вспомогательные типы данных, предлагаемые для моделирования размеров и цвета. Также в этих языках работают типобезопасные адреса URL, что удобно при определении фоновых изображений.
Помимо безопасности типов и проверок во время компиляции, о чем упоминалось выше, наличие специализированных языков для CSS и Javascript предоставляет нам несколько других преимуществ:
- При разработке приложений все CSS и Javascript компилируются в окончательный исполняемый файл, что повышает производительность (благодаря отсутствию ввода/вывода) и упрощает развертывание приложения.
- Благодаря тому, что все это базируется на эффективном конструкторе сборщика, который был описан ранее, прорисовка шаблонов осуществляется очень быстро.
- Есть встроенная поддержка автоматического включения CSS и Javascript в окончательные веб-страницы. Мы столкнемся с этом более подробно, когда далее будем рассматривать виджеты.
Далее: Хранение данных с помощью Persistent