123
Почему Mojolicious? Анатолий Шарифулин YAPC::Russia 2011

Почему Mojolicious?

Embed Size (px)

DESCRIPTION

YAPC::Russia "May Perl" 2011http://event.perlrussia.org/mayperl4/talk/130

Citation preview

Page 1: Почему Mojolicious?

Почему Mojolicious?Анатолий Шарифулин

YAPC::Russia 2011

Page 2: Почему Mojolicious?

mojolicio.us

Page 3: Почему Mojolicious?

Кто знает, что такое Mojolicious?

Page 4: Почему Mojolicious?

Кто использует Mojolicious?

Page 5: Почему Mojolicious?

На кого повлиял я? :)

Page 6: Почему Mojolicious?

Коротко

Page 7: Почему Mojolicious?

Современный и молодой

веб-фреймворк

Page 8: Почему Mojolicious?

Веб в коробке!

Page 9: Почему Mojolicious?

Mojo::BaseMojo::DOM, Mojo::JSON

Mojo::UserAgentMojo::IOLoopMojo::Template

Page 10: Почему Mojolicious?

MojoMojolicious

Mojolicious::Lite

Page 11: Почему Mojolicious?

Test::Mojoojo...

Page 12: Почему Mojolicious?

385 вотчеров88 форковПо данным github.com

Page 13: Почему Mojolicious?

и один Шарифулин :-)По моему мнению

Page 14: Почему Mojolicious?

Почему всё-таки Mojolicious?

Когда есть Dancer, Plack, Python и Node.js

Page 15: Почему Mojolicious?

Помогает решить почти любую задачу

Почему Mojolicious?

Page 16: Почему Mojolicious?

Начиная от простого сайта в 5 страниц

Почему Mojolicious?

Page 17: Почему Mojolicious?

tochkak.ru

Page 18: Почему Mojolicious?

use Mojolicious::Lite;

get '/' => 'about/what' ;get '/who' => 'about/who' ;get '/what' => 'about/what' ;get '/where' => 'about/where';get '/code' => 'about/code' ;

app->log->level('error');

app->start;

Page 19: Почему Mojolicious?

Заканчивая стартапом c 5000+ пользователями

Почему Mojolicious?

Page 20: Почему Mojolicious?

frodio.com

Page 21: Почему Mojolicious?

или узкоспециализированнойсистемой управлениядля кинотеатров

Почему Mojolicious?

Page 22: Почему Mojolicious?

db.dcp24.ru

Page 23: Почему Mojolicious?

От простых скриптовПочему Mojolicious?

Page 24: Почему Mojolicious?

#!/usr/bin/env perluse ojo;

g( 'http://bobina.pdj.ru/rss.xml' ) ->dom ->find( 'enclosure[url]' ) ->each(sub { say shift->attrs->{url} });

Page 25: Почему Mojolicious?

или TCP-клиента для сотни радио-потоков

Почему Mojolicious?

Page 26: Почему Mojolicious?

my $url = Mojo::URL->new( 'http://frod.io:8000/station20');$loop->connect( address => $url->host, port => $url->port, on_connect => sub { ... }, on_read => sub { ... },);$loop->start;

Page 27: Почему Mojolicious?

on_connect => sub { my ($self, $id) = @_; my $r = Mojo::Message::Request->new; $r->headers->header( 'Icy-MetaData' => 1 ); $r->url( $url ); $self->write($id, $r->to_string);},

Page 28: Почему Mojolicious?

on_read => sub { my ($self, $id, $chunk) = @_;

return unless my %tag = $chunk =~ /Stream(\w+)='(.*?)';/g; say $tag{Title};},

Page 29: Почему Mojolicious?

До софта по тиражированию фильмов для

цифровых кинотеатровПочему Mojolicious?

Page 30: Почему Mojolicious?

CopyDisk

Page 31: Почему Mojolicious?

Mojo::BaseMojo::Log

MojoX::RunCurses::Widgets

Page 32: Почему Mojolicious?

А также тесты для веб-сервисов

Почему Mojolicious?

Page 33: Почему Mojolicious?

use Test::More tests => 252;use Test::Mojo;

my $t = Test::Mojo->new(app => 'App'); # App.pmmy $url = '/api';# my $url = 'http://api.dev.frodio.com';

$t->get_ok( "$url/" ) ->status_is( 200 ) ->json_content_is({ hello => 'Hello, Frodio!' });

Page 34: Почему Mojolicious?

my $data = $t->post_form_ok("$url/like", {station_id => 2}, {'X-Frodio-Auth' => $auth}) ->status_is(200) ->tx->res->json;{ is ref $data, 'HASH'; is exists $data->{ok}, 1; is exists $data->{count}, 1; is defined $data->{sign}, 1, 'Like station';}

Page 35: Почему Mojolicious?

$t->post_form_ok("$url/logout/", {'X-Frodio-Auth' => $auth}) ->status_is(200);

Page 36: Почему Mojolicious?

Большинство своих задач я решаю,

используя Mojolicious

Page 37: Почему Mojolicious?

«Всегда хотел научиться делать

сайты»

Page 38: Почему Mojolicious?

etnogenez.ru

Page 39: Почему Mojolicious?

Небольшой сайт с полноценной панелью

управления26 модулей (140k), 91 шаблон (408k), 16 таблиц

Page 40: Почему Mojolicious?

Структура проектаВсе пути и запуски — от корня проекта

Page 41: Почему Mojolicious?

bin/conf/data/lib/log/script/t/tmpl/tmp/

Page 42: Почему Mojolicious?

bin/check.shbin/logs.shbin/mysqlbin/mysqldumpbin/restart.shbin/start.shbin/stop.sh

Page 43: Почему Mojolicious?

bin/start.sh

Page 44: Почему Mojolicious?

( # script/etnogenez daemon --reload starman --listen :3000 script/etnogenez) >> log/error.log &

Page 45: Почему Mojolicious?

conf/app.confconf/mysql.confconf/nginx.conf

Page 46: Почему Mojolicious?

conf/app.conf

Page 47: Почему Mojolicious?

{ secret => '*****', server => { www => $ENV{DEV} ? 'http://...' : 'http:/...', ... }, session => { ... }, log => { level => $ENV{DEV} ? 'debug' : 'warn', path => 'log/app.log', }, ...}

Page 48: Почему Mojolicious?

conf/mysql.conf

Page 49: Почему Mojolicious?

{ drivername => 'mysql', user => $ENV{DEV} ? 'dev' : 'не-dev', password => '******', datasource => { database => $ENV{DEV} ? 'dev' : 'не-dev', host => 'localhost', },};

Page 50: Почему Mojolicious?

data/log/tmp/

t/

Page 51: Почему Mojolicious?

script/

Page 52: Почему Mojolicious?

Стартовый скриптПути к библиотекам, настройка переменных

окружения

Page 53: Почему Mojolicious?

use common::sense;use lib qw(lib /tk/lib);

BEGIN { $ENV{DEV}++ if qx(pwd) =~ /dev/; $ENV{MOJO_MODE} ||= $ENV{DEV} ? 'dev' : 'production'; $ENV{MOJO_TMPDIR} = 'tmp/upload'; $ENV{MOJO_MAX_MESSAGE_SIZE} = 2 * 1024 ** 3;};$ENV{MOJO_APP} ||= 'App';

use Mojolicious::Commands;Mojolicious::Commands->start;

Page 54: Почему Mojolicious?

lib/

Page 55: Почему Mojolicious?

App.pm

Page 56: Почему Mojolicious?

package App;use Mojo::Base 'Mojolicious';

has conf => sub { do 'conf/app.conf' };has db => sub { use Util; Util->db( do 'conf/mysql.conf') };

sub startup { ... }

Page 57: Почему Mojolicious?

use DBI 1.58; use DBD::mysql 4.004; use DBI::Util;

return DBI->connect(DBI::Util::_parse_cfg( $conf, { RootClass => 'DBI::Util', mysql_enable_utf8 => 1, mysql_auto_reconnect => 1, }));

Page 58: Почему Mojolicious?

selectquery

inlimit

values

Page 59: Почему Mojolicious?

use dw;Lazy-обертка, связи parent/child и прочее

Контекстно проекту и БД

Page 60: Почему Mojolicious?

sub book { my $self = shift; SLICELY { $self->dw::g::part ('book_id') } 'id' => 'part' => ...}

sub part { my $self = shift; SLICELY { CHV {$_->[0]} $self->dw::g::book('id') } 'book_id' => 'book' => ...}

Page 61: Почему Mojolicious?

sub _list { my $self = shift; ... return $self->dw->book( $self->db->select( "select * from book where hidden=0 order by $order $limit" ) );}

Page 62: Почему Mojolicious?

bin/mysqlС базой данной работаю через консоль

Page 63: Почему Mojolicious?

Настройка путей, логов, сессий, типов

startup

Page 64: Почему Mojolicious?

Подключение плаггинов и хелперов

startup

Page 65: Почему Mojolicious?

$app->helper(db => sub { shift->app->db });

sub action { my $self = shift; # my $DB = $self->app->db;

$self->db->select('...');}

Page 66: Почему Mojolicious?

$app->helper(u => sub { my $self = shift; my $func = shift || return; return &{"Util::$func"}; });

$self->u(iso2human => '...');

%=u iso2human => '...'

Page 67: Почему Mojolicious?

# в каждом контроллереuse Util;

# в шаблоне или кодеUtil::iso2human(...);

# это boilercode и некрасиво# поэтому хелпер

Page 68: Почему Mojolicious?

Общие и контексно проекта

хелперыMojolicious::Plugin::UtilHelpers и App::Helpers

Page 69: Почему Mojolicious?

Все роутеры проектаstartup

Page 70: Почему Mojolicious?

route, bridge, waypoint, name, shortcut

Mojolicious::Guides::Routing

Page 71: Почему Mojolicious?

my $ad = $r->route('/admin')->to->name('admin');$ad->route('/login')->post->to('admin-enter#login'); my $a = $ad->bridge->to('admin-enter#check');

# shortcut / /sort /add /:id /:id/edit /:id/remove /:filter$a->crud($_ => "admin-$_") for qw(book part ...);

$a->route('/(*any)')->to('admin#not_found');

Page 72: Почему Mojolicious?

App::HelpersРазличные форматирования, работы со строками,

повторяющиеся действия

Page 73: Почему Mojolicious?

$app->helper(format_mmss => sub { my $self = shift; my $int = shift || return '00:00'; return sprintf "%02d:%02d", $int / 60, $int % 60; });

Page 74: Почему Mojolicious?

$app->helper(user_img => sub { my $self = shift; my $user = shift || $self->stash('USER'); return $user->{avatar} || '/.../default.png'; });

Page 75: Почему Mojolicious?

App::Index Контроллер

$r->route->to('index#main');

Page 76: Почему Mojolicious?

package App::Index;use App::Base -controller, with => ['App::News', 'App::Book', 'App::Audio'];

sub main { ... }

Page 77: Почему Mojolicious?

package App::Index;use Mojo::Base 'Mojolicious::Controller';use common::sense;

use App::News;use App::Book;use App::Audio;

has news => sub { App::News->new(%{ +shift }) };has book => sub { App::Book->new(%{ +shift }) };has audio => sub { App::Audio->new(%{ +shift }) };

Page 78: Почему Mojolicious?

package App::Index;use Mojo::Base 'Mojolicious::Controller';use common::sense;

use App::News;use App::Book;use App::Audio;

__PACKAGE__->attr(news => sub { App::News->new(%{ +shift }) });__PACKAGE__->attr(book => sub { App::Book->new(%{ +shift }) });__PACKAGE__->attr(audio => sub { App::Audio->new(%{ +shift }) };

Page 79: Почему Mojolicious?

Mojo::Base vs. App::Basecommon::sense, -controller, with

Page 80: Почему Mojolicious?

package App::Index;use App::Base -controller, with => ['App::News', 'App::Book', 'App::Audio'];

sub main { ... }

Page 81: Почему Mojolicious?

my $self = shift;my $limit = $self->conf('limit')->{index};

$self->render('index', news => $self->news->_last(limit => $limit->{news}), book => $self->book->_list, part => $self->audio->_last(limit => $limit->{part}),);

Page 82: Почему Mojolicious?

App::Book Контроллер

Page 83: Почему Mojolicious?

package App::Book;use App::Base -controller;

sub check { ... } # для bridge

sub list { ... }

sub item { ... }

sub _list { ... } # возращает данные

Page 84: Почему Mojolicious?

sub check { my $self = shift; return 0 unless my $book = $self->dw->book( $self->db->select( 'select * from book where name=? limit 1', $self->stash('book_name') ) )->[0]; $self->stash(book => $book); return 1;}

Page 85: Почему Mojolicious?

sub item { my $self = shift; my $book = $self->stash('book'); ...}

# роутеры

my $bn = $r->bridge('/book/:book_name')->to('book#check');

$bn->route->to('book#item')->name('book');

Page 86: Почему Mojolicious?

tmpl/

Page 87: Почему Mojolicious?

index.html.epШаблон

$r->route->to('index#main');

Page 88: Почему Mojolicious?

% layout 'default', title => '...';

<div id="column1">% for (@$news) { %== include 'news/item.inc', item => $_% }</div>

<span class="date"> %=u iso2humanM => $_->{published}</span>

<span class="download_count"> <%= format_digital($_->{listened}) %> раз</span>

Page 89: Почему Mojolicious?

$newsvs.

stash 'news'

Page 90: Почему Mojolicious?

layouts/default.html.eplayouts/default.mail.ep layouts/default.rss.eplayouts/admin.html.ep

Page 91: Почему Mojolicious?

etc/page.html.epetc/submenu.html.epadmin/etc/sort.txt.ep

Page 92: Почему Mojolicious?

Ни в коем случае сложной логики, тем более SQL :-)

Page 93: Почему Mojolicious?

exception.html.epexception.mail.ep

exception.dev.html.ep

Page 94: Почему Mojolicious?

% layout 'default', title => 'Страница временно недоступна', simple => 1;

<div class="error_page">Ошибка 500. Страница временно недоступна. Попробуйте позднее.</div>

% mail(to => conf('mail')->{devel}, template => 'exception', format => 'mail');

Page 95: Почему Mojolicious?

stash и defaultsСправочники и работа с ними

Page 96: Почему Mojolicious?

include 'etc/vars'Раньше был шаблон, который подключался везде

Page 97: Почему Mojolicious?

# app.confdefaults => { book_status => [ [soon => 'Готовится к изданию'], ..., [new => 'Новинки'], ], ...}

Page 98: Почему Mojolicious?

# App.pmif (my $d = $conf->{defaults}) { $self->defaults( $d ); for (keys %$d) { next unless ref $d->{$_} eq 'ARRAY'; $self->defaults($_ . '_hash' => { map { $_->[0] => $_->[1] } @{ $d->{$_} } }); }}

Page 99: Почему Mojolicious?

# в шаблоне

@$book_status

# или

$book_status_hash->{new}

Page 100: Почему Mojolicious?

Работы с формами

Page 101: Почему Mojolicious?

Я не использую никаких генераторов

форм

Page 102: Почему Mojolicious?

Формы для пользователей и модель данных — разные вещи

Page 103: Почему Mojolicious?

# App::Admin::Booksub add { my $self = shift; return $self->form unless $self->validate->book; # работа с полученными данными}

sub edit { my $self = shift; my $item = $self->stash('item'); # через bridge return $self->form unless $self->validate->book; ...}

Page 104: Почему Mojolicious?

admin/book/form.html.epШаблон может быть один

Page 105: Почему Mojolicious?

В итоге получаются очень простые контроллеры и шаблоны

Page 106: Почему Mojolicious?

И весь проект в целом

Page 107: Почему Mojolicious?

Вспомогательные скрипты

Рассылка по пользователям, графики для munin,cron-скрипты

Page 108: Почему Mojolicious?

# script/munin/user.pl

use MojoX::Loader;my $user = MojoX::Loader->load( controller => 'App::User');

say $user->_total;

# $user->db->select(...);# $user->conf('server')->{www}# $user->render_partial('...', stash1 => '..', stash2 => '..')# $user->mail(to => '..', template => '..')

Page 109: Почему Mojolicious?

MojoX::Loaderhttps://github.com/sharifulin/mojox-loader

Page 110: Почему Mojolicious?

Mojolicious очень удобный и простой инструмент

Page 111: Почему Mojolicious?

С большим количеством современных фитч

Page 112: Почему Mojolicious?

Хороший open source проект

Page 113: Почему Mojolicious?

Активное сообщество

Page 114: Почему Mojolicious?

И в принципе адекватый автор :-)

Page 115: Почему Mojolicious?

«Удивлен насколько легко читается код, даже для человека, который Perl видит второй раз в жизни»

Page 116: Почему Mojolicious?

Попробуйте Mojolicious прямо

сейчас!

Page 117: Почему Mojolicious?

Не будьте

Page 118: Почему Mojolicious?

«I am just slow to get things...»

http://frd.io/gf6

Page 119: Почему Mojolicious?

use Mojolicious or die;

Page 120: Почему Mojolicious?

use Perl or die;

Page 121: Почему Mojolicious?

JFDI

Page 122: Почему Mojolicious?

Спасибо за внимание!Анатолий Шарифулин

YAPC::Russia 2011

Page 123: Почему Mojolicious?

Mojolicous by @vti