Использование ERB-шаблонов
Целью данного занятия является ознакомление с механизмами работы ERB-шаблонов для их дальнейшего использования при разработке веб-приложений.
Документация
- An introduction to ERB Templating
- Ruby: Rendering erb template
- Ruby Templating Languages: ERB, HAML & Slim
- Описание класса ERB в стандартной библиотеке Ruby
Введение в язык ERB
Что такое ERB?
Embedded Ruby, ERB, - язык описания шаблонов, в которые можно вставлять исполняемый код на языке Ruby. Результатом обработки шаблона является строка, которая может представлять любой документ: HTML-документ, XML-документ, исходный код и т.д. Такие шаблоны замечательно подходят для решения задачи вставки повторяющихся элементов.
Для использования ERB-шаблонов в языке Ruby существует два подхода: использовать соответствующую библиотеку, erb
, или использовать инструмент командной строки, erb
. В первом случае взаимодействие происходит на языке Ruby, а во втором через вызов инструмента с помощью командного интерфейса. В рамках нашего курса нас будет интересовать именно программный подход к данному инструменту.
Для решения задачи формирования HTML-документов существуют более специализированные варианты языков шаблонов, однако их реализации всегда будут де-факто медленнее ERB, так как ERB ничего не знает про структуру языка, также ERB можно будет использовать для решения более широкого спектра задач.
Язык шаблонов ERB
Во время обработки шаблонов ERB просто копирует текст из шаблона в результирующий документ, а обрабатывает только лишь части, помеченные специальными метками. В большинстве шаблонов используются только два типа меток, отличающиеся тем как обрабатывается Ruby-код внутри их.
Для описания меток используется подход с тегами, начинающимися с последовательности <%
и заканчивающиеся последовательностью %>
.
Если после открывающей последовательности находится символ =
, то такая метка описывает выражение. Результат выполнения выражения внутри метки будет вставлен в ERB-шаблон после приведения к строке. Такую метку можно использовать для отображения значения переменной или какого-либо выражения. Рассмотрим пример ERB-шаблона:
Здравствуйте, <%= @name %>
Сегодня <%= Time.now.stftime('%A') %>
Если же после открывающей последовательности нет знака равно, то метка описывает скриптлет. При обработке документа каждый скриптлет захватывается и выполняется. Результат выполнения всего захваченного кода затем вставляется в результирующий документ в месте размещения скриптлета.
Скриптлеты используются для внедрения циклов. Рассмотрим пример ERB-шаблона:
<% for item in @shopping_list %>
- <%= item %>
<% end %>
Текст, который находится внутри цикла, будет выведен в финальный документ столько раз сколько раз сам цикл был выполнен. В частности в рамках примера все элементы списка будут выведены.
Скриптлеты также используются для вставки условных выражений. Рассмотрим пример ERB-шаблона:
<% if @user.logged_in? %>
<p>
Вы зашли под учётной записью <%= show_user(@user) %>
</p>
<% end %>
Если условное выражение верно, тогда текстовое содержимое будет добавлено на страницу. Если же нет, тогда никакого текста не будет добавлено в результирующий текст.
Названия для файлов-шаблонов
Файл с ERB-шаблоном, конечно, может иметь произвольное имя, однако по соглашению данные файлы должны заканчиваться на .erb
. Различные фреймворки могут требовать называть файлы специальным образом. Например, Ruby on Rails требует давать ERB-файлу расширение .html.erb
, если результатом обработки шаблона будет HTML-документ. Некоторые редакторы также поддерживают расширение .rhtml
для таких шаблонов.
Использование библиотеки erb
Рассмотрим следующий простой пример использования библиотеки, написанный на языке Ruby:
require 'erb'
weekday = Time.now.strftime('%A')
simple_template = "Today is <%= weekday %>."
renderer = ERB.new(simple_template)
puts renderer.result()
Обработка шаблона начинается в тот момент, когда вызывается метод result
. Это означает, что и значения переменных будут браться на момент вызова метода, а не на момент определения шаблона.
Стоит отметить, что рассмотренный подход почти никогда не будет работать. Это связано с тем, что для доступа к переменным и методам библиотека использует объект типа Binding (связывание). Объекты класса Binding предоставляют возможность захватить контекст выполнения и использовать этот контекст в будущем. Одно из частных применений контекста - при обработке ERB-шаблонов. Если явно не указать объект Binding, тогда ERB будет использовать контекст глобального объекта, в котором почти ничего нет.
Правильный подход к использованию ERB-шаблона состоит в создании специального объекта, который будет содержать в себе данные и методы. Затем контекст такого объекта передаётся шаблонизатору, чтобы он смог их использовать для формирования содержимого шаблона. Для получения объекта Binding существует метод binding
. Для получения полного доступа к контексту объекта данный метод необходимо вызывать внутри объекта, поэтому зачастую формируется прокси-метод. Рассмотрим пример на языке Ruby:
class DataProvider
...
def get_biding
binding
end
end
data_provider = DataProvider.new(...)
renderer = ERB.new(template)
puts output = renderer.result(data_provider.get_binding)
Если для вашей задачи нет необходимости создавать отдельный класс, то можно просто воспользоваться методом binding
для получения контекста переменных внутри метода. Рассмотрим пример кода на языке Ruby:
require 'erb'
def make_world_happy(name)
template = 'Будь счастлив, мой друг <%= name %>!' # Описываем шаблон
renderer = ERB.new(template) # Создаём шаблонизатор
context = binding # Захватываем контекст выполнения
puts renderer.result(context) # Формируем строку и печатаем её
end
make_world_happy('Артемий')
Изменение поведения обработки шаблона
Поведение ERB-шаблонизатора можно изменить, настраивая значение аргумента trim_mode
. Данный аргумент может содержать в себе строку, содержащую один или комбинацию из следующих модификаторов:
%
- включается обработка Ruby-кода для строк, начинающихся с символа%
;<>
- не добавлять новую линию для строк, начинающихся с<%
и заканчивающихся%>
;>
не добавлять новую строку на линиях, которые заканчиваются на%>
;-
не добавлять новую строку на линиях, которые заканчиваются на-%>
.
Например, если мы хотим использовать %
-строки и не добавлять переносы после %>
, тогда необходимо создать шаблонизатор следующим образом:
renderer = ERB.new(template, trim_mode: '%>')
Более длинный пример
Разберём пример использования erb из примера. Данный пример написан на языке Ruby.
require "erb"
# Класс для предоставления данных в шаблон
class Product
def initialize(code, name, desc, cost)
@code = code
@name = name
@desc = desc
@cost = cost
@features = []
end
def add_feature(feature)
@features << feature
end
# Получение доступа к контексту объекта
def get_binding
binding
end
end
# Описываем шаблон
template = <<~TEMPLATE
<!DOCTYPE html>
<html>
<head><title>Магазин игрушек -- <%= @name %></title></head>
<body>
<h1><%= @name %> (<%= @code %>)</h1>
<p><%= @desc %></p>
<ul>
<% @features.each do |f| %>
<li><b><%= f %></b></li>
<% end %>
</ul>
<p>
<% if @cost < 10 %>
<b>Всего <%= @cost %>!!!</b>
<% else %>
Свяжитесь с нами, чтобы узнать цену!
<% end %>
</p>
</body>
</html>
TEMPLATE
# Создаём шаблонизатор и передаём ему шаблон для работы
rhtml = ERB.new(template)
# Заполняем объект с данными для отображения
toy = Product.new("TZ-1002",
"Ruby-мыслящий",
"Лучший друг программсита! Понимает команды на Ruby...",
999.95)
toy.add_feature("Понимает голосовые команды на языке Ruby!")
toy.add_feature("Игнорирует запросы на Perl, Java и всех вариантах языка Си")
toy.add_feature("Знает карате!")
toy.add_feature("Личная подпись Matz на левой ноге!")
toy.add_feature("Глаза инкрустированы драгоценными камнями... Рубинами, конечно!")
# Формируем результат
rhtml.run(toy.get_binding)
Сначала мы описываем класс, который будет содержать данные для шаблона. Данные состоят из четырёх переменных экземпляра, содержащих обычные данные (@code
, @name
, @desc
и @cost
), а также из переменной, содержащей список (@features
). Обратите внимание, что у класса вообще нет атрибутов, но есть метод для получения доступа к контексту через связывание, метод get_binding
.
Далее мы описываем HTML-шаблон, который формирует из данных нашего класса HTML-представление. Данные из класса вставляются как в заглавие документа, так и в его тело. Список параметров отображается в HTML-список, а для указания цены используется условная логика.
После этого мы создаём необходимые объекты ERB-шаблонизатора и класса с данными. Шаблонизатору передаётся текст шаблона. Класс с данными затем заполняется необходимыми для показа данными.
В конце шаблонизатору передаётся контекст объекта с данными в метод run
. В отличие от метода result
данный метод выводит содержимое на стандартный поток вывода, а не возвращает строку.
Задачи на изучение ERB
Сравнение ERB-шаблонов и строковых шаблонов
Вниманиие при реализации данной задачи не надо создавать никаких классов или модулей, достаточно воспользоваться методами. Методу в качестве параметров передаются данные, необходимые для формирования шаблона. Внутри метода необходимо выполнять все действия, которые необходимы для решения задачи.
Задача с помощью ERB-шаблонов и строковых шаблонов решите следующие задачи. Сравните их между собой и примите решение, какой из данных подходов лучше подходит для решения такой задачи. Пояснение: вам необходимо написать по 2 метода для решения каждой задачи и сравнить их между собой. В первом методе для решения задач используем ERB-шаблоны, для второго метода используем встроенные шаблонные строки языка.
- Сформируйте строку приветствия с человеком. Методу в качестве параметра передаются имя и фамилия.
- Сформируйте текст приглашения на событие, которое включает в себя название мероприятия, имя приглашённого, текст приглашения и имя отправляющего приглашение.
-
Сформируйте текст описания товара в интернет-магазине. Методу в качестве аргументов передаётся название товара, его стоимость и категория. Возможные значения категории:
:shoes
,:dress
,:tools
. В зависимости от категории должно выводится различное описание. Пример готового описания:Купите замечательное платье! Название: Mango Цена: 1500 руб.
-
Сформируйте описание расписания на один день у одной группы в университете. Методу в качестве аргумента передаётся массив из хешей, содержащий описание расписания:
schedule = [ {name: "Теормех", audience: 112, when: :numerator}, {name: "Мат. ан.", audience: 205}, {name: "Теор. игр", audience: 108}, {name: "Ин. яз.", audience: 507, when: :denomitanor}, ]
Необходимо сформировать из этого описания расписание, которое будет показывать соответствующую информацию.
Формирование страниц сайта
Внимание при решении данной задачи необходимо следовать всем требованиям по разработке приложений на Ruby.
Вам необходимо сформировать сайт, содержащий информацию по всем сотрудникам компании. Под сайтом подразумевается набор вязанных HTML-документов (файлов), которые можно просмотреть через браузер. Информация по сотрудникам содержится в YAML-документе:
---
people:
- name: Иван
patronymic: Иванович
surname: Семёнов
email: ivan.semenov@example.com
avatar: https://www.gravatar.com/avatar/c941144838e03143e77a9fd40cb36dfa?d=retro&s=400
- name: Сергей
patronymic: Александрович
surname: Краснов
email: sergey.krasnov@example.com
avatar: https://www.gravatar.com/avatar/d15aaf8ed63262edbc364c9395d54da4?d=retro&s=400
- name: Наталья
patronymic: Владимировна
surname: Лихачёва
email: natalia.lihacheva@example.com
avatar: https://www.gravatar.com/avatar/4a236e4c48d7a8acb16e7221fdad03e3?d=retro&s=400
- name: Пётр
patronymic: Алексеевич
surname: Соловьёв
email: petr.soloviev@example.com
avatar: https://www.gravatar.com/avatar/267d7ae01920c7ed15b40fdac2c5eed8?d=retro&s=400
Ваш сайт должен содержать страницу, предоставляющую краткий список сотрудников. В кратком списке выводится имя и фамилия и ссылка на полное описание сайта. При переходе на страницу сотрудника слева должен отображаться аватар пользователя, а справа от него должна находиться полная информация по сотруднику.
Для формирования стиля сайта рекомендуется использовать CSS-фреймворк.