Что такое Mojolicious. Введение
Благодаря заметке на Хабре (в кэшэ Google) наконец-то решил познакомиться с набирающим популярность фреймворком для веб-разработки на Perl под названием Mojolicious. В общем-то я взял пример скрипта из этой заметки и сделал его чуть более интересным для себя, чтобы охватить немного больше документации по фреймворку (результат вполне работоспособен, его можно посмотреть здесь, а код и скриншот выложены в конце заметки). Сразу отмечу, что ни пример с Хабра, ни мой практически не отражают возможностей фреймворка, а только лишь иллюстрируют простоту его использования.
Итак, Mojolicious — фреймворк для разработки веб-приложений, основанный на «фреймворке для разработки фреймворков» Mojo, написанный на языке Perl человеком по имени Sebastian Riedel, одним из авторов Perl-веб-фреймворка Catalyst, фактически для его замены.
Чем мне показался особенно интересен Mojolicious? Во-первых тем, что он имеет встроенный веб-сервер, что в перспективе позволяет не только удобно разрабатывать и проверять приложение, но и распространять его для локального использования. При этом приложение получается универсальным и будет одинаково работоспособным как на локальной машине, так и на сервере. Во-вторых — Mojolicious зависит только от Perl, что также говорит в пользу «во-первых». В-третьих — наличием модуля Mojolicious::Lite, позволяющего создать лёгкие, маленькие, но полноценные приложения. И в-четвёртых — автоматической поддержкой разных режимов запуска (CGI, FastCGI, mod_perl, встроенный сервер и т.д.).
Установка фреймворка Mojolicious
Установить фреймворк можно используя cpan или его производные типа cpan+ (cpan Mojolicious
), загрузив дистрибутив и установив как любой Perl-модуль при помщи make или же воспользоваться системой управления пакетами своей ОС. Я пробовал первый и третий способы, устанавливал Mojolicious под Debian и под Windows XP и нигде проблем не возникло, так что об установке сказать особо нечего. Она проста и не нуждается в пояснениях.
После установки Mojolicious в системе становится доступной команда mojo
, при помощи которой можно создавать, изменять и запускать приложения. Аналогичные действия можно выполнять, вызывая обычным образом любой perl-скрипт, в котором подключен Mojolicious (use Mojolicious;
).
Документация по Mojolicious
Документация к фреймворку начинает появляться, основная масса естественно доступна на домашнем сайте в разделах Documentacion и Wiki. Лучше всего пользоваться именно ей, поскольку не смотря на то, что версия фреймворка является стабильной (1.16 на момент написания заметки), интерфейс всё же иногда меняется и русскоязычная документация за ним не поспевает.
Самый лучший источник документации на русском (представляет собой перевод официальной документации), который мне встретился, расположен тут. Остальные по-моему просто переписаны с него. Также на русском можно отыскать различные примеры использования Mojolicious, особенно в блогах. Некоторые из них иллюстрируют работу с устаревшими версиями фреймворка — соответственно и методы работы в них приводятся неверные. Также может оказаться полезной небольшая заметка про запуск mojolicious-приложения под Apache.
Создание приложения
Создать новое приложение с использованием Mojolicious можно двумя путями — обычным образом создать файл скрипта и вписать в него нужный код или же воспользоваться встроенным генератором приложений фреймворка. Второй путь удобней 🙂
Новое приложение Mojolicious
Новое приложение Mojolicious создаётся командой mojo generate app AppName
. Такой способ пригоден для создания больших проектов с возможностью простого масштабирования. При этом будет создан каталог, носящий имя app_name со следующей структурой (на примере приложения TestApp):
test_app
|
|-- lib
| |-- TestApp
| | |-- Example.pm
| |-- TestApp.pm
|
|-- log
|-- public
| |-- index.html
|
|-- script
| |-- test_app*
|
|-- t
| |-- basic.t
|
|-- templates
|-- example
| |-- welcome.html.ep
|
|-- layouts
|-- default.html.ep
lib — здесь будут расположены библиотеки приложения;
log — логи (если каталог отстутствует — выводятся на экран);
public — статика (статические страницы, java-скрипты и т.п.);
script — само приложение;
t — тесты для приложения;
templates — содержит шаблоны страниц и шаблоны макетов (в layouts — это шаблоны, применяемые на большинстве страниц — например «шапка», «подвал», «сайдбар»).
Новое приложение Mojolicious::Lite
Приложение Mojolicious::Lite создаётся похожей командой: mojo generate lite_app AppName
.
Основное различие между ними — в данном случае создаётся только один исполняемый файл, шаблоны будут содержаться непосредственно в нём, в разделе __DATA__, структура каталогов создаваться не будет. Такой вариант подходит для небольших, буквально «одностраничных» приложений. В дальнейшем, если возникнет необходимость разделить шаблоны и логику обработки данных — достаточно вызвать приложение с параметром inflate — шаблоны будут вынесены в отдельные файлы в директории templates.
Встроенный шаблонизатор EmbeddedPerl
Mojolicious предоставляет обработчик шаблонов — Embedded Perl (отсюда и расширение .ep у файлов шаблонов). Для встраивания Perl-кода в html используется четыре вида специальных тегов (в примере приложения я некоторые из них продемонстрировал):
- [ccie]<% %>[/ccie] или [ccie]%[/ccie] — строка Perl без вычисления результата;
- [ccie]<%= %>[/ccie] или [ccie]%=[/ccie] — выражение Perl, вычисленный результат возвращается в экранированном виде;
- [ccie]<%== %>[/ccie] или [ccie]%==[/ccie] — выражение Perl, вычисленный результат возвращается без обработки (не экранирован);
- [ccie]<%# %>[/ccie] или [ccie]%#[/ccie] — комментарий, строка пропускается;
Mojolicious автоматически экаранирует символы <, >, &, ‘ и «, добавляет ; в конце строки и выставляет границы начала и конца строки в регулярных выражениях внутри своих методов (например — при создании маршрутов).
Кроме использования встроенного шаблонизатора, можно подключить любой желаемый сторонний шаблонизатор используя метод add_handler.
Запуск приложения
Фреймворк Mojolicious имеет встроенный http(s) сервер, с помощью которого можно как проверять работоспособность приложения, так и эксплуатировать его. Для запуска сервера используется следующая команда: perl myapp.pl daemon
.
Во время разработки очень полезно будет запускать сервер с ключём --reload
— с его использованием приложение будет перезагружаться «на лету» после каждого изменения, таким образом вручную перезапускать скрипт не нужно, достаточно запустить с этим ключом в фоне один раз. В процессе эксплуатации приложения можно добиться подобного «горячего обновления» приложения, запустив несколько копий веб-сервера с указанием одного и того же сокета и PID-файла блокировки, т.е. реализуется схема: работающий сервер —> обновление приложения —> параллельный запуск сервера с обновлённым приложением —> мягкое выключение «старого» сервера (активные подключения не будут разорваны).
Кроме того, встроенный сервер из коробки поддерживается TLS с включенным сертификатом разработчика, так что можно запустить https-сервер, использовав ключ --listen
. Тогда полная команда для запуска сервера может выглядеть так:
perl myapp.pl daemon --reload --listen https://localhost:PORT
Если веб-сервер планируется применять не только для разработки/локального использования — можно увеличить его производительность, запустив с опцией daemon prefork
— на каждое соединение будет создаваться свой процесс-обработчик (как в Apache), ключ --clients N
позволяет изменить это число, задав максимальное количество клиентских подключений к одному обработчику.
Пример простого приложения на Mojolicious::Lite
#!/usr/bin/perl
require 5.008_008;
# при подключении Mojolicious::Lite автоматически подключаются warnings и strict
# но лучше перебдеть ;)
use warnings;
use strict;
use utf8;
use Mojolicious::Lite;
use Mojo::UserAgent;
$ENV{'MOJO_MODE'} = 'production';
get '/' => sub {
my $self = shift;
# адреса сайтов берутся из адресной строки, очистки нет поскольку
# ссылки пойдут транзитом к поисковикам. При печати Mojolicious
# по умолчанию экранирует символы < > & ' " против XSS-атак.
my $sites = { map { lc $_, +{} } split /\r\n/, $self->param('site_url') };
if ($sites) {
# метод client устарел, нужно использовать метод ua,
# или создать объект UserAgent явно и с нужными настройками.
# устарел: $self->client->get($g_req_url)->res->dom->at('div#resultStats');
# работает: $self->ua->get($g_req_url)->res->dom->at('div#resultStats');
# Создаем объект UserAgent
my $ua = Mojo::UserAgent->new(
max_redirects => 1,
name => 'Mozilla/5.0 (Windows; Windows NT 6.1; rv:2.0)',
);
foreach (keys %$sites) {
# GOOGLE
# запрашиваем страницу по адресу
# "http://www.google.com/search?q=site%3A$site"
# и из полученной страницы берем содержимое
# блока <div id="resultStats">
# at - ищет элемент по html-тегу
my $g_req_url = 'http://www.google.ru/search?q=site%3A'.$_;
$sites->{$_}{google}{req_url} = $g_req_url;
$sites->{$_}{google}{result} =
$ua->get($g_req_url)->res->dom->at('div#resultStats')->text =~
m/[\w:]+ \s ([\d\s]+)$/msx ? $1 : '---';
# YANDEX
# извлекает содержимое <strong class="b-head-logo__text">
my $y_req_url = 'http://yandex.ru/yandsearch?text=site%3A'.$_.'&lr=2';
$sites->{$_}{yandex}{req_url} = $y_req_url;
$sites->{$_}{yandex}{result} =
$ua->get($y_req_url)->res->dom->at('strong.b-head-logo__text')->text =~
m/^Наш(?:лось|ёлся) ([\d\w\s\.]+) \s \w+$/msx ? $1 : '---';
}
}
$self->render(
# название шаблона
template => 'index',
format => 'html',
sites => $sites,
);
};
# Секретная фраза - используется для подписания кукисов,
# по умолчанию равна названию скрипта (имени приложения)
app->secret('P@r0L-dl!a_MoJ0!');
app->start;
# ниже в этом же файле объявляем шаблон index.html.ep
# index - название шаблона
# html - формат шаблона (кроме html - напр. text)
# ep - обработчик шаблона (от EmbeddedPerl, ещё - epl)
# название, формат и обработчик могут быть переданы методу render
# template => 'название', format => 'формат', handler => 'обработчик'
__DATA__
@@ index.html.ep
% layout 'default';
% title 'Mojolicious::Lite test';
<table cols="3" cellpadding="2" cellspacing="4" width="350px">
<thead>
<tr> <th colspan="3">Количество страниц в индексе поисковиков</th>
<tr> <th>Сайт</th><th>Google</th><th>Yandex</th> </tr>
</thead>
<tbody>
% foreach (sort keys %$sites) {
<tr>
<td align="center"><%= $_ %></td>
<td align="center">
<a href="<%= $sites->{$_}->{google}->{req_url} %>">
<%= $sites->{$_}->{google}->{result} %></a>
</td>
<td align="center">
<a href="<%= $sites->{$_}->{yandex}->{req_url} %>">
<%= $sites->{$_}->{yandex}->{result} %></a>
</td>
</tr>
% }
</tbody>
</table>
<%# вспомогательная функция dumper - использует Data::Dumper %>
<%#= dumper($sites) %>
<hr>
<form action="./<%= $0 %>">
URL<br />
<textarea rows="5" cols="65" name="site_url">
<%= join "\n", sort keys %$sites %>
</textarea>
<br />
<input type="submit" />
</form>
<br />
@@ layouts/default.html.ep
<!doctype html><html>
<head>
<title><%= title %></title>
<%= javascript ('https://dimio.org/cgi-bin/js/liveinternet-counter.js') %>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="favicon" href="https://dimio.org/favicon.ico" type="image/x-icon" />
</head>
<body><%= content %></body>
</html>
Результат работы скрипта-примера
Пример парсера ссылок для Google на Mojolicious
SHok в комментариях к записи выложил в качестве примера приложения, разработанного с помощью Mojolicious::Lite свой парсер ссылок для Google. На примерах учиться проще, так что заинтересовавшимся стоит скачать архив и посмотреть, как реализуется проверка входа по паролю, получение данных и выдача результатов парсинга.
Отличный пост, сослался в твиттере.
Спасибо 🙂
Пост шикарен, спасибо! Кстати, кто знает, почему в последнее время с хабра пропадает так много постов?
На самом деле он оттуда не пропал и находился в Пт через поиск самого Хабра, а по прямой ссылке — нет. Притом ID остался прежним.
Ты сам-то не пробовал ещё Mojolicious? Как считаешь, в сравнении с тем же wxWidgets — что актуальней? Тут с наличием встроенного http-сервера получается тоже автономное приложение, размер самого модуля небольшой, дистрибутив не раздует. С учётом перспективы html 5 — выглядит заманчиво.
приложение выдает ошибку если в домене дефим есть))
И не только в этом случае. Это демонстрация простоты использования фреймворка, а не конечный продукт, о чём и было сказано в заметке и в комментариях исходника.
Да, простота и изящество впечатлили. Не вольно задумываешься, а не использовать ли его))
Я точно буду пользоваться теперь Lite-версией. На сервер встроенный прямо нарадоваться не могу — настолько удобно стало.
И кстати — неплохой способ получается, чтобы посмотреть на сообщения об ошибках, которые Mojolicious генерирует.
Thank you for your articles on you blog. They are useful to me. Your information resources make those spam blog shamed.ntly posting of so many useful tips.They are such a great help to me.Thank you very much!
Your articles are so functional on entertainment, really worth to read after a day of hard work. Maybe you will became a talent script editor.
Похоже на то, что Перл пытается казаться живым, хотя на самом деле конь уже староват для забега и предложить, что-то стоящее уже не может. Ни одного преимущества перед Padrino, Sinatra, да и Руби язык получше будет.
Старый конь борозды не испортит 🙂
С чего бы современному, гибкому, удобному и простому языку умирать?!
Я точно не поддерживаю тезис об умирании Перла!
Думаю это то что нужно 🙂
Уже написал свою первою приложеньку на лайт версии.
Сделал гуло парсер ссылок.
Теперь пишу обвязку для заказаного софта 🙂
Пока что моджо меня радует, посмотрим что там в полной версии после того как допишу обвязку 🙂
Не стесняйтесь выкладывать, если не секретное 🙂 Чем больше примеров — тем проще освоить новичкам.
Вот залил в архиве, потому как там несколько файлов 🙂
[ссылка]
Не против, если я ссылку в запись добавлю? Еще любопытно — чем обоснован выбор в google.pm обычного списка @res и доп. модуля
use List::MoreUtils qw/uniq/;
вместо хэша?Да, размещайте, я не против.
По факту обусловлено лишь тем, что мой мозг не посчитал это необходимым 🙂