4 use Moose::Meta::Class ();
5 extends 'Catalyst::Component';
6 use Moose::Util qw/find_meta/;
7 use B::Hooks::EndOfScope ();
8 use Catalyst::Exception;
11 use Catalyst::Controller;
12 use Catalyst::Context;
13 use Catalyst::Exception::Detach;
14 use Catalyst::Exception::Go;
15 use Devel::InnerPackage ();
16 use Module::Pluggable::Object ();
17 use Text::SimpleTable ();
18 use Path::Class::Dir ();
19 use Path::Class::File ();
20 use Tree::Simple::Visitor::FindByUID;
21 use Class::C3::Adopt::NEXT;
24 use Carp qw/croak carp shortmess/;
26 BEGIN { require 5.008004; }
28 sub comp { shift->component(@_) }
30 #I imagine that very few of these really need to be class variables. if any.
31 #maybe we should just make them attributes with a default?
32 __PACKAGE__->mk_classdata($_)
33 for qw/components arguments dispatcher engine log dispatcher_class
34 engine_class context_class request_class response_class stats_class
37 __PACKAGE__->context_class('Catalyst::Context');
38 __PACKAGE__->dispatcher_class('Catalyst::Dispatcher');
39 __PACKAGE__->engine_class('Catalyst::Engine::CGI');
40 __PACKAGE__->request_class('Catalyst::Request');
41 __PACKAGE__->response_class('Catalyst::Response');
42 __PACKAGE__->stats_class('Catalyst::Stats');
44 # Remember to update this in Catalyst::Runtime as well!
46 our $VERSION = '5.80013';
49 my $dev_version = $VERSION =~ /_\d{2}$/;
50 *_IS_DEVELOPMENT_VERSION = sub () { $dev_version };
53 $VERSION = eval $VERSION;
57 our $DETACH = Catalyst::Exception::Detach->new;
58 our $GO = Catalyst::Exception::Go->new;
61 my ( $class, @arguments ) = @_;
63 # We have to limit $class to Catalyst to avoid pushing Catalyst upon every
65 return unless $class eq 'Catalyst';
67 my $caller = caller();
68 return if $caller eq 'main';
70 # Kill Adopt::NEXT warnings if we're a non-RC version
71 unless (_IS_DEVELOPMENT_VERSION()) {
72 Class::C3::Adopt::NEXT->unimport(qr/^Catalyst::/);
75 my $meta = Moose::Meta::Class->initialize($caller);
76 # Make the caller inherit from Catalyst
77 unless ( $caller->isa('Catalyst') ) {
78 $meta->superclasses($meta->superclasses, 'Catalyst');
80 # Avoid possible C3 issues if 'Moose::Object' is already on RHS of MyApp
81 $meta->superclasses(grep { $_ ne 'Moose::Object' } $meta->superclasses);
83 unless( $meta->has_method('meta') ){
84 $meta->add_method(meta => sub { Moose::Meta::Class->initialize("${caller}") } );
87 $caller->arguments( [@arguments] );
91 sub _application { $_[0] }
95 Catalyst - The Elegant MVC Web Application Framework
99 See the L<Catalyst::Manual> distribution for comprehensive
100 documentation and tutorials.
102 # Install Catalyst::Devel for helpers and other development tools
103 # use the helper to create a new application
106 # add models, views, controllers
107 script/myapp_create.pl model MyDatabase DBIC::Schema create=static dbi:SQLite:/path/to/db
108 script/myapp_create.pl view MyTemplate TT
109 script/myapp_create.pl controller Search
111 # built in testserver -- use -r to restart automatically on changes
112 # --help to see all available options
113 script/myapp_server.pl
115 # command line testing interface
116 script/myapp_test.pl /yada
119 use Catalyst qw/-Debug/; # include plugins here as well
121 ### In lib/MyApp/Controller/Root.pm (autocreated)
122 sub foo : Global { # called for /foo, /foo/1, /foo/1/2, etc.
123 my ( $self, $c, @args ) = @_; # args are qw/1 2/ for /foo/1/2
124 $c->stash->{template} = 'foo.tt'; # set the template
125 # lookup something from db -- stash vars are passed to TT
127 $c->model('Database::Foo')->search( { country => $args[0] } );
128 if ( $c->req->params->{bar} ) { # access GET or POST parameters
129 $c->forward( 'bar' ); # process another action
130 # do something else after forward returns
134 # The foo.tt TT template can use the stash data from the database
135 [% WHILE (item = data.next) %]
139 # called for /bar/of/soap, /bar/of/soap/10, etc.
140 sub bar : Path('/bar/of/soap') { ... }
142 # called for all actions, from the top-most controller downwards
144 my ( $self, $c ) = @_;
145 if ( !$c->user_exists ) { # Catalyst::Plugin::Authentication
146 $c->res->redirect( '/login' ); # require login
147 return 0; # abort request and go immediately to end()
149 return 1; # success; carry on to next action
152 # called after all actions are finished
154 my ( $self, $c ) = @_;
155 if ( scalar @{ $c->error } ) { ... } # handle errors
156 return if $c->res->body; # already have a response
157 $c->forward( 'MyApp::View::TT' ); # render template
160 ### in MyApp/Controller/Foo.pm
161 # called for /foo/bar
162 sub bar : Local { ... }
164 # called for /blargle
165 sub blargle : Global { ... }
167 # an index action matches /foo, but not /foo/1, etc.
168 sub index : Private { ... }
170 ### in MyApp/Controller/Foo/Bar.pm
171 # called for /foo/bar/baz
172 sub baz : Local { ... }
174 # first Root auto is called, then Foo auto, then this
175 sub auto : Private { ... }
177 # powerful regular expression paths are also possible
178 sub details : Regex('^product/(\w+)/details$') {
179 my ( $self, $c ) = @_;
180 # extract the (\w+) from the URI
181 my $product = $c->req->captures->[0];
184 See L<Catalyst::Manual::Intro> for additional information.
188 Catalyst is a modern framework for making web applications without the
189 pain usually associated with this process. This document is a reference
190 to the main Catalyst application. If you are a new user, we suggest you
191 start with L<Catalyst::Manual::Tutorial> or L<Catalyst::Manual::Intro>.
193 See L<Catalyst::Manual> for more documentation.
195 Catalyst plugins can be loaded by naming them as arguments to the "use
196 Catalyst" statement. Omit the C<Catalyst::Plugin::> prefix from the
197 plugin name, i.e., C<Catalyst::Plugin::My::Module> becomes
200 use Catalyst qw/My::Module/;
202 If your plugin starts with a name other than C<Catalyst::Plugin::>, you can
203 fully qualify the name by using a unary plus:
207 +Fully::Qualified::Plugin::Name
210 Special flags like C<-Debug> and C<-Engine> can also be specified as
211 arguments when Catalyst is loaded:
213 use Catalyst qw/-Debug My::Module/;
215 The position of plugins and flags in the chain is important, because
216 they are loaded in the order in which they appear.
218 The following flags are supported:
222 Enables debug output. You can also force this setting from the system
223 environment with CATALYST_DEBUG or <MYAPP>_DEBUG. The environment
224 settings override the application, with <MYAPP>_DEBUG having the highest
229 Forces Catalyst to use a specific engine. Omit the
230 C<Catalyst::Engine::> prefix of the engine name, i.e.:
232 use Catalyst qw/-Engine=CGI/;
236 Forces Catalyst to use a specific home directory, e.g.:
238 use Catalyst qw[-Home=/usr/mst];
240 This can also be done in the shell environment by setting either the
241 C<CATALYST_HOME> environment variable or C<MYAPP_HOME>; where C<MYAPP>
242 is replaced with the uppercased name of your application, any "::" in
243 the name will be replaced with underscores, e.g. MyApp::Web should use
244 MYAPP_WEB_HOME. If both variables are set, the MYAPP_HOME one will be used.
248 use Catalyst '-Log=warn,fatal,error';
250 Specifies a comma-delimited list of log levels.
254 Enables statistics collection and reporting. You can also force this setting
255 from the system environment with CATALYST_STATS or <MYAPP>_STATS. The
256 environment settings override the application, with <MYAPP>_STATS having the
261 use Catalyst qw/-Stats=1/
267 =head2 $c->controller($name)
269 Gets a L<Catalyst::Controller> instance by name.
271 $c->controller('Foo')->do_stuff;
273 If the name is omitted, will return the controller for the dispatched
276 If you want to search for controllers, pass in a regexp as the argument.
278 # find all controllers that start with Foo
279 my @foo_controllers = $c->controller(qr{^Foo});
285 my ( $c, $name, @args ) = @_;
288 my @result = $c->_comp_search_prefixes( $name, qw/Controller C/ );
289 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
290 return $c->_filter_component( $result[ 0 ], @args );
293 return $c->component( $c->action->class );
296 =head2 $c->view($name)
298 Gets a L<Catalyst::View> instance by name.
303 my ( $c, $name, @args ) = @_;
306 my @result = $c->_comp_search_prefixes( $name, qw/View V/ );
307 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
308 return $c->_filter_component( $result[ 0 ], @args );
311 return $c->view( $c->config->{default_view} )
312 if $c->config->{default_view};
313 my( $comp, $rest ) = $c->_comp_search_prefixes( undef, qw/View V/);
316 $c->log->warn( 'Calling $c->view() will return a random view unless you specify one of:' );
317 $c->log->warn( '* $c->config(default_view => "the name of the default view to use")' );
318 $c->log->warn( '* $c->stash->{current_view} # the name of the view to use for this request' );
319 $c->log->warn( '* $c->stash->{current_view_instance} # the instance of the view to use for this request' );
320 $c->log->warn( 'NB: in version 5.81, the "random" behavior will not work at all.' );
323 return $c->_filter_component( $comp );
326 =head2 $c->model($name)
328 Gets a L<Catalyst::Model> instance by name.
333 my ( $c, $name, @args ) = @_;
335 my @result = $c->_comp_search_prefixes( $name, qw/Model M/ );
336 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
337 return $c->_filter_component( $result[ 0 ], @args );
340 return $c->model( $c->config->{default_model} )
341 if $c->config->{default_model};
343 my( $comp, $rest ) = $c->_comp_search_prefixes( undef, qw/Model M/);
346 $c->log->warn( Carp::shortmess('Calling $c->model() will return a random model unless you specify one of:') );
347 $c->log->warn( '* $c->config(default_model => "the name of the default model to use")' );
348 $c->log->warn( '* $c->stash->{current_model} # the name of the model to use for this request' );
349 $c->log->warn( '* $c->stash->{current_model_instance} # the instance of the model to use for this request' );
350 $c->log->warn( 'NB: in version 5.81, the "random" behavior will not work at all.' );
353 return $c->_filter_component( $comp );
357 sub _comp_search_prefixes {
359 return map $c->components->{ $_ }, $c->_comp_names_search_prefixes(@_);
362 # search components given a name and some prefixes
363 sub _comp_names_search_prefixes {
364 my ( $c, $name, @prefixes ) = @_;
365 my $appclass = ref $c || $c;
366 my $filter = "^${appclass}::(" . join( '|', @prefixes ) . ')::';
367 $filter = qr/$filter/; # Compile regex now rather than once per loop
369 # map the original component name to the sub part that we will search against
370 my %eligible = map { my $n = $_; $n =~ s{^$appclass\::[^:]+::}{}; $_ => $n; }
371 grep { /$filter/ } keys %{ $c->components };
373 # undef for a name will return all
374 return keys %eligible if !defined $name;
376 my $query = ref $name ? $name : qr/^$name$/i;
377 my @result = grep { $eligible{$_} =~ m{$query} } keys %eligible;
379 return @result if @result;
381 # if we were given a regexp to search against, we're done.
384 # skip regexp fallback if configured
386 if $appclass->config->{disable_component_resolution_regex_fallback};
390 @result = grep { $eligible{ $_ } =~ m{$query} } keys %eligible;
392 # no results? try against full names
394 @result = grep { m{$query} } keys %eligible;
397 # don't warn if we didn't find any results, it just might not exist
399 # Disgusting hack to work out correct method name
400 my $warn_for = lc $prefixes[0];
401 my $msg = "Used regexp fallback for \$c->${warn_for}('${name}'), which found '" .
402 (join '", "', @result) . "'. Relying on regexp fallback behavior for " .
403 "component resolution is unreliable and unsafe.";
404 my $short = $result[0];
405 # remove the component namespace prefix
406 $short =~ s/.*?(Model|Controller|View):://;
407 my $shortmess = Carp::shortmess('');
408 if ($shortmess =~ m#Catalyst/Plugin#) {
409 $msg .= " You probably need to set '$short' instead of '${name}' in this " .
411 } elsif ($shortmess =~ m#Catalyst/lib/(View|Controller)#) {
412 $msg .= " You probably need to set '$short' instead of '${name}' in this " .
413 "component's config";
415 $msg .= " You probably meant \$c->${warn_for}('$short') instead of \$c->${warn_for}('${name}'), " .
416 "but if you really wanted to search, pass in a regexp as the argument " .
417 "like so: \$c->${warn_for}(qr/${name}/)";
419 $c->log->warn( "${msg}$shortmess" );
425 # Find possible names for a prefix
427 my ( $c, @prefixes ) = @_;
428 my $appclass = ref $c || $c;
430 my $filter = "^${appclass}::(" . join( '|', @prefixes ) . ')::';
432 my @names = map { s{$filter}{}; $_; }
433 $c->_comp_names_search_prefixes( undef, @prefixes );
438 # Filter a component before returning by calling ACCEPT_CONTEXT if available
439 sub _filter_component {
440 my ( $c, $comp, @args ) = @_;
442 if ( eval { $comp->can('ACCEPT_CONTEXT'); } ) {
443 return $comp->ACCEPT_CONTEXT( $c, @args );
449 =head2 COMPONENT ACCESSORS
451 =head2 $c->controllers
453 Returns the available names which can be passed to $c->controller
459 return $c->_comp_names(qw/Controller C/);
464 Returns the available names which can be passed to $c->model
470 return $c->_comp_names(qw/Model M/);
476 Returns the available names which can be passed to $c->view
482 return $c->_comp_names(qw/View V/);
485 =head2 $c->comp($name)
487 =head2 $c->component($name)
489 Gets a component object by name. This method is not recommended,
490 unless you want to get a specific component by full
491 class. C<< $c->controller >>, C<< $c->model >>, and C<< $c->view >>
492 should be used instead.
494 If C<$name> is a regexp, a list of components matched against the full
495 component name will be returned.
497 If Catalyst can't find a component by name, it will fallback to regex
498 matching by default. To disable this behaviour set
499 disable_component_resolution_regex_fallback to a true value.
501 __PACKAGE__->config( disable_component_resolution_regex_fallback => 1 );
506 my ( $c, $name, @args ) = @_;
509 my $comps = $c->components;
512 # is it the exact name?
513 return $c->_filter_component( $comps->{ $name }, @args )
514 if exists $comps->{ $name };
516 # perhaps we just omitted "MyApp"?
517 my $composed = ( ref $c || $c ) . "::${name}";
518 return $c->_filter_component( $comps->{ $composed }, @args )
519 if exists $comps->{ $composed };
521 # search all of the models, views and controllers
522 my( $comp ) = $c->_comp_search_prefixes( $name, qw/Model M Controller C View V/ );
523 return $c->_filter_component( $comp, @args ) if $comp;
526 # This is here so $c->comp( '::M::' ) works
527 my $query = ref $name ? $name : qr{$name}i;
529 my @result = grep { m{$query} } keys %{ $c->components };
530 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
533 $c->log->warn( Carp::shortmess(qq(Found results for "${name}" using regexp fallback)) );
534 $c->log->warn( 'Relying on the regexp fallback behavior for component resolution' );
535 $c->log->warn( 'is unreliable and unsafe. You have been warned' );
536 return $c->_filter_component( $result[ 0 ], @args );
539 # I would expect to return an empty list here, but that breaks back-compat
543 return sort keys %{ $c->components };
546 =head2 CLASS DATA AND HELPER CLASSES
550 Returns or takes a hashref containing the application's configuration.
552 __PACKAGE__->config( { db => 'dsn:SQLite:foo.db' } );
554 You can also use a C<YAML>, C<XML> or L<Config::General> config file
555 like C<myapp.conf> in your applications home directory. See
556 L<Catalyst::Plugin::ConfigLoader>.
558 =head3 Cascading configuration
560 The config method is present on all Catalyst components, and configuration
561 will be merged when an application is started. Configuration loaded with
562 L<Catalyst::Plugin::ConfigLoader> takes precedence over other configuration,
563 followed by configuration in your top level C<MyApp> class. These two
564 configurations are merged, and then configuration data whose hash key matches a
565 component name is merged with configuration for that component.
567 The configuration for a component is then passed to the C<new> method when a
568 component is constructed.
572 MyApp->config({ 'Model::Foo' => { bar => 'baz', overrides => 'me' } });
573 MyApp::Model::Foo->config({ quux => 'frob', 'overrides => 'this' });
575 will mean that C<MyApp::Model::Foo> receives the following data when
578 MyApp::Model::Foo->new({
586 around config => sub {
590 croak('Setting config after setup has been run is not allowed.')
591 if ( @_ and $c->setup_finished );
598 Returns the logging object instance. Unless it is already set, Catalyst
599 sets this up with a L<Catalyst::Log> object. To use your own log class,
600 set the logger with the C<< __PACKAGE__->log >> method prior to calling
601 C<< __PACKAGE__->setup >>.
603 __PACKAGE__->log( MyLogger->new );
608 $c->log->info( 'Now logging with my own logger!' );
610 Your log class should implement the methods described in
616 Returns 1 if debug mode is enabled, 0 otherwise.
618 You can enable debug mode in several ways:
622 =item By calling myapp_server.pl with the -d flag
624 =item With the environment variables MYAPP_DEBUG, or CATALYST_DEBUG
626 =item The -Debug option in your MyApp.pm
628 =item By declaring C<sub debug { 1 }> in your MyApp.pm.
632 Calling C<< $c->debug(1) >> has no effect.
638 =head2 $c->dispatcher
640 Returns the dispatcher instance. See L<Catalyst::Dispatcher>.
644 Returns the engine instance. See L<Catalyst::Engine>.
647 =head2 UTILITY METHODS
649 =head2 $c->path_to(@path)
651 Merges C<@path> with C<< $c->config->{home} >> and returns a
652 L<Path::Class::Dir> object. Note you can usually use this object as
653 a filename, but sometimes you will have to explicitly stringify it
654 yourself by calling the C<< ->stringify >> method.
658 $c->path_to( 'db', 'sqlite.db' );
663 my ( $c, @path ) = @_;
664 my $path = Path::Class::Dir->new( $c->config->{home}, @path );
665 if ( -d $path ) { return $path }
666 else { return Path::Class::File->new( $c->config->{home}, @path ) }
669 =head2 $c->plugin( $name, $class, @args )
671 Helper method for plugins. It creates a class data accessor/mutator and
672 loads and instantiates the given class.
674 MyApp->plugin( 'prototype', 'HTML::Prototype' );
676 $c->prototype->define_javascript_functions;
678 B<Note:> This method of adding plugins is deprecated. The ability
679 to add plugins like this B<will be removed> in a Catalyst 5.81.
680 Please do not use this functionality in new code.
685 my ( $class, $name, $plugin, @args ) = @_;
687 # See block comment in t/unit_core_plugin.t
688 $class->log->warn(qq/Adding plugin using the ->plugin method is deprecated, and will be removed in Catalyst 5.81/);
690 $class->_register_plugin( $plugin, 1 );
692 eval { $plugin->import };
693 $class->mk_classdata($name);
695 eval { $obj = $plugin->new(@args) };
698 Catalyst::Exception->throw( message =>
699 qq/Couldn't instantiate instant plugin "$plugin", "$@"/ );
703 $class->log->debug(qq/Initialized instant plugin "$plugin" as "$name"/)
709 Initializes the dispatcher and engine, loads any plugins, and loads the
710 model, view, and controller components. You may also specify an array
711 of plugins to load here, if you choose to not load them in the C<use
715 MyApp->setup( qw/-Debug/ );
720 my ( $class, @arguments ) = @_;
721 croak('Running setup more than once')
722 if ( $class->setup_finished );
724 unless ( $class->isa('Catalyst') ) {
726 Catalyst::Exception->throw(
727 message => qq/'$class' does not inherit from Catalyst/ );
730 if ( $class->arguments ) {
731 @arguments = ( @arguments, @{ $class->arguments } );
737 foreach (@arguments) {
741 ( $flags->{log} ) ? 'debug,' . $flags->{log} : 'debug';
743 elsif (/^-(\w+)=?(.*)$/) {
744 $flags->{ lc $1 } = $2;
747 push @{ $flags->{plugins} }, $_;
751 $class->setup_home( delete $flags->{home} );
753 $class->setup_log( delete $flags->{log} );
754 $class->setup_plugins( delete $flags->{plugins} );
755 $class->setup_dispatcher( delete $flags->{dispatcher} );
756 $class->setup_engine( delete $flags->{engine} );
757 $class->setup_stats( delete $flags->{stats} );
759 for my $flag ( sort keys %{$flags} ) {
761 if ( my $code = $class->can( 'setup_' . $flag ) ) {
762 &$code( $class, delete $flags->{$flag} );
765 $class->log->warn(qq/Unknown flag "$flag"/);
769 eval { require Catalyst::Devel; };
770 if( !$@ && $ENV{CATALYST_SCRIPT_GEN} && ( $ENV{CATALYST_SCRIPT_GEN} < $Catalyst::Devel::CATALYST_SCRIPT_GEN ) ) {
771 $class->log->warn(<<"EOF");
772 You are running an old script!
774 Please update by running (this will overwrite existing files):
775 catalyst.pl -force -scripts $class
777 or (this will not overwrite existing files):
778 catalyst.pl -scripts $class
783 if ( $class->debug ) {
784 my @plugins = map { "$_ " . ( $_->VERSION || '' ) } $class->registered_plugins;
787 my $column_width = Catalyst::Utils::term_width() - 6;
788 my $t = Text::SimpleTable->new($column_width);
789 $t->row($_) for @plugins;
790 $class->log->debug( "Loaded plugins:\n" . $t->draw . "\n" );
793 my $dispatcher = $class->dispatcher;
794 my $engine = $class->engine;
795 my $home = $class->config->{home};
797 $class->log->debug(sprintf(q/Loaded dispatcher "%s"/, blessed($dispatcher)));
798 $class->log->debug(sprintf(q/Loaded engine "%s"/, blessed($engine)));
802 ? $class->log->debug(qq/Found home "$home"/)
803 : $class->log->debug(qq/Home "$home" doesn't exist/)
804 : $class->log->debug(q/Couldn't find home/);
807 # Call plugins setup, this is stupid and evil.
808 # Also screws C3 badly on 5.10, hack to avoid.
810 no warnings qw/redefine/;
811 local *setup = sub { };
812 $class->setup unless $Catalyst::__AM_RESTARTING;
815 # Initialize our data structure
816 $class->components( {} );
818 $class->setup_components;
820 if ( $class->debug ) {
821 my $column_width = Catalyst::Utils::term_width() - 8 - 9;
822 my $t = Text::SimpleTable->new( [ $column_width, 'Class' ], [ 8, 'Type' ] );
823 for my $comp ( sort keys %{ $class->components } ) {
824 my $type = ref $class->components->{$comp} ? 'instance' : 'class';
825 $t->row( $comp, $type );
827 $class->log->debug( "Loaded components:\n" . $t->draw . "\n" )
828 if ( keys %{ $class->components } );
831 $class->setup_actions;
833 if ( $class->debug ) {
834 my $name = $class->config->{name} || 'Application';
835 $class->log->info("$name powered by Catalyst $Catalyst::VERSION");
838 # Make sure that the application class becomes immutable at this point,
839 B::Hooks::EndOfScope::on_scope_end {
841 my $meta = Class::MOP::get_metaclass_by_name($class);
844 && ! { $meta->immutable_options }->{replace_constructor}
846 $class->isa('Class::Accessor::Fast')
847 || $class->isa('Class::Accessor')
850 warn "You made your application class ($class) immutable, "
851 . "but did not inline the\nconstructor. "
852 . "This will break catalyst, as your app \@ISA "
853 . "Class::Accessor(::Fast)?\nPlease pass "
854 . "(replace_constructor => 1)\nwhen making your class immutable.\n";
856 $meta->make_immutable(
857 replace_constructor => 1,
858 ) unless $meta->is_immutable;
861 $class->setup_finalize;
862 # Should be the last thing we do so that user things hooking
863 # setup_finalize can log..
864 $class->log->_flush() if $class->log->can('_flush');
865 return 1; # Explicit return true as people have __PACKAGE__->setup as the last thing in their class. HATE.
869 =head2 $app->setup_finalize
871 A hook to attach modifiers to.
872 Using C<< after setup => sub{}; >> doesn't work, because of quirky things done for plugin setup.
873 Also better than C< setup_finished(); >, as that is a getter method.
879 ## do stuff, i.e., determine a primary key column for sessions stored in a DB
881 $app->next::method(@_);
890 $class->setup_finished(1);
893 =head2 $c->welcome_message
895 Returns the Catalyst welcome HTML page.
899 sub welcome_message {
901 my $name = $c->config->{name};
902 my $logo = $c->uri_for('/static/images/catalyst_logo.png');
903 my $prefix = Catalyst::Utils::appprefix( ref $c );
904 $c->response->content_type('text/html; charset=utf-8');
906 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
907 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
908 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
910 <meta http-equiv="Content-Language" content="en" />
911 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
912 <title>$name on Catalyst $VERSION</title>
913 <style type="text/css">
916 background-color: #eee;
925 background-color: #ccc;
926 border: 1px solid #aaa;
931 font-family: verdana, tahoma, sans-serif;
934 font-family: verdana, tahoma, sans-serif;
937 text-decoration: none;
939 border-bottom: 1px dotted #bbb;
941 :link:hover, :visited:hover {
954 background-color: #fff;
955 border: 1px solid #aaa;
981 <h1><span id="appname">$name</span> on <a href="http://catalyst.perl.org">Catalyst</a>
986 <img src="$logo" alt="Catalyst Logo" />
988 <p>Welcome to the world of Catalyst.
989 This <a href="http://en.wikipedia.org/wiki/MVC">MVC</a>
990 framework will make web development something you had
991 never expected it to be: Fun, rewarding, and quick.</p>
992 <h2>What to do now?</h2>
993 <p>That really depends on what <b>you</b> want to do.
994 We do, however, provide you with a few starting points.</p>
995 <p>If you want to jump right into web development with Catalyst
996 you might want to start with a tutorial.</p>
997 <pre>perldoc <a href="http://cpansearch.perl.org/dist/Catalyst-Manual/lib/Catalyst/Manual/Tutorial.pod">Catalyst::Manual::Tutorial</a></code>
999 <p>Afterwards you can go on to check out a more complete look at our features.</p>
1001 <code>perldoc <a href="http://cpansearch.perl.org/dist/Catalyst-Manual/lib/Catalyst/Manual/Intro.pod">Catalyst::Manual::Intro</a>
1002 <!-- Something else should go here, but the Catalyst::Manual link seems unhelpful -->
1004 <h2>What to do next?</h2>
1005 <p>Next it's time to write an actual application. Use the
1006 helper scripts to generate <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AController%3A%3A&mode=all">controllers</a>,
1007 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AModel%3A%3A&mode=all">models</a>, and
1008 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AView%3A%3A&mode=all">views</a>;
1009 they can save you a lot of work.</p>
1010 <pre><code>script/${prefix}_create.pl -help</code></pre>
1011 <p>Also, be sure to check out the vast and growing
1012 collection of <a href="http://search.cpan.org/search?query=Catalyst">plugins for Catalyst on CPAN</a>;
1013 you are likely to find what you need there.
1017 <p>Catalyst has a very active community. Here are the main places to
1018 get in touch with us.</p>
1021 <a href="http://dev.catalyst.perl.org">Wiki</a>
1024 <a href="http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst">Mailing-List</a>
1027 <a href="irc://irc.perl.org/catalyst">IRC channel #catalyst on irc.perl.org</a>
1030 <h2>In conclusion</h2>
1031 <p>The Catalyst team hopes you will enjoy using Catalyst as much
1032 as we enjoyed making it. Please contact us if you have ideas
1033 for improvement or other feedback.</p>
1041 =head1 INTERNAL METHODS
1043 These methods are not meant to be used by end users.
1045 =head2 $c->components
1047 Returns a hash of components.
1049 =head2 $c->context_class
1051 Returns or sets the context class.
1053 =head2 $c->dispatcher_class
1055 Returns or sets the dispatcher class.
1057 =head2 $c->engine_class
1059 Returns or sets the engine class.
1061 =head2 $c->handle_request( $class, @arguments )
1063 Called to handle each HTTP request.
1067 sub handle_request {
1068 my ( $class, @arguments ) = @_;
1070 # Always expect worst case!
1073 if ($class->debug) {
1074 my $secs = time - $START || 1;
1075 my $av = sprintf '%.3f', $COUNT / $secs;
1076 my $time = localtime time;
1077 $class->log->info("*** Request $COUNT ($av/s) [$$] [$time] ***");
1080 my $c = $class->prepare(@arguments);
1082 $status = $c->finalize;
1085 if ( my $error = $@ ) {
1087 $class->log->error(qq/Caught exception in engine "$error"/);
1092 if(my $coderef = $class->log->can('_flush')){
1093 $class->log->$coderef();
1098 =head2 $c->prepare( @arguments )
1100 Creates a Catalyst context from an engine-specific request (Apache, CGI,
1106 my ( $class, @arguments ) = @_;
1109 # After the app/ctxt split, this should become an attribute based on something passed
1110 # into the application.
1111 $class->context_class( ref $class || $class ) unless $class->context_class;
1113 my $app = $class->new({});
1114 my $c = $class->context_class->new( application => $app );
1116 # For on-demand data
1117 $c->request->_context($c);
1118 $c->response->_context($c);
1120 #surely this is not the most efficient way to do things...
1121 $c->stats($class->stats_class->new)->enable($c->use_stats);
1123 $c->res->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
1126 #XXX reuse coderef from can
1127 # Allow engine to direct the prepare flow (for POE)
1128 if ( $c->engine->can('prepare') ) {
1129 $c->engine->prepare( $c, @arguments );
1132 $c->prepare_request(@arguments);
1133 $c->prepare_connection;
1134 $c->prepare_query_parameters;
1135 $c->prepare_headers;
1136 $c->prepare_cookies;
1139 # Prepare the body for reading, either by prepare_body
1140 # or the user, if they are using $c->read
1143 # Parse the body unless the user wants it on-demand
1144 unless ( $app->config->{parse_on_demand} ) {
1149 my $method = $c->req->method || '';
1150 my $path = $c->req->path;
1151 $path = '/' unless length $path;
1152 my $address = $c->req->address || '';
1154 $c->log->debug(qq/"$method" request for "$path" from "$address"/)
1162 =head2 $c->request_class
1164 Returns or sets the request class.
1166 =head2 $c->response_class
1168 Returns or sets the response class.
1176 sub run { my $c = shift; return $c->engine->run( $c, @_ ) }
1178 =head2 $c->set_action( $action, $code, $namespace, $attrs )
1180 Sets an action in a given namespace.
1184 sub set_action { my $c = shift; $c->dispatcher->set_action( $c, @_ ) }
1186 =head2 $c->setup_actions($component)
1188 Sets up actions for a component.
1192 sub setup_actions { my $c = shift; $c->dispatcher->setup_actions( $c, @_ ) }
1194 =head2 $c->setup_components
1196 This method is called internally to set up the application's components.
1198 It finds modules by calling the L<locate_components> method, expands them to
1199 package names with the L<expand_component_module> method, and then installs
1200 each component into the application.
1202 The C<setup_components> config option is passed to both of the above methods.
1204 Installation of each component is performed by the L<setup_component> method,
1209 sub setup_components {
1212 my $config = $class->config->{ setup_components };
1214 my @comps = sort { length $a <=> length $b }
1215 $class->locate_components($config);
1216 my %comps = map { $_ => 1 } @comps;
1218 my $deprecatedcatalyst_component_names = grep { /::[CMV]::/ } @comps;
1219 $class->log->warn(qq{Your application is using the deprecated ::[MVC]:: type naming scheme.\n}.
1220 qq{Please switch your class names to ::Model::, ::View:: and ::Controller: as appropriate.\n}
1221 ) if $deprecatedcatalyst_component_names;
1223 for my $component ( @comps ) {
1225 # We pass ignore_loaded here so that overlay files for (e.g.)
1226 # Model::DBI::Schema sub-classes are loaded - if it's in @comps
1227 # we know M::P::O found a file on disk so this is safe
1229 Catalyst::Utils::ensure_class_loaded( $component, { ignore_loaded => 1 } );
1231 # Needs to be done as soon as the component is loaded, as loading a sub-component
1232 # (next time round the loop) can cause us to get the wrong metaclass..
1233 $class->_controller_init_base_classes($component);
1236 for my $component (@comps) {
1237 $class->components->{ $component } = $class->setup_component($component);
1238 for my $component ($class->expand_component_module( $component, $config )) {
1239 next if $comps{$component};
1240 $class->_controller_init_base_classes($component); # Also cover inner packages
1241 $class->components->{ $component } = $class->setup_component($component);
1246 =head2 $c->locate_components( $setup_component_config )
1248 This method is meant to provide a list of component modules that should be
1249 setup for the application. By default, it will use L<Module::Pluggable>.
1251 Specify a C<setup_components> config option to pass additional options directly
1252 to L<Module::Pluggable>. To add additional search paths, specify a key named
1253 C<search_extra> as an array reference. Items in the array beginning with C<::>
1254 will have the application class name prepended to them.
1258 sub locate_components {
1262 my @paths = qw( ::Controller ::C ::Model ::M ::View ::V );
1263 my $extra = delete $config->{ search_extra } || [];
1265 push @paths, @$extra;
1267 my $locator = Module::Pluggable::Object->new(
1268 search_path => [ map { s/^(?=::)/$class/; $_; } @paths ],
1272 my @comps = $locator->plugins;
1277 =head2 $c->expand_component_module( $component, $setup_component_config )
1279 Components found by C<locate_components> will be passed to this method, which
1280 is expected to return a list of component (package) names to be set up.
1284 sub expand_component_module {
1285 my ($class, $module) = @_;
1286 return Devel::InnerPackage::list_packages( $module );
1289 =head2 $c->setup_component
1293 # FIXME - Ugly, ugly hack to ensure the we force initialize non-moose base classes
1294 # nearest to Catalyst::Controller first, no matter what order stuff happens
1295 # to be loaded. There are TODO tests in Moose for this, see
1296 # f2391d17574eff81d911b97be15ea51080500003
1297 sub _controller_init_base_classes {
1298 my ($app_class, $component) = @_;
1299 return unless $component->isa('Catalyst::Controller');
1300 foreach my $class ( reverse @{ mro::get_linear_isa($component) } ) {
1301 Moose::Meta::Class->initialize( $class )
1302 unless find_meta($class);
1306 sub setup_component {
1307 my( $class, $component ) = @_;
1309 unless ( $component->can( 'COMPONENT' ) ) {
1313 my $suffix = Catalyst::Utils::class2classsuffix( $component );
1314 my $config = $class->config->{ $suffix } || {};
1315 # Stash catalyst_component_name in the config here, so that custom COMPONENT
1316 # methods also pass it. local to avoid pointlessly shitting in config
1317 # for the debug screen, as $component is already the key name.
1318 local $config->{catalyst_component_name} = $component;
1320 my $instance = eval { $component->COMPONENT( $class, $config ); };
1322 if ( my $error = $@ ) {
1324 Catalyst::Exception->throw(
1325 message => qq/Couldn't instantiate component "$component", "$error"/
1329 unless (blessed $instance) {
1330 my $metaclass = Moose::Util::find_meta($component);
1331 my $method_meta = $metaclass->find_method_by_name('COMPONENT');
1332 my $component_method_from = $method_meta->associated_metaclass->name;
1333 my $value = defined($instance) ? $instance : 'undef';
1334 Catalyst::Exception->throw(
1336 qq/Couldn't instantiate component "$component", COMPONENT() method (from $component_method_from) didn't return an object-like value (value was $value)./
1342 =head2 $c->setup_dispatcher
1348 sub setup_dispatcher {
1349 my ( $class, $dispatcher ) = @_;
1352 $dispatcher = 'Catalyst::Dispatcher::' . $dispatcher;
1355 if ( my $env = Catalyst::Utils::env_value( $class, 'DISPATCHER' ) ) {
1356 $dispatcher = 'Catalyst::Dispatcher::' . $env;
1359 unless ($dispatcher) {
1360 $dispatcher = $class->dispatcher_class;
1363 Class::MOP::load_class($dispatcher);
1365 # dispatcher instance
1366 $class->dispatcher( $dispatcher->new );
1369 =head2 $c->setup_engine
1376 my ( $class, $engine ) = @_;
1379 $engine = 'Catalyst::Engine::' . $engine;
1382 if ( my $env = Catalyst::Utils::env_value( $class, 'ENGINE' ) ) {
1383 $engine = 'Catalyst::Engine::' . $env;
1386 if ( $ENV{MOD_PERL} ) {
1387 my $meta = Class::MOP::get_metaclass_by_name($class);
1389 # create the apache method
1390 $meta->add_method('apache' => sub { shift->engine->apache });
1392 my ( $software, $version ) =
1393 $ENV{MOD_PERL} =~ /^(\S+)\/(\d+(?:[\.\_]\d+)+)/;
1396 $version =~ s/(\.[^.]+)\./$1/g;
1398 if ( $software eq 'mod_perl' ) {
1402 if ( $version >= 1.99922 ) {
1403 $engine = 'Catalyst::Engine::Apache2::MP20';
1406 elsif ( $version >= 1.9901 ) {
1407 $engine = 'Catalyst::Engine::Apache2::MP19';
1410 elsif ( $version >= 1.24 ) {
1411 $engine = 'Catalyst::Engine::Apache::MP13';
1415 Catalyst::Exception->throw( message =>
1416 qq/Unsupported mod_perl version: $ENV{MOD_PERL}/ );
1421 # install the correct mod_perl handler
1422 if ( $version >= 1.9901 ) {
1423 *handler = sub : method {
1424 shift->handle_request(@_);
1428 *handler = sub ($$) { shift->handle_request(@_) };
1433 elsif ( $software eq 'Zeus-Perl' ) {
1434 $engine = 'Catalyst::Engine::Zeus';
1438 Catalyst::Exception->throw(
1439 message => qq/Unsupported mod_perl: $ENV{MOD_PERL}/ );
1444 $engine = $class->engine_class;
1447 Class::MOP::load_class($engine);
1449 # check for old engines that are no longer compatible
1451 if ( $engine->isa('Catalyst::Engine::Apache')
1452 && !Catalyst::Engine::Apache->VERSION )
1457 elsif ( $engine->isa('Catalyst::Engine::Server::Base')
1458 && Catalyst::Engine::Server->VERSION le '0.02' )
1463 elsif ($engine->isa('Catalyst::Engine::HTTP::POE')
1464 && $engine->VERSION eq '0.01' )
1469 elsif ($engine->isa('Catalyst::Engine::Zeus')
1470 && $engine->VERSION eq '0.01' )
1476 Catalyst::Exception->throw( message =>
1477 qq/Engine "$engine" is not supported by this version of Catalyst/
1482 $class->engine( $engine->new );
1485 =head2 $c->setup_home
1487 Sets up the home directory.
1492 my ( $class, $home ) = @_;
1494 if ( my $env = Catalyst::Utils::env_value( $class, 'HOME' ) ) {
1498 $home ||= Catalyst::Utils::home($class);
1501 #I remember recently being scolded for assigning config values like this
1502 $class->config->{home} ||= $home;
1503 $class->config->{root} ||= Path::Class::Dir->new($home)->subdir('root');
1507 =head2 $c->setup_log
1509 Sets up log by instantiating a L<Catalyst::Log|Catalyst::Log> object and
1510 passing it to C<log()>. Pass in a comma-delimited list of levels to set the
1513 This method also installs a C<debug> method that returns a true value into the
1514 catalyst subclass if the "debug" level is passed in the comma-delimited list,
1515 or if the C<$CATALYST_DEBUG> environment variable is set to a true value.
1517 Note that if the log has already been setup, by either a previous call to
1518 C<setup_log> or by a call such as C<< __PACKAGE__->log( MyLogger->new ) >>,
1519 that this method won't actually set up the log object.
1524 my ( $class, $levels ) = @_;
1527 $levels =~ s/^\s+//;
1528 $levels =~ s/\s+$//;
1529 my %levels = map { $_ => 1 } split /\s*,\s*/, $levels;
1531 my $env_debug = Catalyst::Utils::env_value( $class, 'DEBUG' );
1532 if ( defined $env_debug ) {
1533 $levels{debug} = 1 if $env_debug; # Ugly!
1534 delete($levels{debug}) unless $env_debug;
1537 unless ( $class->log ) {
1538 $class->log( Catalyst::Log->new(keys %levels) );
1541 if ( $levels{debug} ) {
1542 Class::MOP::get_metaclass_by_name($class)->add_method('debug' => sub { 1 });
1543 $class->log->debug('Debug messages enabled');
1547 =head2 $c->setup_plugins
1553 =head2 $c->setup_stats
1555 Sets up timing statistics class.
1560 my ( $class, $stats ) = @_;
1562 Catalyst::Utils::ensure_class_loaded($class->stats_class);
1564 my $env = Catalyst::Utils::env_value( $class, 'STATS' );
1565 if ( defined($env) ? $env : ($stats || $class->debug ) ) {
1566 Class::MOP::get_metaclass_by_name($class)->add_method('use_stats' => sub { 1 });
1567 $class->log->debug('Statistics enabled');
1572 =head2 $c->registered_plugins
1574 Returns a sorted list of the plugins which have either been stated in the
1575 import list or which have been added via C<< MyApp->plugin(@args); >>.
1577 If passed a given plugin name, it will report a boolean value indicating
1578 whether or not that plugin is loaded. A fully qualified name is required if
1579 the plugin name does not begin with C<Catalyst::Plugin::>.
1581 if ($c->registered_plugins('Some::Plugin')) {
1589 sub registered_plugins {
1591 return sort keys %{ $proto->_plugins } unless @_;
1593 return 1 if exists $proto->_plugins->{$plugin};
1594 return exists $proto->_plugins->{"Catalyst::Plugin::$plugin"};
1597 sub _register_plugin {
1598 my ( $proto, $plugin, $instant ) = @_;
1599 my $class = ref $proto || $proto;
1601 Class::MOP::load_class( $plugin );
1603 $proto->_plugins->{$plugin} = 1;
1606 if ( my $meta = Class::MOP::get_metaclass_by_name($class) ) {
1607 my @superclasses = ($plugin, $meta->superclasses );
1608 $meta->superclasses(@superclasses);
1610 unshift @{"$class\::ISA"}, $plugin;
1617 my ( $class, $plugins ) = @_;
1619 $class->_plugins( {} ) unless $class->_plugins;
1622 my @plugins = Catalyst::Utils::resolve_namespace($class . '::Plugin', 'Catalyst::Plugin', @$plugins);
1624 for my $plugin ( reverse @plugins ) {
1625 Class::MOP::load_class($plugin);
1626 my $meta = find_meta($plugin);
1627 next if $meta && $meta->isa('Moose::Meta::Role');
1629 $class->_register_plugin($plugin);
1634 grep { $_ && blessed($_) && $_->isa('Moose::Meta::Role') }
1635 map { find_meta($_) }
1638 Moose::Util::apply_all_roles(
1644 =head2 $c->stats_class
1646 Returns or sets the stats (timing statistics) class.
1648 =head2 $c->use_stats
1650 Returns 1 when stats collection is enabled. Stats collection is enabled
1651 when the -Stats options is set, debug is on or when the <MYAPP>_STATS
1652 environment variable is set.
1654 Note that this is a static method, not an accessor and should be overridden
1655 by declaring C<sub use_stats { 1 }> in your MyApp.pm, not by calling C<< $c->use_stats(1) >>.
1663 Returns the Catalyst version number. Mostly useful for "powered by"
1664 messages in template systems.
1668 sub version { return $Catalyst::VERSION }
1670 =head1 CONFIGURATION
1672 There are a number of 'base' config variables which can be set:
1678 C<default_model> - The default model picked if you say C<< $c->model >>. See L</$c->model($name)>.
1682 C<default_view> - The default view to be rendered or returned when C<< $c->view >>. See L</$c->view($name)>.
1687 C<disable_component_resolution_regex_fallback> - Turns
1688 off the deprecated component resolution functionality so
1689 that if any of the component methods (e.g. C<< $c->controller('Foo') >>)
1690 are called then regex search will not be attempted on string values and
1691 instead C<undef> will be returned.
1695 C<home> - The application home directory. In an uninstalled application,
1696 this is the top level application directory. In an installed application,
1697 this will be the directory containing C<< MyApp.pm >>.
1701 C<ignore_frontend_proxy> - See L</PROXY SUPPORT>
1705 C<name> - The name of the application in debug messages and the debug and
1710 C<parse_on_demand> - The request body (for example file uploads) will not be parsed
1711 until it is accessed. This allows you to (for example) check authentication (and reject
1712 the upload) before actually recieving all the data. See L</ON-DEMAND PARSER>
1716 C<root> - The root directory for templates. Usually this is just a
1717 subdirectory of the home directory, but you can set it to change the
1718 templates to a different directory.
1722 C<search_extra> - Array reference passed to Module::Pluggable to for additional
1723 namespaces from which components will be loaded (and constructed and stored in
1724 C<< $c->components >>).
1728 C<show_internal_actions> - If true, causes internal actions such as C<< _DISPATCH >>
1729 to be shown in hit debug tables in the test server.
1733 C<using_frontend_proxy> - See L</PROXY SUPPORT>.
1737 =head1 INTERNAL ACTIONS
1739 Catalyst uses internal actions like C<_DISPATCH>, C<_BEGIN>, C<_AUTO>,
1740 C<_ACTION>, and C<_END>. These are by default not shown in the private
1741 action table, but you can make them visible with a config parameter.
1743 MyApp->config(show_internal_actions => 1);
1745 =head1 ON-DEMAND PARSER
1747 The request body is usually parsed at the beginning of a request,
1748 but if you want to handle input yourself, you can enable on-demand
1749 parsing with a config parameter.
1751 MyApp->config(parse_on_demand => 1);
1753 =head1 PROXY SUPPORT
1755 Many production servers operate using the common double-server approach,
1756 with a lightweight frontend web server passing requests to a larger
1757 backend server. An application running on the backend server must deal
1758 with two problems: the remote user always appears to be C<127.0.0.1> and
1759 the server's hostname will appear to be C<localhost> regardless of the
1760 virtual host that the user connected through.
1762 Catalyst will automatically detect this situation when you are running
1763 the frontend and backend servers on the same machine. The following
1764 changes are made to the request.
1766 $c->req->address is set to the user's real IP address, as read from
1767 the HTTP X-Forwarded-For header.
1769 The host value for $c->req->base and $c->req->uri is set to the real
1770 host, as read from the HTTP X-Forwarded-Host header.
1772 Additionally, you may be running your backend application on an insecure
1773 connection (port 80) while your frontend proxy is running under SSL. If there
1774 is a discrepancy in the ports, use the HTTP header C<X-Forwarded-Port> to
1775 tell Catalyst what port the frontend listens on. This will allow all URIs to
1776 be created properly.
1778 In the case of passing in:
1780 X-Forwarded-Port: 443
1782 All calls to C<uri_for> will result in an https link, as is expected.
1784 Obviously, your web server must support these headers for this to work.
1786 In a more complex server farm environment where you may have your
1787 frontend proxy server(s) on different machines, you will need to set a
1788 configuration option to tell Catalyst to read the proxied data from the
1791 MyApp->config(using_frontend_proxy => 1);
1793 If you do not wish to use the proxy support at all, you may set:
1795 MyApp->config(ignore_frontend_proxy => 1);
1797 =head1 THREAD SAFETY
1799 Catalyst has been tested under Apache 2's threading C<mpm_worker>,
1800 C<mpm_winnt>, and the standalone forking HTTP server on Windows. We
1801 believe the Catalyst core to be thread-safe.
1803 If you plan to operate in a threaded environment, remember that all other
1804 modules you are using must also be thread-safe. Some modules, most notably
1805 L<DBD::SQLite>, are not thread-safe.
1811 Join #catalyst on irc.perl.org.
1815 http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
1816 http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst-dev
1820 http://catalyst.perl.org
1824 http://dev.catalyst.perl.org
1828 =head2 L<Task::Catalyst> - All you need to start with Catalyst
1830 =head2 L<Catalyst::Manual> - The Catalyst Manual
1832 =head2 L<Catalyst::Component>, L<Catalyst::Controller> - Base classes for components
1834 =head2 L<Catalyst::Engine> - Core engine
1836 =head2 L<Catalyst::Log> - Log class.
1838 =head2 L<Catalyst::Request> - Request object
1840 =head2 L<Catalyst::Response> - Response object
1842 =head2 L<Catalyst::Test> - The test suite.
1844 =head1 PROJECT FOUNDER
1846 sri: Sebastian Riedel <sri@cpan.org>
1852 acme: Leon Brocard <leon@astray.com>
1854 abraxxa: Alexander Hartmaier <abraxxa@cpan.org>
1858 Andrew Ford E<lt>A.Ford@ford-mason.co.ukE<gt>
1862 andyg: Andy Grundman <andy@hybridized.org>
1864 audreyt: Audrey Tang
1866 bricas: Brian Cassidy <bricas@cpan.org>
1868 Caelum: Rafael Kitover <rkitover@io.com>
1870 chansen: Christian Hansen
1872 chicks: Christopher Hicks
1874 Chisel Wright C<pause@herlpacker.co.uk>
1876 Danijel Milicevic C<me@danijel.de>
1878 David Kamholz E<lt>dkamholz@cpan.orgE<gt>
1880 David Naughton, C<naughton@umn.edu>
1884 dkubb: Dan Kubb <dan.kubb-cpan@onautopilot.com>
1888 dwc: Daniel Westermann-Clark <danieltwc@cpan.org>
1890 esskar: Sascha Kiefer
1892 fireartist: Carl Franks <cfranks@cpan.org>
1894 frew: Arthur Axel "fREW" Schmidt <frioux@gmail.com>
1896 gabb: Danijel Milicevic
1900 Gavin Henry C<ghenry@perl.me.uk>
1904 groditi: Guillermo Roditi <groditi@gmail.com>
1906 hobbs: Andrew Rodland <andrew@cleverdomain.org>
1908 ilmari: Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>
1910 jcamacho: Juan Camacho
1912 jester: Jesse Sheidlower C<jester@panix.com>
1914 jhannah: Jay Hannah <jay@jays.net>
1920 jon: Jon Schutz <jjschutz@cpan.org>
1922 Jonathan Rockway C<< <jrockway@cpan.org> >>
1924 Kieren Diment C<kd@totaldatasolution.com>
1926 konobi: Scott McWhirter <konobi@cpan.org>
1928 marcus: Marcus Ramberg <mramberg@cpan.org>
1930 miyagawa: Tatsuhiko Miyagawa <miyagawa@bulknews.net>
1932 mst: Matt S. Trout <mst@shadowcatsystems.co.uk>
1936 naughton: David Naughton
1938 ningu: David Kamholz <dkamholz@cpan.org>
1940 nothingmuch: Yuval Kogman <nothingmuch@woobling.org>
1942 numa: Dan Sully <daniel@cpan.org>
1946 omega: Andreas Marienborg
1948 Oleg Kostyuk <cub.uanic@gmail.com>
1950 phaylon: Robert Sedlacek <phaylon@dunkelheit.at>
1952 rafl: Florian Ragwitz <rafl@debian.org>
1954 random: Roland Lammel <lammel@cpan.org>
1956 Robert Sedlacek C<< <rs@474.at> >>
1960 t0m: Tomas Doran <bobtfish@bobtfish.net>
1964 Viljo Marrandi C<vilts@yahoo.com>
1966 Will Hawes C<info@whawes.co.uk>
1968 willert: Sebastian Willert <willert@cpan.org>
1970 Yuval Kogman, C<nothingmuch@woobling.org>
1974 This library is free software. You can redistribute it and/or modify it under
1975 the same terms as Perl itself.
1981 __PACKAGE__->meta->make_immutable;