Mojolicious
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

Mojolicious

on

  • 1,355 views

 

Statistics

Views

Total Views
1,355
Views on SlideShare
1,354
Embed Views
1

Actions

Likes
0
Downloads
4
Comments
0

1 Embed 1

http://www.linkedin.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Mojolicious Presentation 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