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

Post on 09-Jun-2015

1.284 views 0 download

description

Perl Mova + YAPC::Russia 2010

Transcript of Mojolicious. Веб в коробке!

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

Perl Mova + YAPC::Russia 2010

Что такое Mojolicious?

Что такое Mojolicious?

• Веб-фреймворки: Mojolicious::Lite, Mojolicious, Mojo

• Объектно-ориентированное API, без скрытой магии и зависимостей, написанное на чистом Perl

• Полный стек HTTP 1.1 и WebSocket #76(клиент-сервер), а также IPv6, SSL и IDNA

Что такое Mojolicious?

• Асинхронный ввод-вывод, prefork-веб сервер с поддержкой epoll и kqueue, unix-сокетов и «горячей» разработки

• CGI, FastCGI и PSGI

• RESTful-роутеры, плагины, сессии, Perl-ish шаблонизатор, поддержка I18N, JSON и XML DOM с CSS3-селекторами

«Свежий» код, основанный на опыте разработке Catalyst

«Весёлая ферма» Mojolicious

CGI FastCGI PSGI HTTP 1.1 WebSocket

Mojo

Mojolicious

Mojolicious::Lite

Код

Удовольствие!

Код

Mojolicious::LiteMVC веб-фреймворк

~ sinatra

use Mojolicious::Lite;

get '/hello' => sub { shift->render_text( 'Привет Киев!' );};

app->start;

use Mojolicious::Lite;

post '/hello' => sub { shift->render_text( 'Привет Киев!' );};

app->start;

use Mojolicious::Lite;

any '/hello' => sub { shift->render_text( 'Привет Киев!' );};

app->start;

use Mojolicious::Lite;

get '/hello' => (agent => qr/Firefox/) => sub { shift->render_text( 'Привет Киев!' );};

app->start;

use Mojolicious::Lite;

post '/:name' => sub { # /* my $self = shift; my $name = $self->param('name');

$self->render_text( "Привет $name!" );};

app->start;

use Mojolicious::Lite;

post '/:name' => sub { # /* my $self = shift; my $name = $self->stash('name');

$self->render_text( "Привет $name!" );};

app->start;

use Mojolicious::Lite;

post '/:name' => { id => 42 } => sub { # /* my $self = shift; my $name = $self->param('name'); warn $self->param( 'id' ); $self->render_text( "Привет $name!" );};

app->start;

use Mojolicious::Lite;

any '/time' => 'clock';

app->start;

__DATA__

@@ clock.html.ep% my ($sec, $min, $hour) = (localtime)[0, 1, 2];Текущее время <%= $hour %>:<%= $min %>:<%= $sec %>

use Mojolicious::Lite;

websocket '/echo' => sub { my $self = shift; $self->receive_message( sub { my ($self, $msg) = @_; $self->send_message( "тук-тук: $msg" ); } );};

Примеры Mojolicious WebSocket

@xantus, @vtiИнтересный пример IRC-клиент

use Mojolicious::Lite;

get '/fetch' => sub { my $self = shift; $self->render_data( $self->client ->get( 'http://2010.yapcrussia.org' ) ->res ->body );};

use Mojolicious::Lite;

plugin charset => { charset => 'UTF-8' };

#

under sub { my $self = shift;

# проверка авторизации };get '/foo' => sub { ... };

Cписок всех роутеров приложения

script/lite.pl routes/hello (?-xism:^/hello)/time (?-xism:^/time)/echo (?-xism:^/echo)/fetch (?-xism:^/fetch)/:name (?-xism:^/((?-xism:\d+)))

Если много шаблонов в секции __DATA__script/lite.pl inflate

/templates//templates/clock.html.ep

Сокращатель ссылокна Mojolicious::Lite

100 строк кода (5 обработчиков)130 строк шаблонов (4 шаблона)

1 файл

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

~ Ruby on Rails

package App;use base 'Mojolicious';

sub startup { my $self = shift; my $r = $self->routes; $r->route('/:controller/:action/:id') ->to('example#welcome', id => 1);}

1;

package App;use base 'Mojolicious';

sub startup { my $self = shift; my $r = $self->routes; $r->route('/:controller/:action/:id') ->to('example#welcome', id => 1);}

1;

package App;use base 'Mojolicious';

sub startup { my $self = shift; my $r = $self->routes; $r->route('/:controller/:action/:id') ->to('example#welcome', id => 1);}

1;

package App;use base 'Mojolicious';

sub startup { my $self = shift; my $r = $self->routes; $r->route('/:controller/:action/:id') ->to('example#welcome', id => 1);}

1;

package App;use base 'Mojolicious';

sub startup { my $self = shift; my $r = $self->routes; my $b = $r->bridge->to('auth#check); $b->route('/admin')->to('admin#welcome');}

package App;use base 'Mojolicious';

sub startup { my $self = shift; $self->plugin(charset => { ... }); $self->types->type(json => 'text/plain'); $self->renderer->root( ... );}

1;

package App;use base 'Mojolicious';

sub startup { my $self = shift; my $r = $self->routes; $r->route('/:controller/:action/:id') ->to('example#welcome', id => 1);}

1;

package App::Example;use base 'Mojolicious::Controller';

sub welcome { my $self = shift; warn $self->param( ‘id’ ); $self->render( message => 'Привет Киев!' );}

1;

package App::Example;use base 'Mojolicious::Controller';

sub welcome { my $self = shift; warn $self->stash( ‘id’ ); $self->render( message => 'Привет Киев!' );}

1;

Шаблонexample/welcome.html.ep

controller / action . format . handler

Шаблонexample/welcome.xml.ep

controller / action . format . handler

Шаблонexample/welcome.rss.ep

controller / action . format . handler

Шаблонexample/welcome.mail.ep

controller / action . format . handler

Шаблонexample/welcome.html.ep

controller / action . format . handler

Шаблонexample/welcome.html.ep

controller / action . format . handler

Шаблонexample/welcome.html.tt

controller / action . format . handler

Шаблонexample/welcome.html.cttp2

controller / action . format . handler

Шаблонexample/welcome.html.ep

controller / action . format . handler

% layout 'default';

<h2><%= $message %></h2>

<a href="<%== url_for %>">click here</a>

% layout 'default';

<h2><%= $message %></h2>

<a href="<%== url_for %>">click here</a>

% layout 'default';

<h2><%= stash 'message' %></h2>

<a href="<%== url_for %>">click here</a>

% layout 'default';

<h2><%= $self->stash('message') %></h2>

<a href="<%== url_for %>">click here</a>

% layout 'default';

<h2><%= $message2 %></h2>

<a href="<%== url_for %>">click here</a>

Global symbol "$message2" requires explicit package name at (eval 280) line 2.

1: % layout 'default';2: <h2><%= $message2 %></h2>3: ...

{ 'status' => 500, 'message' => ‘Привет Киев!’, ...

% layout 'default';

<h2><%= $message if is_iphone %></h2>

<a href="<%== url_for %>">click here</a>

sub startup { ... $self->renderer->add_helper( is_iphone => sub { shift->tx->req->headers ->user_agent =~ /iphone|cfnetwork/i ? 1 : 0 });

Шаблонlayouts/default.html.epпуть к layout-шаблонам / имя . format . handler

<!doctype html><html> <head><title> Привет! </title></head> <body> <%== content %> </body></html>

Около 20 проектовна Mojolicious

MojoБазовый веб-фреймворк

package App;use base 'Mojo';

sub handler { my ($self, $tx) = @_; warn $tx->req; warn $tx->req->url; $tx->res->headers ->content_type( 'text/plain' ); $tx->res->body( 'Привет Киев!' );}

package App;use base 'Mojo';

sub handler { my ($self, $tx) = @_; warn $tx->req; warn $tx->req->url; $tx->res->headers ->content_type( 'text/plain' ); $tx->res->body( 'Привет Киев!' );}

GET / HTTP/1.1Connection: keep-aliveAccept: text/html, application/xhtml, ....Accept-Charset: windows-1251, utf-8; ...Accept-Encoding: gzip,deflateAccept-Language: ru,en-us;q=0.7,en;q=0.3Host: localhost:3000User-Agent: Mozilla/5.0 (Macintosh; ...Content-Length: 0Keep-Alive: 300

package App;use base 'Mojo';

sub handler { my ($self, $tx) = @_; warn $tx->req; warn $tx->req->url; $tx->res->headers ->content_type( 'text/plain' ); $tx->res->body( 'Привет Киев!' );}

Mojo::ClientHTTP 1.1 и WebSocket клиент

my $client = Mojo::Client->new;

$client->get( ‘http://2010.yapcrussia.org’ => sub { my ($self, $tx) = @_; say $tx->res; })->process;

my $client = Mojo::Client->new;

$client->get( ‘http://2010.yapcrussia.org’ => sub { ... },);$client->post( ‘http://2010.yapcrussia.ru’ => sub { ... },);

$client->process;

my $client = Mojo::Client->new;

$client->get(‘http://goo.gl’)->res->code;

$client->get( 'http://search.twitter.com/trends.json')->success->json->{trends}->[0]->{name}

$client->get( ... )->dom->success ->search('body > #container > div p[id]')

Mojo::IOLoopTCP клиент-сервер

my $loop = Mojo::IOLoop->new;

$loop->listen(port => 3000, cb => sub { my ($self, $id) = @_; $self->read_cb ($id => sub { ... });

$self->write_cb($id => sub { ... }););

my $id = $loop->connect(port => 3000, ...);

$loop->start; $loop->stop;

Test::MojoФреймворк для тестирования

my $t = Test::Mojo->new( app => 'App' );

$t->get_ok( '/hello' ) ->status_is( 200 ) ->header_is( 'X-Powered-By' => 'Mojolicious (Perl)' ) ->content_is( 'Привет Киев!' );

$t->post_ok( '/42' ) ->content_like(qr/Привет/, 'тест пройден!');

Всё, что нужно – есть!Mojolicious – веб в коробке!

Если нет, то есть на CPAN

или github.com :)

Mojolicious на CPAN• Mojolicious

• Mojo::Server::FCGI

• AnyEvent::Mojo

• Apache::Mojo

Apache2::Mojo

• Catalyst::Engine::MojoSquatting::On::Mojo

• MojoX::Log::*

• MojoX::Renderer::*

• TT

• CTTP2, HTP

• XSLT

• Mail

Модель, где же модель данных?А говорите всё есть :)

Любая модель данных может быть использована

в MojoliciousDBI, DBIx::Class, Fey::ORM, CouchDB, MongoDB, ...

Документация

• Пока мало документации, зато очень хороший фидбек :)

• Mojolicious::Lite и Mojolicious::Guides

• Mojolicious Handbook @kvorg

• Mojolicious FAQ @vti

«Making hard things possible and everything fun!»

Девиз Mojolicious

«Duct tape for the HTML5 Web»

Девиз Mojolicious #2

«Viva la revolution!»

Девиз Mojolicious #3

Mojolicious::Lite vs.

DancerСоревнование

Mojoliciousvs.

CatalystЧто выбрать?

«Особая разновидность современного программиста – программист, изучающий

фреймворки»Алекс Капранов

Анатолий Шарифулин

«Каждый программист должен сделать 3 вещи: фреймворк, шаблонизатор и событийную машину»

use Mojoliciousor die

Viva la revolution!

use Perlor die

JFDI

Посмотрите, какие у меня крутые часы :)

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

sharifulin

any ‘/questions’ => sub { shift->render( answer => ‘sharifulin’ ); };