Mojolicious
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
1,388
On Slideshare
1,387
From Embeds
1
Number of Embeds
1

Actions

Shares
Downloads
4
Comments
0
Likes
0

Embeds 1

http://www.linkedin.com 1

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

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