Your SlideShare is downloading. ×
0
Почему Mojolicious?     Анатолий Шарифулин      YAPC::Russia 2011
mojolicio.us
Кто знает, что такое    Mojolicious?
Кто использует Mojolicious?
На кого повлиял я? :)
Коротко
Современный и   молодойвеб-фреймворк
Веб в коробке!
Mojo::BaseMojo::DOM, Mojo::JSON   Mojo::UserAgent     Mojo::IOLoop    Mojo::Template
Mojo MojoliciousMojolicious::Lite
Test::Mojo   ojo     ...
385 вотчеров 88 форков По данным github.com
и один Шарифулин :-)      По моему мнению
Почему всё-таки   Mojolicious?Когда есть Dancer, Plack, Python и Node.js
Помогает решитьпочти любую задачу     Почему Mojolicious?
Начиная от простого сайта в 5 страниц     Почему Mojolicious?
tochkak.ru
use Mojolicious::Lite;get /      => about/what ;get /who => about/who ;get /what => about/what ;get /where => about/where;...
Заканчивая стартапомc 5000+ пользователями       Почему Mojolicious?
frodio.com
илиузкоспециализированной  системой управления    для кинотеатров       Почему Mojolicious?
db.dcp24.ru
От простых скриптов     Почему Mojolicious?
#!/usr/bin/env perluse ojo;g( http://bobina.pdj.ru/rss.xml )	 ->dom   	 ->find( enclosure[url] )	 ->each(sub {	 	 say shift...
или TCP-клиента длясотни радио-потоков     Почему Mojolicious?
my $url = Mojo::URL->new(	 http://frod.io:8000/station20);$loop->connect(	 address       => $url->host,	 port           =>...
on_connect => sub {	 	 my ($self, $id) = @_;	 		 	 my $r = Mojo::Message::Request->new;	 	 $r->headers->header(           ...
on_read => sub {	 my ($self, $id, $chunk) = @_;	 return unless my %tag =	 	 $chunk =~ /Stream(w+)=(.*?);/g;		 say $tag{Tit...
До софта по   тиражированию     фильмов дляцифровых кинотеатров      Почему Mojolicious?
CopyDisk
Mojo::Base  Mojo::Log MojoX::RunCurses::Widgets
А также тесты для  веб-сервисов    Почему Mojolicious?
use Test::More tests => 252;use Test::Mojo;my $t = Test::Mojo->new(app => App); # App.pmmy $url = /api;# my $url = http://...
my $data = $t->post_form_ok("$url/like",{station_id => 2}, {X-Frodio-Auth => $auth})   ->status_is(200)   ->tx->res->json;...
$t->post_form_ok("$url/logout/",	 {X-Frodio-Auth => $auth})   ->status_is(200);
Большинство своих   задач я решаю,используя Mojolicious
«Всегда хотелнаучиться делать     сайты»
etnogenez.ru
Небольшой сайт сполноценной панелью     управления26 модулей (140k), 91 шаблон (408k), 16 таблиц
Структура проектаВсе пути и запуски — от корня проекта
bin/conf/data/lib/log/script/t/tmpl/tmp/
bin/check.shbin/logs.shbin/mysqlbin/mysqldumpbin/restart.shbin/start.shbin/stop.sh
bin/start.sh
(	 # script/etnogenez daemon --reload	 starman --listen :3000 script/etnogenez) >> log/error.log &
conf/app.confconf/mysql.confconf/nginx.conf
conf/app.conf
{	   secret => *****,	   server => {	   	 www => $ENV{DEV} ? http://... : http:/...,	   	 ...	   },	   session => { ... },...
conf/mysql.conf
{	   drivername => mysql,	   user           => $ENV{DEV} ? dev : не-dev,	   password       => ******,	   datasource => {	 ...
data/ log/tmp/  t/
script/
Стартовый скриптПути к библиотекам, настройка переменных               окружения
use common::sense;use lib qw(lib /tk/lib);BEGIN {	 $ENV{DEV}++ if qx(pwd) =~ /dev/;	 $ENV{MOJO_MODE} ||= $ENV{DEV} ? dev :...
lib/
App.pm
package App;use Mojo::Base Mojolicious;has conf => sub { do conf/app.conf };has db => sub { use Util; Util->db(	 do conf/m...
use DBI 1.58; use DBD::mysql 4.004; use DBI::Util;return DBI->connect(DBI::Util::_parse_cfg(	 $conf,	 {	 	 RootClass => DB...
selectquery   in limitvalues
use dw;Lazy-обертка, связи parent/child и прочее       Контекстно проекту и БД
sub book { my $self = shift;	 SLICELY { $self->dw::g::part (book_id) } id => part =>	 ...}sub part { my $self = shift;	 SL...
sub _list {	 my $self = shift;	 ...		 return $self->dw->book(	 	 $self->db->select(	 	 	 "select * from book where hidden=...
bin/mysqlС базой данной работаю через консоль
Настройка путей,логов, сессий, типов        startup
Подключениеплаггинов и хелперов        startup
$app->helper(db => sub { shift->app->db });sub action {	 my $self = shift;	 # my $DB = $self->app->db;	 $self->db->select(...
$app->helper(u => sub {	 	 my $self = shift;	 	 my $func = shift || return;	 		 	 return &{"Util::$func"};	 });$self->u(is...
# в каждом контроллереuse Util;# в шаблоне или кодеUtil::iso2human(...);# это boilercode и некрасиво# поэтому хелпер
Общие иконтексно проекта     хелперыMojolicious::Plugin::UtilHelpers и App::Helpers
Все роутеры проекта        startup
route, bridge, waypoint,    name, shortcut     Mojolicious::Guides::Routing
my $ad = $r->route(/admin)->to->name(admin);$ad->route(/login)->post->to(admin-enter#login);	my $a = $ad->bridge->to(admin...
App::HelpersРазличные форматирования, работы со строками,          повторяющиеся действия
$app->helper(format_mmss => sub {	   	 my $self = shift;	   	 my $int = shift || return 00:00;	   		   	 return sprintf "%...
$app->helper(user_img => sub {	   	 my $self = shift;	   	 my $user = shift || $self->stash(USER);	   		   	 return $user-...
App::Index        Контроллер$r->route->to(index#main);
package App::Index;use App::Base -controller, with =>[App::News, App::Book, App::Audio];sub main { ... }
package App::Index;use Mojo::Base Mojolicious::Controller;use common::sense;use App::News;use App::Book;use App::Audio;has...
package App::Index;use Mojo::Base Mojolicious::Controller;use common::sense;use App::News;use App::Book;use App::Audio;__P...
Mojo::Base vs. App::Base    common::sense, -controller, with
package App::Index;use App::Base -controller, with =>[App::News, App::Book, App::Audio];sub main { ... }
my $self = shift;my $limit = $self->conf(limit)->{index};$self->render(index,	 news => $self->news->_last(limit =>$limit->...
App::Book  Контроллер
package App::Book;use App::Base -controller;sub check { ... } # для bridgesub list { ... }sub item { ... }sub _list { ... ...
sub check {	 my $self = shift;		 return 0 unless my $book = $self->dw->book(	 	 $self->db->select(	 	 	 select * from book...
sub item {	 my $self = shift;	 my $book = $self->stash(book);	 ...}# роутерыmy $bn = $r->bridge(/book/:book_name)->to(book...
tmpl/
index.html.ep          Шаблон$r->route->to(index#main);
% layout default, title => ...;<div id="column1">% for (@$news) {	 %== include news/item.inc, item => $_%}</div><span clas...
$news     vs.stash news
layouts/default.html.eplayouts/default.mail.ep  layouts/default.rss.ep layouts/admin.html.ep
etc/page.html.epetc/submenu.html.epadmin/etc/sort.txt.ep
Ни в коем случаесложной логики, тем   более SQL :-)
exception.html.ep  exception.mail.epexception.dev.html.ep
% layout default, title => Страница временнонедоступна, simple => 1;<div class="error_page">Ошибка 500. Страницавременно н...
stash и defaultsСправочники и работа с ними
include etc/varsРаньше был шаблон, который подключался везде
# app.confdefaults => {	 book_status => [	 	 [soon => Готовится к изданию],	 	 ...,	 	 [new => Новинки],	 ],	 ...}
# App.pmif (my $d = $conf->{defaults}) {	 	 $self->defaults( $d );	 		 	 for (keys %$d) {	 	 	 next unless ref $d->{$_} eq...
# в шаблоне@$book_status# или$book_status_hash->{new}
Работы с формами
Я не используюникаких генераторов       форм
Формы для пользователей имодель данных —  разные вещи
# App::Admin::Booksub add {	 my $self = shift;	 return $self->form unless $self->validate->book;	 # работа с полученными д...
admin/book/form.html.epШаблон может быть один
В итоге получаются  очень простые  контроллеры и     шаблоны
И весь проект в целом
Вспомогательные      скриптыРассылка по пользователям, графики для munin,                cron-скрипты
# script/munin/user.pluse MojoX::Loader;my $user = MojoX::Loader->load(	 controller => App::User);say $user->_total;# $use...
MojoX::Loaderhttps://github.com/sharifulin/mojox-loader
Mojolicious оченьудобный и простой   инструмент
С большим количеством  современных фитч
Хороший open source     проект
Активное сообщество
И в принципеадекватый автор :-)
«Удивлен наскольколегко читается код, даже для человека,который Perl видитвторой раз в жизни»
ПопробуйтеMojolicious прямо     сейчас!
Не будьте
«I am just slow to get      things...»       http://frd.io/gf6
use Mojolicious or die;
use Perl or die;
JFDI
Спасибо за внимание!     Анатолий Шарифулин      YAPC::Russia 2011
Mojolicous by @vti
Upcoming SlideShare
Loading in...5
×

Почему Mojolicious?

5,944

Published on

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

Published in: Education
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
5,944
On Slideshare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
25
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Transcript of "Почему Mojolicious?"

  1. 1. Почему Mojolicious? Анатолий Шарифулин YAPC::Russia 2011
  2. 2. mojolicio.us
  3. 3. Кто знает, что такое Mojolicious?
  4. 4. Кто использует Mojolicious?
  5. 5. На кого повлиял я? :)
  6. 6. Коротко
  7. 7. Современный и молодойвеб-фреймворк
  8. 8. Веб в коробке!
  9. 9. Mojo::BaseMojo::DOM, Mojo::JSON Mojo::UserAgent Mojo::IOLoop Mojo::Template
  10. 10. Mojo MojoliciousMojolicious::Lite
  11. 11. Test::Mojo ojo ...
  12. 12. 385 вотчеров 88 форков По данным github.com
  13. 13. и один Шарифулин :-) По моему мнению
  14. 14. Почему всё-таки Mojolicious?Когда есть Dancer, Plack, Python и Node.js
  15. 15. Помогает решитьпочти любую задачу Почему Mojolicious?
  16. 16. Начиная от простого сайта в 5 страниц Почему Mojolicious?
  17. 17. tochkak.ru
  18. 18. 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;
  19. 19. Заканчивая стартапомc 5000+ пользователями Почему Mojolicious?
  20. 20. frodio.com
  21. 21. илиузкоспециализированной системой управления для кинотеатров Почему Mojolicious?
  22. 22. db.dcp24.ru
  23. 23. От простых скриптов Почему Mojolicious?
  24. 24. #!/usr/bin/env perluse ojo;g( http://bobina.pdj.ru/rss.xml ) ->dom ->find( enclosure[url] ) ->each(sub { say shift->attrs->{url} });
  25. 25. или TCP-клиента длясотни радио-потоков Почему Mojolicious?
  26. 26. 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;
  27. 27. 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);},
  28. 28. on_read => sub { my ($self, $id, $chunk) = @_; return unless my %tag = $chunk =~ /Stream(w+)=(.*?);/g; say $tag{Title};},
  29. 29. До софта по тиражированию фильмов дляцифровых кинотеатров Почему Mojolicious?
  30. 30. CopyDisk
  31. 31. Mojo::Base Mojo::Log MojoX::RunCurses::Widgets
  32. 32. А также тесты для веб-сервисов Почему Mojolicious?
  33. 33. 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! });
  34. 34. 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;}
  35. 35. $t->post_form_ok("$url/logout/", {X-Frodio-Auth => $auth}) ->status_is(200);
  36. 36. Большинство своих задач я решаю,используя Mojolicious
  37. 37. «Всегда хотелнаучиться делать сайты»
  38. 38. etnogenez.ru
  39. 39. Небольшой сайт сполноценной панелью управления26 модулей (140k), 91 шаблон (408k), 16 таблиц
  40. 40. Структура проектаВсе пути и запуски — от корня проекта
  41. 41. bin/conf/data/lib/log/script/t/tmpl/tmp/
  42. 42. bin/check.shbin/logs.shbin/mysqlbin/mysqldumpbin/restart.shbin/start.shbin/stop.sh
  43. 43. bin/start.sh
  44. 44. ( # script/etnogenez daemon --reload starman --listen :3000 script/etnogenez) >> log/error.log &
  45. 45. conf/app.confconf/mysql.confconf/nginx.conf
  46. 46. conf/app.conf
  47. 47. { secret => *****, server => { www => $ENV{DEV} ? http://... : http:/..., ... }, session => { ... }, log => { level => $ENV{DEV} ? debug : warn, path => log/app.log, }, ...}
  48. 48. conf/mysql.conf
  49. 49. { drivername => mysql, user => $ENV{DEV} ? dev : не-dev, password => ******, datasource => { database => $ENV{DEV} ? dev : не-dev, host => localhost, },};
  50. 50. data/ log/tmp/ t/
  51. 51. script/
  52. 52. Стартовый скриптПути к библиотекам, настройка переменных окружения
  53. 53. 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;
  54. 54. lib/
  55. 55. App.pm
  56. 56. 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 { ... }
  57. 57. 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, }));
  58. 58. selectquery in limitvalues
  59. 59. use dw;Lazy-обертка, связи parent/child и прочее Контекстно проекту и БД
  60. 60. 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 => ...}
  61. 61. sub _list { my $self = shift; ... return $self->dw->book( $self->db->select( "select * from book where hidden=0 order by $order $limit" ) );}
  62. 62. bin/mysqlС базой данной работаю через консоль
  63. 63. Настройка путей,логов, сессий, типов startup
  64. 64. Подключениеплаггинов и хелперов startup
  65. 65. $app->helper(db => sub { shift->app->db });sub action { my $self = shift; # my $DB = $self->app->db; $self->db->select(...);}
  66. 66. $app->helper(u => sub { my $self = shift; my $func = shift || return; return &{"Util::$func"}; });$self->u(iso2human => ...);%=u iso2human => ...
  67. 67. # в каждом контроллереuse Util;# в шаблоне или кодеUtil::iso2human(...);# это boilercode и некрасиво# поэтому хелпер
  68. 68. Общие иконтексно проекта хелперыMojolicious::Plugin::UtilHelpers и App::Helpers
  69. 69. Все роутеры проекта startup
  70. 70. route, bridge, waypoint, name, shortcut Mojolicious::Guides::Routing
  71. 71. 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);
  72. 72. App::HelpersРазличные форматирования, работы со строками, повторяющиеся действия
  73. 73. $app->helper(format_mmss => sub { my $self = shift; my $int = shift || return 00:00; return sprintf "%02d:%02d", $int / 60, $int % 60; });
  74. 74. $app->helper(user_img => sub { my $self = shift; my $user = shift || $self->stash(USER); return $user->{avatar} || /.../default.png; });
  75. 75. App::Index Контроллер$r->route->to(index#main);
  76. 76. package App::Index;use App::Base -controller, with =>[App::News, App::Book, App::Audio];sub main { ... }
  77. 77. 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 }) };
  78. 78. 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 }) };
  79. 79. Mojo::Base vs. App::Base common::sense, -controller, with
  80. 80. package App::Index;use App::Base -controller, with =>[App::News, App::Book, App::Audio];sub main { ... }
  81. 81. 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}),);
  82. 82. App::Book Контроллер
  83. 83. package App::Book;use App::Base -controller;sub check { ... } # для bridgesub list { ... }sub item { ... }sub _list { ... } # возращает данные
  84. 84. 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;}
  85. 85. 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);
  86. 86. tmpl/
  87. 87. index.html.ep Шаблон$r->route->to(index#main);
  88. 88. % 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>
  89. 89. $news vs.stash news
  90. 90. layouts/default.html.eplayouts/default.mail.ep layouts/default.rss.ep layouts/admin.html.ep
  91. 91. etc/page.html.epetc/submenu.html.epadmin/etc/sort.txt.ep
  92. 92. Ни в коем случаесложной логики, тем более SQL :-)
  93. 93. exception.html.ep exception.mail.epexception.dev.html.ep
  94. 94. % layout default, title => Страница временнонедоступна, simple => 1;<div class="error_page">Ошибка 500. Страницавременно недоступна. Попробуйте позднее.</div>% mail(to => conf(mail)->{devel}, template =>exception, format => mail);
  95. 95. stash и defaultsСправочники и работа с ними
  96. 96. include etc/varsРаньше был шаблон, который подключался везде
  97. 97. # app.confdefaults => { book_status => [ [soon => Готовится к изданию], ..., [new => Новинки], ], ...}
  98. 98. # 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->{$_} } }); }}
  99. 99. # в шаблоне@$book_status# или$book_status_hash->{new}
  100. 100. Работы с формами
  101. 101. Я не используюникаких генераторов форм
  102. 102. Формы для пользователей имодель данных — разные вещи
  103. 103. # 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; ...}
  104. 104. admin/book/form.html.epШаблон может быть один
  105. 105. В итоге получаются очень простые контроллеры и шаблоны
  106. 106. И весь проект в целом
  107. 107. Вспомогательные скриптыРассылка по пользователям, графики для munin, cron-скрипты
  108. 108. # script/munin/user.pluse 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 => ..)
  109. 109. MojoX::Loaderhttps://github.com/sharifulin/mojox-loader
  110. 110. Mojolicious оченьудобный и простой инструмент
  111. 111. С большим количеством современных фитч
  112. 112. Хороший open source проект
  113. 113. Активное сообщество
  114. 114. И в принципеадекватый автор :-)
  115. 115. «Удивлен наскольколегко читается код, даже для человека,который Perl видитвторой раз в жизни»
  116. 116. ПопробуйтеMojolicious прямо сейчас!
  117. 117. Не будьте
  118. 118. «I am just slow to get things...» http://frd.io/gf6
  119. 119. use Mojolicious or die;
  120. 120. use Perl or die;
  121. 121. JFDI
  122. 122. Спасибо за внимание! Анатолий Шарифулин YAPC::Russia 2011
  123. 123. Mojolicous by @vti
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×