Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Mojoliciousでつくる! Webアプリ入門

Mojoliciousでつくる! Webアプリ入門

2013/09/21
YAPC::Asia 2013
Yusuke Wada a.k.a. yusukebe

Yusuke Wada

May 07, 2023
Tweet

More Decks by Yusuke Wada

Other Decks in Programming

Transcript

  1. ϋογϡؔ਺ my $name = "yusukebe"; my $max = 3; my

    $number = 0; # จࣈྻΛҰจࣈͣͭ෼ղ for my $char (split //, $name) { # จࣈʹରԠ͢Δ਺஋ΛಘΔ $number += ord $char; } # ૝ఆ͞ΕΔ࠷େ஋Ͱׂͬͨ༨ΓΛಘΔ my $result = $number % $max; print "$result\n"; จࣈྻ ਺஋ ݻఆ஋ͰׂΔ ༨Γ͕݁Ռ
  2. Կ͕Πέͯͳ͍ͬͯʁ w ৭ʑࠞͬͯ͡Δ w ϔομʔग़ྗ w ϩδοΫॲཧ w )5.-ͷඳը w

    ϑΝΠϧ͝ͱʹϧʔςΟϯά͢Δ w ॏෳ͕ى͜Δ ˎ$(*͸σϓϩΠํ๏ͷ ҰͭͳͷͰ$(*ࣗମ͕ ྑ͘ͳ͍Θ͚Ͱ͸ͳ͍
  3. ۪௚ʹDHJΛॻ͘ͱ use CGI qw/param header/; my $name = param('name'); my

    @list = qw/ྑ͍ࣄ͕ى͜ΔͰ͠ΐ͏ ग़ձ͍͕͋Δ͔΋ʁ ෆ޾ʹͳΓ·͢/; my $num = 0; $num += ord ($_) for split //, $name; my $index = $num % scalar @list; my $message = $list[$index]; print header('text/html; charset=utf-8'); print "<html><body>"; print "<center><b>$message</b></center>"; print "</body></html>";
  4. )5.-͚ͩͰ΋෼཭ͤ͞Δͱ use CGI qw/param header/; use Text::MicroTemplate qw/render_mt/; use Data::Section::Simple

    qw/get_data_section/; my $name = param('name'); my @list = qw/ྑ͍ࣄ͕ى͜ΔͰ͠ΐ͏ ग़ձ͍͕͋Δ͔΋ʁ ෆ޾ʹͳΓ·͢/; my $num = 0; $num += ord ($_) for split //, $name; my $index = $num % scalar @list; my $message = $list[$index]; my $template = get_data_section('index.mt'); my $html = render_mt($template, $message)->as_string(); print header('text/html; charset=utf-8'); print $html; __DATA__ @@ index.mt <html> <body> <center><b><?= $_[0] ?></b></center> </body> </html>
  5. ੾Γ෼͚ํ  3PVUFS  $POUSPMMFS  .PEFM-PHJD  %#૚03.BQQFS 

    7JFX4UBUJDpMFT ϏδωεϩδοΫΛѻ͏ ग़ྗ΍ݟͨ໨ʹؔ͢Δ෦෼ ݸผͷϦΫΤετʹجͮ͘ॲཧ σʔλϕʔεʹ·ͭΘΔ 63-.&5)0%ʹԠͯ͡ৼΓ෼͚Δ
  6. 1FSMͷ8"'ୡ w $BUBMZTU w %BODFS w "NPO w ,PTTZ w

    1JDLMFT w 7PTPO w .PKPMJDJPVT w ࣗ࡞8"'
  7. ࣗ࡞8"'ͱطଘ8"' w .7$ʁΛ࣮ݱ͢ΔϞδϡʔϧ͸ଗ͍ͬͯΔ w 1MBDL3FRVFTU w 3PVUFS4JNQMF w 5FYU9TMBUF w

    ͨͩΞϓϦΛॻ͖ͳ͕Β8"'΋͸Ωπ͍ w ษڧ༻ʹंྠͷ࠶ൃ໌͸ଟ͍ʹ׻ܴ w Ͱ΋ͱΓ͋͑ͣ8"'Λ࢖͍·͠ΐ͏Ͷ—
  8. ಛ௃ͦͷଞ w Ξοϓσʔτ͕සൟ $self->render_json( $ref ); # 4.00 Ͱഇࢭ #

    => $self->render( json => $ref ); ͨͩ͠ґଘ͕ແ͍ͷͰ.PKPMJDJPVT͚ͩ௥͍ͬͯΕ͹Α͍ w .PKPMJDJPVT-JUFΛ࢖͑͹ϑΝΠϧҰͭͰ w ޻෉͢Ε͹$(*Ͱ΋ಈ࡞Մೳ w 1FSMҎ্ඞਢɺҎ্Λਪ঑ w ։ൃ༻αʔόNPSCPɺຊ൪༻IZQOPUPBE w ΋ͪΖΜ14(*ޓ׵
  9. ͸͡Ίͯͷ.PKPMJDJPVT-JUF #!/usr/bin/env perl use Mojolicious::Lite; get '/' => sub {

    my $self = shift; $self->stash->{message} = 'Hello Mojo!'; $self->render('index'); }; app->start; __DATA__ @@ index.html.ep <html> <body> <p><%= $message %></p> </body> </html> $POUSPMMFSʹ֘౰ 7JFXʢςϯϓϨʔτʣ 3PVUJOHͯ͠Δ
  10. )FMMP8PSME͔ΒֶͿ get '/' => sub {}; ϧʔςΟϯάͱίϯτϩʔϥ (&5IUUQMPDBMIPTU get '/entry/:id'

    => sub { my $entry_id = $self->stash->{id}; }; post '/entry' => sub {}; 1045IUUQMPDBMIPTUFOUSZ (&5IUUQMPDBMIPTUFOUSZ
  11. )FMMP8PSME͔ΒֶͿ get '/' => sub { my $self = shift;

    $self->stash->{message} = 'Hello Mojo'; ...; } ςϯϓϨʔτʹσʔλΛ౉͢ $self->render('index'); # index.html.ep Λඳը ...; <p><%= $message %></p> ςϯϓϨʔτͷهड़ͱϨϯμʔ
  12. #!/usr/bin/env perl use Mojolicious::Lite; use utf8; ...; get '/' =>

    sub { my $self = shift; $self->render('index'); }; ...; @@ index.html.ep <p>໊લΛೖྗ͍ͯͩ͘͠͞</p> <form action="/result"> <input type="text" name="name" /> <input type="submit" value="઎͏" /> </form> τοϓϖʔδΛඳը
  13. ...; get '/result' => sub { my $self = shift;

    my $name = $self->req->param('name'); my @list = qw/ྑ͍ࣄ͕ى͜ΔͰ͠ΐ͏ ग़ձ͍͕͋Δ͔΋ʁ ෆ޾ʹͳΓ·͢/; my $num = 0; $num += ord ($_) for split //, $name; my $index = $num % scalar @list; $self->stash->{message} = $list[$index]; $self->stash->{name} = $name; $self->render('result'); }; ...; @@ result.html.ep <p><%= $name %>͞Μͷ݁Ռʮ<%= $message %>ʯ</p> ݁ՌΛग़ྗ
  14. $POUSPMMFS಺Ͱͷૢ࡞ w શͯ͸ʮTFMGʯͷϝιουΛѻ͏ my $value = $self->req->param('key'); $self->render('entry'); $self->render( json

    => { key => $value } ); .PKPMJDJPVT$POUSPMMFSΛܧঝ͢ΔͷͰͦͷυΩϡϝϯτΛಡΊ͹0,ʂ $self->redirect_to('/');
  15. .PKP5FNQMBUFपΓ w 1FSMJTIUFNQMBUFT1FSMॻ͚Δʂ % for my $entry (@$entries) { <h2><%=

    $entry->{title} %></h2> % } .PKP5FNQMBUF.PKPMJDJPVT1MVHJO%FGBVMU)FMQFS w ςϯϓϨʔτ޲͚IFMQFS @@ index.html.ep % layout 'default'; Hi, <%= $name %> @@ layouts/default.html.ep <html> <body><%= content %></body> </html>
  16. .PKPMJDJPVT-JUFΞϓϦΛ֦ு͢Δ w QVCMJD੩తϑΝΠϧΛஔ͘ w UFNQMBUFTςϯϓϨʔτϑΝΠϧΛಠཱ ./ !"" myapp.pl !"" public/

    # !"" css/ # !"" favicon.ico # !"" images/ # %"" js/ %"" templates/ !"" layouts/ # %"" default.html.ep %"" root/ %"" index.html.ep
  17. ͍͍ͩͨ͜Μͳߏ੒ ./ !"" Uranai/ # !"" DB/ # # %""

    Schema.pm # !"" DB.pm # !"" Model/ # # %"" OneModel.pm # !"" Web/ # # %"" Controller/ # # %"" Root.pm # %"" Web.pm %"" Uranai.pm %#ϨΠϠʔ5FOHFUD ϏδωεϩδοΫ1FSM.PEVMF 8FCϨΠϠʔ ओʹ$POUSPMMFSͱϧʔςΟϯά 6SBOBJQNͰ͸ύεղܾͱઃఆϩʔυΛ࣮૷
  18. -JUF͔ΒͷҠߦ #!/usr/bin/env perl use Mojolicious::Lite; get '/' => sub {

    my $self = shift; $self->stash->{message} = 'Hello Mojo!'; $self->render('index'); }; app->start; __DATA__ @@ index.html.ep <html> <body> <p><%= $message %></p> </body> </html> MJC6SBOBJ8FCQN MJC6SBOBJ8FC$POUSPMMFS .PKPMJDJPVT$POUSPMMFSΛܧঝ UFNQMBUFT .PKP5FNQMBUFʹ४ͣΔ
  19. 6SBOBJ.PEFM6SBOBJ package Uranai::Model::Uranai; use Mouse; has 'list' => ( is

    => 'ro', isa => 'ArrayRef[Str]', default => sub { [qw/ྑ͍ࣄ͕ى͜ΔͰ͠ΐ͏ ग़ձ͍͕͋Δ͔΋ʁ ෆ޾ʹͳΓ·͢ /]} ); sub uranau { my ($self, $name) = @_; my $num = 0; $num += ord ($_) for split //, $name; my $index = $num % scalar @{$self->list()}; return $self->list->[$index]; } __PACKAGE__->meta->make_immutable();
  20. 6SBOBJ8FC$POUSPMMFS3PPU package Uranai::Web::Controller::Root; use Mojo::Base 'Mojolicious::Controller'; use Uranai::Model::Uranai; sub index

    { my $self = shift; $self->render('index'); } sub result { my $self = shift; my $name = $self->req->param('name'); return $self->redirect_to('/') unless $name; my $uranai = Uranai::Model::Uranai->new; my $message = $uranai->uranau($name); $self->stash->{message} = $message; $self->render('result'); } 1;
  21. VTF'PSN7BMJEBUPS-JUF w ೖྗ஋ͷଥ౰ੑΛνΣοΫ͢Δ w ྫɿϝʔϧΞυϨεɺ༣ศ൪߸ɺจࣈ਺ FormValidator::Lite->load_constraints(qw/Japanese Email/); my $validator =

    FormValidator::Lite->new($self->req); my $res -> $validator->check( name => [qw/NOT_NULL/], mail => [qw/EMAIL/], { mails => [qw/mail mail_confirm/] } => ['DUPLICATION'] ); if($validator->has_error) { $self->stash->{messages} = $validator->get_error_messages(); return $self->render; } ...;
  22. VTF5FOH w σʔλϕʔεΛૢ࡞͢Δ03.BQQFS w ͱͬͯ΋γϯϓϧ w $POUSPMMFS͔Β͸ૢ࡞ͤͣ.PEFM͔Β৮Δ my $teng =

    Teng::Schema::Loader->load( dbh => $dbh, namespace => 'Uranai::DB', ); my $row = $teng->insert(result => { text => '͋ͳͨ͸݁ࠗग़དྷ·ͤΜ', });
  23. ͪͳΈʹ΍ͬͨ͜ͱ CREATE TABLE result ( id INT UNSIGNED AUTO_INCREMENT, text

    VARCHAR(200) NOT NULL, created_at DATETIME NOT NULL, PRIMARY KEY (`id`) ); %#Λͭͬͯ͘ lib/Uranai/DB.pm lib/Uranai/DB/Schema.pm 5FOHͷ%#εΩʔϚͭͬͯ͘ lib/Uranai/Model/Uranai.pm .PEFM͔Βૢ࡞͢ΔΑ͏ʹͯ͠ lib/Uranai/Controller/Root.pm $POUSPMMFS͔Βݺͼग़͢ templates/root/index.html.ep 7JFXͷมߋ t/01_model.t ؆୯ͳςετॻ͍ͯ Ͱ͖ͨʂ
  24. ͦͷଞ࣮ફͰ࢖ͬͯΔϞδϡʔϧ w )5.-'JMM*O'PSN-JUF w %BUB7BMJEBUPS w .PVTF w 42-.BLFS w

    $BSUPO w %FWFM/:51SPG%FWFM,:51SPG w 5FTUNZTRME w )BSSJFU w $JOOBNPO w 4FSWFS4UBSUFS w 4UBSNBO4UBSMFU w FUD 5IBOLTUPHSFBU.PEVMF"VUIPSTʂ
  25. %&-&5&165Λٖࣅతʹαϙʔτͤ͞Δ $self->hook( before_dispatch => sub { my $c = shift;

    if($c->req->method eq 'POST' && $c->req->param('_method')) { my $methods = [qw/GET POST PUT DELETE/]; if ( grep { $_ eq uc $c->req->param('_method') } @$methods ) { $c->req->method( $c->req->param('_method') ); } } } ); my $r = $self->routes; $r->delete('/entry/:id')-> to( controller => 'Entry', action => 'delete' );
  26. IFMQFSͰ'JMM*O'PSNΛ͓खܰʹ # Uranai::Web $self->helper( render_fill => sub { my ($self,

    $name) = @_; my $html = $self->render(template => $name, partial => 1); return $self->render( text => HTML::FillInForm::Lite->fill(\$html, $self->req->params), format => 'html' ); } ); # Uranai::Web::Controller::* sub form { my $self = shift; ...; if ($validator->error) { $self->stash->{messages} = $validator->get_error_messages(); return $self->render_fill('form'); } }
  27. 6SBOBJDPOpH  # Uranai sub config { my $mode =

    $ENV{PLACK_ENV} || 'development'; my $fname = File::Spec->catfile( Uranai->base_dir() , $mode . '.pl' ); my $config = undef; if( -f $fname ){ $config = do $fname or die "Cannnot load configuration file: $fname"; }else{ die "Cannot find configuration file: $fname"; } return $config; }
  28. 8FCΞϓϦΛͭ͘Δʹ͸ʁ w ྫ͑͹ࠓճͷ઎͍ΞϓϦ w .PKPMJDJPVT-JUFͰ࣮૷ͯ͠ΈΔ w ग़དྷͨʂԶͬͯ͹εήʔମݧͦͷ w .PKPMJDJPVTΞϓϦͰ֦ுͯ͠ΈΔ w

    ग़དྷͨʂԶͬͯ͹εήʔମݧͦͷ w 5FOHΛֶश͠઎͍ͷύλʔϯΛ૿΍͢ w ग़དྷͨʂԶͬͯ͹εήʔମݧͦͷ
  29. ѻΘͳ͔ͬͨओͳ఺ w ΑΓποίΜͩ.PKPMJDJPVTͷ࢖͍ํ w ςετ5FTU.PSF5FTU.PKP w ੜʹ͍ۙ%#42-ૢ࡞ w ͦͷଞϛυϧ΢ΣΞNFNDBDIFE3FEJT w

    σϓϩΠαʔόߏ੒ΞϓϦαʔό w ύϑΥʔϚϯεܭଌɺνϡʔχϯά w 1FSMҎ֎ͷ͜ͱ+BWB4DSJQU$44)5.-