Почему Mojolicious?

6,229 views
6,111 views

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
6,229
On SlideShare
0
From Embeds
0
Number of Embeds
2,882
Actions
Shares
0
Downloads
25
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Почему 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

×