modern Catalyst
    Hideo Kimura
about me
about me
• hide-k
about me
• hide-k
 • hideki
about me
• hide-k
 • hideki
 • hide
about me
• hide-k
 • hideki
 • hide
• DeNA
about me
• hide-k
 • hideki
 • hide
• DeNA
 • MobaSif
Catalyst
Agenda
Agenda
• How to extend modern Catalyst on your
  applications
Agenda
• How to extend modern Catalyst on your
  applications
• Not Catalyst introducing
Agenda
• How to extend modern Catalyst on your
  applications
• Not Catalyst introducing
• Not plugin recomendation
Agenda
• How to extend modern Catalyst on your
  applications
• Not Catalyst introducing
• Not plugin recomendation
• Not tips
Agenda
• How to extend modern Catalyst on your
  applications
• Not Catalyst introducing
• Not plugin recomendation
• Not tips
• No
Catalyst 5.8
Catalyst 5.8
• 13 Oct 2008
Catalyst 5.8
• 13 Oct 2008
• Deprecation
Catalyst 5.8
• 13 Oct 2008
• Deprecation
• Catamoose
Deprecation
Deprecation
•   ::[M V C]:: style
Deprecation
•   ::[M V C]:: style

•   NEXT
Deprecation
•   ::[M V C]:: style

•   NEXT

    •   use MRO::Compat
Deprecation
•   ::[M V C]:: style

•   NEXT

    •   use MRO::Compat

•   __PACKAGE__->mk_accessors()
Deprecation
•   ::[M V C]:: style

•   NEXT

    •   use MRO::Compat

•   __PACKAGE__->mk_accessors()

    •   use Moose attribute ‘has’
Deprecation
•   ::[M V C]:: style

•   NEXT

    •   use MRO::Compat

•   __PACKAGE__->mk_accessors()

    •   use Moose attribute ‘has’

•   and more...
Moose
Moose
• A postmodern object system for Perl5
Moose
• A postmodern object system for Perl5
• Meta Object Protocol sugar syntax
Moose
• A postmodern object system for Perl5
• Meta Object Protocol sugar syntax
 • attributes
Moose
• A postmodern object system for Perl5
• Meta Object Protocol sugar syntax
 • attributes
 • method modifiers
Moose
• A postmodern object system for Perl5
• Meta Object Protocol sugar syntax
 • attributes
 • method modifiers
 • roles
Application
package MyApp;

use strict;
use warnings;

use parent qw/Catalyst/;
use Catalyst qw/
                 -Debug
                 ConfigLoader
                 Static::Simple/;

__PACKAGE__->config( name => 'MyApp' );
__PACKAGE__->setup();

1;
Moose-ified Applicatoion
package MyApp;

use Moose;

extends 'Catalyst';

__PACKAGE__->config(name => 'MyApp');
__PACKAGE__->setup(
    qw/
        -Debug
        ConfigLoader
        Static::Simple/
);

1;
Extend Application
Extend Application
• Plugin?
Extend Application
• Plugin?
 • Application namespace
Extend Application
• Plugin?
 • Application namespace
• Helper Method
Extend Application
• Plugin?
 • Application namespace
• Helper Method
• Role
Extend Application
• Plugin?
 • Application namespace
• Helper Method
• Role
• base Controller
Extend Applicatoion
package MyApp;
...

after finalize => sub {
    my $c = shift;
    $c->log->(‘finalize’);
};

sub foo {
    my $c = shift;
    $c->log->debug(‘foo’);
}

1;
Extend Applicatoion
package MyApp::Role::Foo;

use Moose::Role;

after finalize => sub {
    my $c = shift;
    $c->log->(‘finalize’);
};

sub foo {
    my $c = shift;
    $c->log->debug(‘foo’);
}

1;
Extend Applicatoion
package MyApp;

...

__PACKAGE__->setup(
    qw/
        -Debug
        ConfigLoader
        Static::Simple
        +MyApp::Role::Foo/
);

1;
Controller
package MyApp::Contorller::Foo;

use strict;
use warnings;

use parent ‘Catalyst::Controller’;

sub foo : Path('foo') {
    my ($self, $c) = @_;

     $c->res->body('foo');
}

1;
Moose-ified Controller
package MyApp::Contorller::Foo;

use Moose;

BEGIN {extends ‘Catalyst::Controller};

sub foo : Path('foo') {
    my ($self, $c) = @_;

     $c->res->body('foo');
}

1;
Extend Controller
Extend Controller

• Moose::Role
Extend Controller

• Moose::Role
 • MooseX::MethodAttributes
Extend Controller

• Moose::Role
 • MooseX::MethodAttributes
• ActionClass
Extend Controller

• Moose::Role
 • MooseX::MethodAttributes
• ActionClass
• ActionRole
Extend Controller
package MyApp::Role;

use Moose::Role -traits => 'MethodAttributes';

sub foo : Path('foo') {
    my ($self, $c) = @_;

     $c->log->debug('foo');
}

1;
Extend Controller
package MyApp::Controller::Foo;

use Moose;
BEGIN {extends ‘Catalyst::Controller’}

with MyApp::Role;

1;
ActionClass
package MyApp::Action::Foo;

use Moose;

extends 'Catalyst::Action';

after execute => sub {
    my ($self, $controller, $c) = @_;

     $c->log->debug(‘foo’);
};

1;
ActionClass
...

sub foo : Path('foo')
ActionClass('+MyApp::Action::Foo') {
    my ($self, $c) = @_;

      $c->res->body('foo');
}

...
ActionClass
...

sub _parse_Foo_attr {
  return ActionClass => ‘MyApp::Action::Foo’;
}

sub foo : Path('foo') Foo {

...
ActionClass
ActionClass
• Pros
ActionClass
• Pros
 • Reusable
Action Class
Action Class
sub foobar : Path(‘foobar’)
                  ActionClass(‘Foo’)
                  ActionClass(‘Bar’) {
Action Class
• Cons
   sub foobar : Path(‘foobar’)
                     ActionClass(‘Foo’)
                     ActionClass(‘Bar’) {
Action Class
• Cons
   sub foobar : Path(‘foobar’)
                     ActionClass(‘Foo’)
                     ActionClass(‘Bar’) {
Action Class
• Cons
   sub foobar : Path(‘foobar’)
                     ActionClass(‘Foo’)
                     ActionClass(‘Bar’) {
Action Class
• Cons
     sub foobar : Path(‘foobar’)
                       ActionClass(‘Foo’)
                       ActionClass(‘Bar’) {


 •     NG
Action Class
• Cons
   sub foobar : Path(‘foobar’)
                     ActionClass(‘Foo’)
                     ActionClass(‘Bar’) {


 • NG
 • Sucks
ActionRole
ActionRole
• Catalyst::Controller::ActionRole
ActionRole
• Catalyst::Controller::ActionRole
 • Moose::Role as Action
ActionRole
package MyApp::ActionRole::Foo;

use Moose::Role;

after execute => sub {
    my ($self, $controller, $c) = @_;

     $c->log->debug(‘foo’);
};

1;
ActionRole
package MyApp::Contorller::Foo;

use Moose;

BEGIN {extends ‘Catalyst::Controller::ActionRole’};

sub foo : Path('foo') Does('Foo') {
    my ($self, $c) = @_;

      $c->res->body('foo');
}
...
ActionRole
ActionRole

sub foobar : Path(‘foobar’)
                  Does(‘Foo’)
                  Does(‘Bar’) {
ActionRole
• Pros
  sub foobar : Path(‘foobar’)
                    Does(‘Foo’)
                    Does(‘Bar’) {
ActionRole
• Pros
  sub foobar : Path(‘foobar’)
                    Does(‘Foo’)
                    Does(‘Bar’) {
ActionRole
• Pros
  sub foobar : Path(‘foobar’)
                    Does(‘Foo’)
                    Does(‘Bar’) {
ActionRole
• Pros
  sub foobar : Path(‘foobar’)
                    Does(‘Foo’)
                    Does(‘Bar’) {



 •       OK
Dispatcher
• Path
• Local
• Global
• Regex
• LocalRegex
Dispatcher
• begin :Private
• end :Private
• auto :Private
Dispatcher
Dispatcher
• default :Private
Dispatcher
• default :Private
 • default :Path
Dispatcher
• default :Private
 • default :Path
 • catchall :Path
Dispatcher
• default :Private
 • default :Path
 • catchall :Path
• index :Private
Dispatcher
• default :Private
 • default :Path
 • catchall :Path
• index :Private
 • index :Path :Args(0)
Dispatcher
• default :Private
 • default :Path
 • catchall :Path
• index :Private
 • index :Path :Args(0)
 • home :Path :Args(0)
Dispatcher
Dispatcher
• Chained
Dispatcher
• Chained
 • dispatch chains of actions
Dispatcher
package MyApp::Controller::Foo;

use Moose;

BEGIN {extends 'Catalyst::Controller'}

sub root :Chained('/') PathPart('foo') CaptureArgs
{}

sub bar :Chained('root') PathPart Args(0) {
#/foo/bar
}

sub baz :Chained('root') PathPart Args(1) {
#/foo/baz/*
}

1;
Dispatcher
• $c->forward
• $c->detach
• $c->go
• $c->visit
Model
Model
• Thin Contoroller, Smart Model
Model
• Thin Contoroller, Smart Model
• Do not depend on Catalyst
Model
• Thin Contoroller, Smart Model
• Do not depend on Catalyst
• Model::Adaptor
Model::Adaptor
package MyApp::Model::Foo;

use Moose;

extends 'Catalyst::Model::Adaptor';

__PACKAGE__->config(
    class       => 'MyApp::Foo'
);

1;
Test
• Catalyst::Test
• Test::WWW::Mechanize::Catalyst
Catalyst::Test
use strict;
use warnings;

use Test::More;
use HTTP::Request::Common;

BEGIN { use_ok 'Catalyst::Test', 'MyApp' }

my $req = GET('/');
my $res = request($req); #$res = get(‘/’)
ok($res->is_success, 'index return ok');
is($res->content_type, 'text/html', 'content type
is HTML');
like($res->content, qr/Home/, 'contains Home');

done_testing();
Catalyst::Test
...

my ($res, $c) = ctx_request('/');

ok($res->is_success, 'index return ok');
is($c->stash->{foo}, 'foo', 'statsh foo is foo');

...
Test::WWW::Mechanize::Catalyst
use Test::WWW::Mechanize::Catalyst;
my $mech =
    Test::WWW::Mecanize::Catalyst->new(
        catalyst_app => ‘MyApp’
    );
$mech->get(‘/’);
$mech->content_contains(‘Home’, ‘contains Home’);
$mech->submit_form(
    form_number => 1,
    fields       => {
                      foo => ‘foo’,
                      bar => ‘bar’
                    }
);
$mech->content_contains(‘Foo’, ‘contains Foo’);
...
Resources
•   Catalyst::Delta

•   Catalyst::Upgrading

•   Catalyst::Manual::ExtendingCatalyst

•   Catalyst::Manual::CatalystAndMoose

•   Catalyst::Manual::Cookbook

•          Perl

    •   http://gihyo.jp/dev/serial/01/modern-perl

•   The Definitive Guide to Catalyst
One more thing...
PSGI
PSGI
PSGI
• Perl Server Gateway Interface
 • just specification, not implementation
 • start developing at 2009/09/04
 • talk in this morning
   • miyaga-san, tokuhirom-san
Catalyst::Engine::PSGI
                                   MyApp



               Catalyst::Engine::PSGI      Catalyst::Engine::*



::Impl::Coro        ::Impl::Mojo
Thank you

Modern Catalyst