Что же такое Mojolicious?
Автором сего чуда есть ни кто иной как создатель фреймворка Catalyst — Sebastian Riedel. Что же толкнуло создателя одного Perl фреймворка создать другой? Catalyst имеет очень служную архитектуру. К тому же, как и во многих существующих MVC фреймворках, Catalyst имеет единственный вариант роутинга — это
example.com///. Основное достоинство Catalyst — это повторое использование кода. Для чего же стоило заморачиваться с новым фреймворком? Что же есть такого в Mojolicious?
Mojolicious — это настоящий фреймфорк для Perl, который отвечает всем принципам языка:
«Есть больше одного способа это сделать» («There’s more than one way to do it»), известный также под аббревиатурой TMTOWTDI; «Простые вещи должны оставаться простыми, а сложные стать выполнимыми» («Easy things should be easy and hard things should be possible». Catalyst стал черновиком для Mojolicious, который выделяется следующими фичами:
* Полностью объектно ориентированое API
* Поддержка HTTP 1.1(REST), WebSocket, IPv6, SSL, IDNA
* Поддержка CGI, FastCGI, PSGI, Daemon, Prefork
* Отсутствие зависимостей (начиная с Perl 5.8.1)

Слова — вода! А где же код?
Как и в самом Perl, все плюшки можно осознать, только после рассмотрения основных модулей и примеров их использования.
Рассмотрим самые вкусные атрибуты класса Mojolicious:
* controller_class — Класс который используется в качестве контроллера по умолчанию(по умолчанию Mojolicious::Controller)
my $class = $app->controller_class;
$app = $app->controller_class('Mojolicious::Controller');
* mode — определяет режим в котором работает приложение. Вы можете добавлять код уникальный для приложения в режиме разработки или в продакшине.
my $mode = $app->mode;
$app = $app->mode('production');
sub development_mode {
my $self = shift;
}
sub production_mode {
my $self = shift;
}
* plugin — загрузчик плагинов (по умолчанию Mojolicious::Plugins)
my $plugins = $app->plugins;
$app = $app->plugins(Mojolicious::Plugins->new);
* renderer — Определяет класс, который используется для создания ответа от сервера. (по умолчанию Mojolicious::Renderer)
my $renderer = $app->renderer;
$app = $app->renderer(Mojolicious::Renderer->new);
* routes — определяет класс, который используется для роутинга запросов. (по умолчанию Mojolicious::Routes)
my $routes = $app->routes;
$app = $app->routes(Mojolicious::Routes->new);
И методы:
* hook — дает возможность прицепиться на какой-то именованый ивент. это экспериментальный метод, но на мой взгляд — самый интересный
$app->hook($event => sub { ... });
список доступных ивентов: after_build_tx, before_dispatch, after_static_dispatch, after_dispatch
* plugin — загружает плагин.
А теперь немного подробнее про использование некоторых классов
Mojolicious::Controller:
*render
render(controller=>'foo',action=>'bar');
render('foo#bar')
render('foo#bar', format=>'html');
render(template=>'foo/bar');
* render_text
render_text('Hello world!');
render(text=>'Hello world!');
* render_data
render_data('binary data');
render(data=>'binary data');
* render_json
render_json({foo=>'bar'});
render(json=>{foo=>'bar'});
* render_static
render_static('img/logo.png');
Методы render возвращают ответ клиенту в заданов формате или с использованием темплейтов. Для того чтобы иметь доступ к ответу, а не отправлять его, например для отправки его в качестве имейла, необходимо использовать параметр partial.
my $html = $self->render('mail', partial => 1);
Вы так же можете передавать статус код через параметр status
$self->render(text => 'Oops!', status => 500);
Или Content-Type и MIME тип через параметр format, что может быть полезным, если Вы генерируете какой-нибудь файл на стороне сервера или храните какие-то файлы в БД.
$self->render(text => 'Hello!', format => 'txt');
$self->types->type(txt => 'text/plain; charset=utf-8');
* render_not_found/render_excepton
* send_message/receive_message
* url_for/redirect_to
Данные в темплейты передаются через stash следующим образом:
$self->stash(author => 'Sebastian');
$self->stash(frameworks => [qw/Catalyst Mojolicious/]);
$self->stash(examples => {tweetylicious => 'a microblogging app'});
темплейт:
<% for my $framework (@$frameworks) { %>
<%= $framework %> was written by <%= $author %>.
<% } %>
<% while (my ($app, $description) = each %$examples) { %>
<%= $app %> is a <%= $description %>.
<% } %>
Mojolicious::Routes:
Итак, в большинстве фреймворков диспатчер работает по одному определенному принципу. В Mojolicious же этот процесс сделан более динамическим.
Маршруты могут быть описаны не только статической строкой, но и регулярным выражением. Так же в маршрутах данного фреймворка введено понятие placeholder.
Например хабрамаршрут к статье /blogs/social_networks/111416 может быть обобщен с помощью регулярных выражений как /blogs/(\w+)/(\d+) или с помощью placeholder'ов /blogs/:blog/:article
placeholder'ы бывают 3х типов:
1. Обычные — находят все символы, кроме / и.
/hello -> /:name/hello -> undef
/sebastian/23/hello -> /:name/hello -> undef
/sebastian.23/hello -> /:name/hello -> undef
/sebastian/hello -> /:name/hello -> {name => 'sebastian'}
/sebastian23/hello -> /:name/hello -> {name => 'sebastian23'}
/sebastian 23/hello -> /:name/hello -> {name => 'sebastian 23'}
2. «Ослабленые» — находят все символы, кроме /
/hello -> /(.name)/hello -> undef
/sebastian/23/hello -> /(.name)/hello -> undef
/sebastian.23/hello -> /(.name)/hello -> {name => 'sebastian.23'}
/sebastian/hello -> /(.name)/hello -> {name => 'sebastian'}
/sebastian23/hello -> /(.name)/hello -> {name => 'sebastian23'}
/sebastian 23/hello -> /(.name)/hello -> {name => 'sebastian 23'}
3. «Расширеные» — Находят все символы
/hello -> /(*name)/hello -> undef
/sebastian/23/hello -> /(*name)/hello -> {name => 'sebastian/23'}
/sebastian.23/hello -> /(*name)/hello -> {name => 'sebastian.23'}
/sebastian/hello -> /(*name)/hello -> {name => 'sebastian'}
/sebastian23/hello -> /(*name)/hello -> {name => 'sebastian23'}
/sebastian 23/hello -> /(*name)/hello -> {name => 'sebastian 23'}
Для определения цели маршрута используется метод to. Простой пример:
# /welcome -> {controller => 'foo', action => 'welcome'}
$r->route('/welcome')->to(controller => 'foo', action => 'welcome');
Передача данных без явного использования stash:
# /bye -> {controller => 'foo', action => 'bye', mymessage => 'Bye!'}
$r->route('/bye')
->to(controller => 'foo', action => 'bye', mymessage => 'Bye!');
обозначение controler/method в виде 'controler#method' уместно не только в рендере, но и здесь, тогда предидущий пример будет выглядеть так:
# /bye -> {controller => 'foo', action => 'bye', mymessage => 'Bye!'}
$r->route('/bye')->to('foo#bye', mymessage => 'Bye!');
В качестве цели маршрута может служить класс(namespace)
# /bye -> MyApp::Controller::Foo->bye
$r->route('/bye')->to('foo#bye', namespace => 'MyApp::Controller');
или метод:
$r->route('/bye')->to(cb => sub {
my $self = shift;
$self->render(text => 'Good bye!');
});
Так же Вы можете для большего удобства задавать имена маршрутам, например для получения полной строки запроса:
# /foo/abc -> {controller => 'foo', action => 'bar', name => 'abc'}
$r->route('/foo/:name')->name('test')
->to(controller => 'foo', action => 'bar');
# Generate URL "/foo/abc" for route "test"
$self->url_for('test');
# Generate URL "/foo/sebastian" for route "test"
$self->url_for('test', name => 'sebastian');
Так же фреймворк предоставляет возможность использовать разные маршруты для разных типов HTTP запросов
# GET /bye -> {controller => 'foo', action => 'bye'}
# POST /bye -> undef
# DELETE /bye -> undef
$r->route('/bye')->via('get')->to(controller => 'foo', action => 'bye');
# GET /bye -> {controller => 'foo', action => 'bye'}
# POST /bye -> {controller => 'foo', action => 'bye'}
# DELETE /bye -> undef
$r->route('/bye')->via(qw/get post/)
->to(controller => 'foo', action => 'bye');
В Mojolicious::Lite для этого используется более простая запись:
# GET /yada
# POST /yada
my $yada = $r->under('/yada');
$yada->get(sub {
my $self = shift;
$self->render(text => 'Hello!');
});
$yada->post(sub {
my $self = shift;
$self->render(text => 'Go away!');
});
Вместо заключения.
Mojolicious — очень гибкий и мощный фреймворк для Perl, который, ко всему прочему, вполне может потягаться с большинством современных фреймворков для модных языков программирования. Что в свою очередь показывает, что не стоит збрасывать со счетов Perl прогаммистов и пренебрегать Perlом как вариантом языка для разработки своего веб проекта. Описаное в этой статье — это всего-навсего маленькая часть возможностей.
Большая презентация с кучей примеров: тыц
Официальный сайт: http://mojolicio.us/