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 Devel::InnerPackage ();
14 use Module::Pluggable::Object ();
15 use Text::SimpleTable ();
16 use Path::Class::Dir ();
17 use Path::Class::File ();
18 use Tree::Simple::Visitor::FindByUID;
19 use Class::C3::Adopt::NEXT;
22 use Carp qw/croak carp shortmess/;
24 BEGIN { require 5.008004; }
26 sub comp { shift->component(@_) }
28 #I imagine that very few of these really need to be class variables. if any.
29 #maybe we should just make them attributes with a default?
30 __PACKAGE__->mk_classdata($_)
31 for qw/components arguments dispatcher engine log dispatcher_class
32 engine_class context_class request_class response_class stats_class
35 __PACKAGE__->context_class('Catalyst::Context');
36 __PACKAGE__->dispatcher_class('Catalyst::Dispatcher');
37 __PACKAGE__->engine_class('Catalyst::Engine::CGI');
38 __PACKAGE__->request_class('Catalyst::Request');
39 __PACKAGE__->response_class('Catalyst::Response');
40 __PACKAGE__->stats_class('Catalyst::Stats');
42 # Remember to update this in Catalyst::Runtime as well!
44 our $VERSION = '5.80013';
47 my $dev_version = $VERSION =~ /_\d{2}$/;
48 *_IS_DEVELOPMENT_VERSION = sub () { $dev_version };
51 $VERSION = eval $VERSION;
55 our $DETACH = Catalyst::Exception::Detach->new;
56 our $GO = Catalyst::Exception::Go->new;
59 my ( $class, @arguments ) = @_;
61 # We have to limit $class to Catalyst to avoid pushing Catalyst upon every
63 return unless $class eq 'Catalyst';
65 my $caller = caller();
66 return if $caller eq 'main';
68 # Kill Adopt::NEXT warnings if we're a non-RC version
69 unless (_IS_DEVELOPMENT_VERSION()) {
70 Class::C3::Adopt::NEXT->unimport(qr/^Catalyst::/);
73 my $meta = Moose::Meta::Class->initialize($caller);
74 unless ( $caller->isa('Catalyst') ) {
75 my @superclasses = ($meta->superclasses, $class, 'Catalyst::Controller');
76 $meta->superclasses(@superclasses);
78 # Avoid possible C3 issues if 'Moose::Object' is already on RHS of MyApp
79 $meta->superclasses(grep { $_ ne 'Moose::Object' } $meta->superclasses);
81 unless( $meta->has_method('meta') ){
82 $meta->add_method(meta => sub { Moose::Meta::Class->initialize("${caller}") } );
85 $caller->arguments( [@arguments] );
89 sub _application { $_[0] }
93 Catalyst - The Elegant MVC Web Application Framework
97 See the L<Catalyst::Manual> distribution for comprehensive
98 documentation and tutorials.
100 # Install Catalyst::Devel for helpers and other development tools
101 # use the helper to create a new application
104 # add models, views, controllers
105 script/myapp_create.pl model MyDatabase DBIC::Schema create=static dbi:SQLite:/path/to/db
106 script/myapp_create.pl view MyTemplate TT
107 script/myapp_create.pl controller Search
109 # built in testserver -- use -r to restart automatically on changes
110 # --help to see all available options
111 script/myapp_server.pl
113 # command line testing interface
114 script/myapp_test.pl /yada
117 use Catalyst qw/-Debug/; # include plugins here as well
119 ### In lib/MyApp/Controller/Root.pm (autocreated)
120 sub foo : Global { # called for /foo, /foo/1, /foo/1/2, etc.
121 my ( $self, $c, @args ) = @_; # args are qw/1 2/ for /foo/1/2
122 $c->stash->{template} = 'foo.tt'; # set the template
123 # lookup something from db -- stash vars are passed to TT
125 $c->model('Database::Foo')->search( { country => $args[0] } );
126 if ( $c->req->params->{bar} ) { # access GET or POST parameters
127 $c->forward( 'bar' ); # process another action
128 # do something else after forward returns
132 # The foo.tt TT template can use the stash data from the database
133 [% WHILE (item = data.next) %]
137 # called for /bar/of/soap, /bar/of/soap/10, etc.
138 sub bar : Path('/bar/of/soap') { ... }
140 # called for all actions, from the top-most controller downwards
142 my ( $self, $c ) = @_;
143 if ( !$c->user_exists ) { # Catalyst::Plugin::Authentication
144 $c->res->redirect( '/login' ); # require login
145 return 0; # abort request and go immediately to end()
147 return 1; # success; carry on to next action
150 # called after all actions are finished
152 my ( $self, $c ) = @_;
153 if ( scalar @{ $c->error } ) { ... } # handle errors
154 return if $c->res->body; # already have a response
155 $c->forward( 'MyApp::View::TT' ); # render template
158 ### in MyApp/Controller/Foo.pm
159 # called for /foo/bar
160 sub bar : Local { ... }
162 # called for /blargle
163 sub blargle : Global { ... }
165 # an index action matches /foo, but not /foo/1, etc.
166 sub index : Private { ... }
168 ### in MyApp/Controller/Foo/Bar.pm
169 # called for /foo/bar/baz
170 sub baz : Local { ... }
172 # first Root auto is called, then Foo auto, then this
173 sub auto : Private { ... }
175 # powerful regular expression paths are also possible
176 sub details : Regex('^product/(\w+)/details$') {
177 my ( $self, $c ) = @_;
178 # extract the (\w+) from the URI
179 my $product = $c->req->captures->[0];
182 See L<Catalyst::Manual::Intro> for additional information.
186 Catalyst is a modern framework for making web applications without the
187 pain usually associated with this process. This document is a reference
188 to the main Catalyst application. If you are a new user, we suggest you
189 start with L<Catalyst::Manual::Tutorial> or L<Catalyst::Manual::Intro>.
191 See L<Catalyst::Manual> for more documentation.
193 Catalyst plugins can be loaded by naming them as arguments to the "use
194 Catalyst" statement. Omit the C<Catalyst::Plugin::> prefix from the
195 plugin name, i.e., C<Catalyst::Plugin::My::Module> becomes
198 use Catalyst qw/My::Module/;
200 If your plugin starts with a name other than C<Catalyst::Plugin::>, you can
201 fully qualify the name by using a unary plus:
205 +Fully::Qualified::Plugin::Name
208 Special flags like C<-Debug> and C<-Engine> can also be specified as
209 arguments when Catalyst is loaded:
211 use Catalyst qw/-Debug My::Module/;
213 The position of plugins and flags in the chain is important, because
214 they are loaded in the order in which they appear.
216 The following flags are supported:
220 Enables debug output. You can also force this setting from the system
221 environment with CATALYST_DEBUG or <MYAPP>_DEBUG. The environment
222 settings override the application, with <MYAPP>_DEBUG having the highest
227 Forces Catalyst to use a specific engine. Omit the
228 C<Catalyst::Engine::> prefix of the engine name, i.e.:
230 use Catalyst qw/-Engine=CGI/;
234 Forces Catalyst to use a specific home directory, e.g.:
236 use Catalyst qw[-Home=/usr/mst];
238 This can also be done in the shell environment by setting either the
239 C<CATALYST_HOME> environment variable or C<MYAPP_HOME>; where C<MYAPP>
240 is replaced with the uppercased name of your application, any "::" in
241 the name will be replaced with underscores, e.g. MyApp::Web should use
242 MYAPP_WEB_HOME. If both variables are set, the MYAPP_HOME one will be used.
246 use Catalyst '-Log=warn,fatal,error';
248 Specifies a comma-delimited list of log levels.
252 Enables statistics collection and reporting. You can also force this setting
253 from the system environment with CATALYST_STATS or <MYAPP>_STATS. The
254 environment settings override the application, with <MYAPP>_STATS having the
259 use Catalyst qw/-Stats=1/
265 =head2 $c->controller($name)
267 Gets a L<Catalyst::Controller> instance by name.
269 $c->controller('Foo')->do_stuff;
271 If the name is omitted, will return the controller for the dispatched
274 If you want to search for controllers, pass in a regexp as the argument.
276 # find all controllers that start with Foo
277 my @foo_controllers = $c->controller(qr{^Foo});
283 my ( $c, $name, @args ) = @_;
286 my @result = $c->_comp_search_prefixes( $name, qw/Controller C/ );
287 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
288 return $c->_filter_component( $result[ 0 ], @args );
291 return $c->component( $c->action->class );
295 my ( $c, $name, @args ) = @_;
298 my @result = $c->_comp_search_prefixes( $name, qw/View V/ );
299 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
300 return $c->_filter_component( $result[ 0 ], @args );
303 return $c->view( $c->config->{default_view} )
304 if $c->config->{default_view};
305 my( $comp, $rest ) = $c->_comp_search_prefixes( undef, qw/View V/);
308 $c->log->warn( 'Calling $c->view() will return a random view unless you specify one of:' );
309 $c->log->warn( '* $c->config(default_view => "the name of the default view to use")' );
310 $c->log->warn( '* $c->stash->{current_view} # the name of the view to use for this request' );
311 $c->log->warn( '* $c->stash->{current_view_instance} # the instance of the view to use for this request' );
312 $c->log->warn( 'NB: in version 5.81, the "random" behavior will not work at all.' );
315 return $c->_filter_component( $comp );
319 my ( $c, $name, @args ) = @_;
321 my @result = $c->_comp_search_prefixes( $name, qw/Model M/ );
322 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
323 return $c->_filter_component( $result[ 0 ], @args );
326 return $c->model( $c->config->{default_model} )
327 if $c->config->{default_model};
329 my( $comp, $rest ) = $c->_comp_search_prefixes( undef, qw/Model M/);
332 $c->log->warn( Carp::shortmess('Calling $c->model() will return a random model unless you specify one of:') );
333 $c->log->warn( '* $c->config(default_model => "the name of the default model to use")' );
334 $c->log->warn( '* $c->stash->{current_model} # the name of the model to use for this request' );
335 $c->log->warn( '* $c->stash->{current_model_instance} # the instance of the model to use for this request' );
336 $c->log->warn( 'NB: in version 5.81, the "random" behavior will not work at all.' );
339 return $c->_filter_component( $comp );
343 sub _comp_search_prefixes {
345 return map $c->components->{ $_ }, $c->_comp_names_search_prefixes(@_);
348 # search components given a name and some prefixes
349 sub _comp_names_search_prefixes {
350 my ( $c, $name, @prefixes ) = @_;
351 my $appclass = ref $c || $c;
352 my $filter = "^${appclass}::(" . join( '|', @prefixes ) . ')::';
353 $filter = qr/$filter/; # Compile regex now rather than once per loop
355 # map the original component name to the sub part that we will search against
356 my %eligible = map { my $n = $_; $n =~ s{^$appclass\::[^:]+::}{}; $_ => $n; }
357 grep { /$filter/ } keys %{ $c->components };
359 # undef for a name will return all
360 return keys %eligible if !defined $name;
362 my $query = ref $name ? $name : qr/^$name$/i;
363 my @result = grep { $eligible{$_} =~ m{$query} } keys %eligible;
365 return @result if @result;
367 # if we were given a regexp to search against, we're done.
370 # skip regexp fallback if configured
372 if $appclass->config->{disable_component_resolution_regex_fallback};
376 @result = grep { $eligible{ $_ } =~ m{$query} } keys %eligible;
378 # no results? try against full names
380 @result = grep { m{$query} } keys %eligible;
383 # don't warn if we didn't find any results, it just might not exist
385 # Disgusting hack to work out correct method name
386 my $warn_for = lc $prefixes[0];
387 my $msg = "Used regexp fallback for \$c->${warn_for}('${name}'), which found '" .
388 (join '", "', @result) . "'. Relying on regexp fallback behavior for " .
389 "component resolution is unreliable and unsafe.";
390 my $short = $result[0];
391 # remove the component namespace prefix
392 $short =~ s/.*?(Model|Controller|View):://;
393 my $shortmess = Carp::shortmess('');
394 if ($shortmess =~ m#Catalyst/Plugin#) {
395 $msg .= " You probably need to set '$short' instead of '${name}' in this " .
397 } elsif ($shortmess =~ m#Catalyst/lib/(View|Controller)#) {
398 $msg .= " You probably need to set '$short' instead of '${name}' in this " .
399 "component's config";
401 $msg .= " You probably meant \$c->${warn_for}('$short') instead of \$c->${warn_for}('${name}'), " .
402 "but if you really wanted to search, pass in a regexp as the argument " .
403 "like so: \$c->${warn_for}(qr/${name}/)";
405 $c->log->warn( "${msg}$shortmess" );
411 # Find possible names for a prefix
413 my ( $c, @prefixes ) = @_;
414 my $appclass = ref $c || $c;
416 my $filter = "^${appclass}::(" . join( '|', @prefixes ) . ')::';
418 my @names = map { s{$filter}{}; $_; }
419 $c->_comp_names_search_prefixes( undef, @prefixes );
424 # Filter a component before returning by calling ACCEPT_CONTEXT if available
425 sub _filter_component {
426 my ( $c, $comp, @args ) = @_;
428 if ( eval { $comp->can('ACCEPT_CONTEXT'); } ) {
429 return $comp->ACCEPT_CONTEXT( $c, @args );
435 =head2 COMPONENT ACCESSORS
437 =head2 $c->controllers
439 Returns the available names which can be passed to $c->controller
445 return $c->_comp_names(qw/Controller C/);
450 Returns the available names which can be passed to $c->model
456 return $c->_comp_names(qw/Model M/);
462 Returns the available names which can be passed to $c->view
468 return $c->_comp_names(qw/View V/);
471 =head2 $c->comp($name)
473 =head2 $c->component($name)
475 Gets a component object by name. This method is not recommended,
476 unless you want to get a specific component by full
477 class. C<< $c->controller >>, C<< $c->model >>, and C<< $c->view >>
478 should be used instead.
480 If C<$name> is a regexp, a list of components matched against the full
481 component name will be returned.
483 If Catalyst can't find a component by name, it will fallback to regex
484 matching by default. To disable this behaviour set
485 disable_component_resolution_regex_fallback to a true value.
487 __PACKAGE__->config( disable_component_resolution_regex_fallback => 1 );
492 my ( $c, $name, @args ) = @_;
495 my $comps = $c->components;
498 # is it the exact name?
499 return $c->_filter_component( $comps->{ $name }, @args )
500 if exists $comps->{ $name };
502 # perhaps we just omitted "MyApp"?
503 my $composed = ( ref $c || $c ) . "::${name}";
504 return $c->_filter_component( $comps->{ $composed }, @args )
505 if exists $comps->{ $composed };
507 # search all of the models, views and controllers
508 my( $comp ) = $c->_comp_search_prefixes( $name, qw/Model M Controller C View V/ );
509 return $c->_filter_component( $comp, @args ) if $comp;
512 # This is here so $c->comp( '::M::' ) works
513 my $query = ref $name ? $name : qr{$name}i;
515 my @result = grep { m{$query} } keys %{ $c->components };
516 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
519 $c->log->warn( Carp::shortmess(qq(Found results for "${name}" using regexp fallback)) );
520 $c->log->warn( 'Relying on the regexp fallback behavior for component resolution' );
521 $c->log->warn( 'is unreliable and unsafe. You have been warned' );
522 return $c->_filter_component( $result[ 0 ], @args );
525 # I would expect to return an empty list here, but that breaks back-compat
529 return sort keys %{ $c->components };
532 =head2 CLASS DATA AND HELPER CLASSES
536 Returns or takes a hashref containing the application's configuration.
538 __PACKAGE__->config( { db => 'dsn:SQLite:foo.db' } );
540 You can also use a C<YAML>, C<XML> or L<Config::General> config file
541 like C<myapp.conf> in your applications home directory. See
542 L<Catalyst::Plugin::ConfigLoader>.
544 =head3 Cascading configuration
546 The config method is present on all Catalyst components, and configuration
547 will be merged when an application is started. Configuration loaded with
548 L<Catalyst::Plugin::ConfigLoader> takes precedence over other configuration,
549 followed by configuration in your top level C<MyApp> class. These two
550 configurations are merged, and then configuration data whose hash key matches a
551 component name is merged with configuration for that component.
553 The configuration for a component is then passed to the C<new> method when a
554 component is constructed.
558 MyApp->config({ 'Model::Foo' => { bar => 'baz', overrides => 'me' } });
559 MyApp::Model::Foo->config({ quux => 'frob', 'overrides => 'this' });
561 will mean that C<MyApp::Model::Foo> receives the following data when
564 MyApp::Model::Foo->new({
572 around config => sub {
576 croak('Setting config after setup has been run is not allowed.')
577 if ( @_ and $c->setup_finished );
584 Returns the logging object instance. Unless it is already set, Catalyst
585 sets this up with a L<Catalyst::Log> object. To use your own log class,
586 set the logger with the C<< __PACKAGE__->log >> method prior to calling
587 C<< __PACKAGE__->setup >>.
589 __PACKAGE__->log( MyLogger->new );
594 $c->log->info( 'Now logging with my own logger!' );
596 Your log class should implement the methods described in
602 Returns 1 if debug mode is enabled, 0 otherwise.
604 You can enable debug mode in several ways:
608 =item By calling myapp_server.pl with the -d flag
610 =item With the environment variables MYAPP_DEBUG, or CATALYST_DEBUG
612 =item The -Debug option in your MyApp.pm
614 =item By declaring C<sub debug { 1 }> in your MyApp.pm.
618 Calling C<< $c->debug(1) >> has no effect.
624 =head2 $c->dispatcher
626 Returns the dispatcher instance. See L<Catalyst::Dispatcher>.
630 Returns the engine instance. See L<Catalyst::Engine>.
633 =head2 UTILITY METHODS
635 =head2 $c->path_to(@path)
637 Merges C<@path> with C<< $c->config->{home} >> and returns a
638 L<Path::Class::Dir> object. Note you can usually use this object as
639 a filename, but sometimes you will have to explicitly stringify it
640 yourself by calling the C<< ->stringify >> method.
644 $c->path_to( 'db', 'sqlite.db' );
649 my ( $c, @path ) = @_;
650 my $path = Path::Class::Dir->new( $c->config->{home}, @path );
651 if ( -d $path ) { return $path }
652 else { return Path::Class::File->new( $c->config->{home}, @path ) }
655 =head2 $c->plugin( $name, $class, @args )
657 Helper method for plugins. It creates a class data accessor/mutator and
658 loads and instantiates the given class.
660 MyApp->plugin( 'prototype', 'HTML::Prototype' );
662 $c->prototype->define_javascript_functions;
664 B<Note:> This method of adding plugins is deprecated. The ability
665 to add plugins like this B<will be removed> in a Catalyst 5.81.
666 Please do not use this functionality in new code.
671 my ( $class, $name, $plugin, @args ) = @_;
673 # See block comment in t/unit_core_plugin.t
674 $class->log->warn(qq/Adding plugin using the ->plugin method is deprecated, and will be removed in Catalyst 5.81/);
676 $class->_register_plugin( $plugin, 1 );
678 eval { $plugin->import };
679 $class->mk_classdata($name);
681 eval { $obj = $plugin->new(@args) };
684 Catalyst::Exception->throw( message =>
685 qq/Couldn't instantiate instant plugin "$plugin", "$@"/ );
689 $class->log->debug(qq/Initialized instant plugin "$plugin" as "$name"/)
695 Initializes the dispatcher and engine, loads any plugins, and loads the
696 model, view, and controller components. You may also specify an array
697 of plugins to load here, if you choose to not load them in the C<use
701 MyApp->setup( qw/-Debug/ );
706 my ( $class, @arguments ) = @_;
707 croak('Running setup more than once')
708 if ( $class->setup_finished );
710 unless ( $class->isa('Catalyst') ) {
712 Catalyst::Exception->throw(
713 message => qq/'$class' does not inherit from Catalyst/ );
716 if ( $class->arguments ) {
717 @arguments = ( @arguments, @{ $class->arguments } );
723 foreach (@arguments) {
727 ( $flags->{log} ) ? 'debug,' . $flags->{log} : 'debug';
729 elsif (/^-(\w+)=?(.*)$/) {
730 $flags->{ lc $1 } = $2;
733 push @{ $flags->{plugins} }, $_;
737 $class->setup_home( delete $flags->{home} );
739 $class->setup_log( delete $flags->{log} );
740 $class->setup_plugins( delete $flags->{plugins} );
741 $class->setup_dispatcher( delete $flags->{dispatcher} );
742 $class->setup_engine( delete $flags->{engine} );
743 $class->setup_stats( delete $flags->{stats} );
745 for my $flag ( sort keys %{$flags} ) {
747 if ( my $code = $class->can( 'setup_' . $flag ) ) {
748 &$code( $class, delete $flags->{$flag} );
751 $class->log->warn(qq/Unknown flag "$flag"/);
755 eval { require Catalyst::Devel; };
756 if( !$@ && $ENV{CATALYST_SCRIPT_GEN} && ( $ENV{CATALYST_SCRIPT_GEN} < $Catalyst::Devel::CATALYST_SCRIPT_GEN ) ) {
757 $class->log->warn(<<"EOF");
758 You are running an old script!
760 Please update by running (this will overwrite existing files):
761 catalyst.pl -force -scripts $class
763 or (this will not overwrite existing files):
764 catalyst.pl -scripts $class
769 if ( $class->debug ) {
770 my @plugins = map { "$_ " . ( $_->VERSION || '' ) } $class->registered_plugins;
773 my $column_width = Catalyst::Utils::term_width() - 6;
774 my $t = Text::SimpleTable->new($column_width);
775 $t->row($_) for @plugins;
776 $class->log->debug( "Loaded plugins:\n" . $t->draw . "\n" );
779 my $dispatcher = $class->dispatcher;
780 my $engine = $class->engine;
781 my $home = $class->config->{home};
783 $class->log->debug(sprintf(q/Loaded dispatcher "%s"/, blessed($dispatcher)));
784 $class->log->debug(sprintf(q/Loaded engine "%s"/, blessed($engine)));
788 ? $class->log->debug(qq/Found home "$home"/)
789 : $class->log->debug(qq/Home "$home" doesn't exist/)
790 : $class->log->debug(q/Couldn't find home/);
793 # Call plugins setup, this is stupid and evil.
794 # Also screws C3 badly on 5.10, hack to avoid.
796 no warnings qw/redefine/;
797 local *setup = sub { };
798 $class->setup unless $Catalyst::__AM_RESTARTING;
801 # Initialize our data structure
802 $class->components( {} );
804 $class->setup_components;
806 if ( $class->debug ) {
807 my $column_width = Catalyst::Utils::term_width() - 8 - 9;
808 my $t = Text::SimpleTable->new( [ $column_width, 'Class' ], [ 8, 'Type' ] );
809 for my $comp ( sort keys %{ $class->components } ) {
810 my $type = ref $class->components->{$comp} ? 'instance' : 'class';
811 $t->row( $comp, $type );
813 $class->log->debug( "Loaded components:\n" . $t->draw . "\n" )
814 if ( keys %{ $class->components } );
817 # Add our self to components, since we are also a component
818 if( $class->isa('Catalyst::Controller') ){
819 $class->components->{$class} = $class;
822 $class->setup_actions;
824 if ( $class->debug ) {
825 my $name = $class->config->{name} || 'Application';
826 $class->log->info("$name powered by Catalyst $Catalyst::VERSION");
829 # Make sure that the application class becomes immutable at this point,
830 B::Hooks::EndOfScope::on_scope_end {
832 my $meta = Class::MOP::get_metaclass_by_name($class);
835 && ! { $meta->immutable_options }->{replace_constructor}
837 $class->isa('Class::Accessor::Fast')
838 || $class->isa('Class::Accessor')
841 warn "You made your application class ($class) immutable, "
842 . "but did not inline the\nconstructor. "
843 . "This will break catalyst, as your app \@ISA "
844 . "Class::Accessor(::Fast)?\nPlease pass "
845 . "(replace_constructor => 1)\nwhen making your class immutable.\n";
847 $meta->make_immutable(
848 replace_constructor => 1,
849 ) unless $meta->is_immutable;
852 $class->setup_finalize;
853 # Should be the last thing we do so that user things hooking
854 # setup_finalize can log..
855 $class->log->_flush() if $class->log->can('_flush');
856 return 1; # Explicit return true as people have __PACKAGE__->setup as the last thing in their class. HATE.
860 =head2 $app->setup_finalize
862 A hook to attach modifiers to.
863 Using C<< after setup => sub{}; >> doesn't work, because of quirky things done for plugin setup.
864 Also better than C< setup_finished(); >, as that is a getter method.
870 ## do stuff, i.e., determine a primary key column for sessions stored in a DB
872 $app->next::method(@_);
881 $class->setup_finished(1);
884 =head2 $c->welcome_message
886 Returns the Catalyst welcome HTML page.
890 sub welcome_message {
892 my $name = $c->config->{name};
893 my $logo = $c->uri_for('/static/images/catalyst_logo.png');
894 my $prefix = Catalyst::Utils::appprefix( ref $c );
895 $c->response->content_type('text/html; charset=utf-8');
897 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
898 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
899 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
901 <meta http-equiv="Content-Language" content="en" />
902 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
903 <title>$name on Catalyst $VERSION</title>
904 <style type="text/css">
907 background-color: #eee;
916 background-color: #ccc;
917 border: 1px solid #aaa;
922 font-family: verdana, tahoma, sans-serif;
925 font-family: verdana, tahoma, sans-serif;
928 text-decoration: none;
930 border-bottom: 1px dotted #bbb;
932 :link:hover, :visited:hover {
945 background-color: #fff;
946 border: 1px solid #aaa;
972 <h1><span id="appname">$name</span> on <a href="http://catalyst.perl.org">Catalyst</a>
977 <img src="$logo" alt="Catalyst Logo" />
979 <p>Welcome to the world of Catalyst.
980 This <a href="http://en.wikipedia.org/wiki/MVC">MVC</a>
981 framework will make web development something you had
982 never expected it to be: Fun, rewarding, and quick.</p>
983 <h2>What to do now?</h2>
984 <p>That really depends on what <b>you</b> want to do.
985 We do, however, provide you with a few starting points.</p>
986 <p>If you want to jump right into web development with Catalyst
987 you might want to start with a tutorial.</p>
988 <pre>perldoc <a href="http://cpansearch.perl.org/dist/Catalyst-Manual/lib/Catalyst/Manual/Tutorial.pod">Catalyst::Manual::Tutorial</a></code>
990 <p>Afterwards you can go on to check out a more complete look at our features.</p>
992 <code>perldoc <a href="http://cpansearch.perl.org/dist/Catalyst-Manual/lib/Catalyst/Manual/Intro.pod">Catalyst::Manual::Intro</a>
993 <!-- Something else should go here, but the Catalyst::Manual link seems unhelpful -->
995 <h2>What to do next?</h2>
996 <p>Next it's time to write an actual application. Use the
997 helper scripts to generate <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AController%3A%3A&mode=all">controllers</a>,
998 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AModel%3A%3A&mode=all">models</a>, and
999 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AView%3A%3A&mode=all">views</a>;
1000 they can save you a lot of work.</p>
1001 <pre><code>script/${prefix}_create.pl -help</code></pre>
1002 <p>Also, be sure to check out the vast and growing
1003 collection of <a href="http://search.cpan.org/search?query=Catalyst">plugins for Catalyst on CPAN</a>;
1004 you are likely to find what you need there.
1008 <p>Catalyst has a very active community. Here are the main places to
1009 get in touch with us.</p>
1012 <a href="http://dev.catalyst.perl.org">Wiki</a>
1015 <a href="http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst">Mailing-List</a>
1018 <a href="irc://irc.perl.org/catalyst">IRC channel #catalyst on irc.perl.org</a>
1021 <h2>In conclusion</h2>
1022 <p>The Catalyst team hopes you will enjoy using Catalyst as much
1023 as we enjoyed making it. Please contact us if you have ideas
1024 for improvement or other feedback.</p>
1032 =head1 INTERNAL METHODS
1034 These methods are not meant to be used by end users.
1036 =head2 $c->components
1038 Returns a hash of components.
1040 =head2 $c->context_class
1042 Returns or sets the context class.
1044 =head2 $c->dispatcher_class
1046 Returns or sets the dispatcher class.
1048 =head2 $c->engine_class
1050 Returns or sets the engine class.
1052 =head2 $c->handle_request( $class, @arguments )
1054 Called to handle each HTTP request.
1058 sub handle_request {
1059 my ( $class, @arguments ) = @_;
1061 # Always expect worst case!
1064 if ($class->debug) {
1065 my $secs = time - $START || 1;
1066 my $av = sprintf '%.3f', $COUNT / $secs;
1067 my $time = localtime time;
1068 $class->log->info("*** Request $COUNT ($av/s) [$$] [$time] ***");
1071 my $c = $class->prepare(@arguments);
1073 $status = $c->finalize;
1076 if ( my $error = $@ ) {
1078 $class->log->error(qq/Caught exception in engine "$error"/);
1083 if(my $coderef = $class->log->can('_flush')){
1084 $class->log->$coderef();
1089 =head2 $c->prepare( @arguments )
1091 Creates a Catalyst context from an engine-specific request (Apache, CGI,
1097 my ( $class, @arguments ) = @_;
1100 # After the app/ctxt split, this should become an attribute based on something passed
1101 # into the application.
1102 $class->context_class( ref $class || $class ) unless $class->context_class;
1104 my $app = $class->new({});
1105 my $c = $class->context_class->new( application => $app );
1107 # For on-demand data
1108 $c->request->_context($c);
1109 $c->response->_context($c);
1111 #surely this is not the most efficient way to do things...
1112 $c->stats($class->stats_class->new)->enable($c->use_stats);
1114 $c->res->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
1117 #XXX reuse coderef from can
1118 # Allow engine to direct the prepare flow (for POE)
1119 if ( $c->engine->can('prepare') ) {
1120 $c->engine->prepare( $c, @arguments );
1123 $c->prepare_request(@arguments);
1124 $c->prepare_connection;
1125 $c->prepare_query_parameters;
1126 $c->prepare_headers;
1127 $c->prepare_cookies;
1130 # Prepare the body for reading, either by prepare_body
1131 # or the user, if they are using $c->read
1134 # Parse the body unless the user wants it on-demand
1135 unless ( $app->config->{parse_on_demand} ) {
1140 my $method = $c->req->method || '';
1141 my $path = $c->req->path;
1142 $path = '/' unless length $path;
1143 my $address = $c->req->address || '';
1145 $c->log->debug(qq/"$method" request for "$path" from "$address"/)
1153 =head2 $c->request_class
1155 Returns or sets the request class.
1157 =head2 $c->response_class
1159 Returns or sets the response class.
1167 sub run { my $c = shift; return $c->engine->run( $c, @_ ) }
1169 =head2 $c->set_action( $action, $code, $namespace, $attrs )
1171 Sets an action in a given namespace.
1175 sub set_action { my $c = shift; $c->dispatcher->set_action( $c, @_ ) }
1177 =head2 $c->setup_actions($component)
1179 Sets up actions for a component.
1183 sub setup_actions { my $c = shift; $c->dispatcher->setup_actions( $c, @_ ) }
1185 =head2 $c->setup_components
1187 This method is called internally to set up the application's components.
1189 It finds modules by calling the L<locate_components> method, expands them to
1190 package names with the L<expand_component_module> method, and then installs
1191 each component into the application.
1193 The C<setup_components> config option is passed to both of the above methods.
1195 Installation of each component is performed by the L<setup_component> method,
1200 sub setup_components {
1203 my $config = $class->config->{ setup_components };
1205 my @comps = sort { length $a <=> length $b }
1206 $class->locate_components($config);
1207 my %comps = map { $_ => 1 } @comps;
1209 my $deprecatedcatalyst_component_names = grep { /::[CMV]::/ } @comps;
1210 $class->log->warn(qq{Your application is using the deprecated ::[MVC]:: type naming scheme.\n}.
1211 qq{Please switch your class names to ::Model::, ::View:: and ::Controller: as appropriate.\n}
1212 ) if $deprecatedcatalyst_component_names;
1214 for my $component ( @comps ) {
1216 # We pass ignore_loaded here so that overlay files for (e.g.)
1217 # Model::DBI::Schema sub-classes are loaded - if it's in @comps
1218 # we know M::P::O found a file on disk so this is safe
1220 Catalyst::Utils::ensure_class_loaded( $component, { ignore_loaded => 1 } );
1222 # Needs to be done as soon as the component is loaded, as loading a sub-component
1223 # (next time round the loop) can cause us to get the wrong metaclass..
1224 $class->_controller_init_base_classes($component);
1227 for my $component (@comps) {
1228 $class->components->{ $component } = $class->setup_component($component);
1229 for my $component ($class->expand_component_module( $component, $config )) {
1230 next if $comps{$component};
1231 $class->_controller_init_base_classes($component); # Also cover inner packages
1232 $class->components->{ $component } = $class->setup_component($component);
1237 =head2 $c->locate_components( $setup_component_config )
1239 This method is meant to provide a list of component modules that should be
1240 setup for the application. By default, it will use L<Module::Pluggable>.
1242 Specify a C<setup_components> config option to pass additional options directly
1243 to L<Module::Pluggable>. To add additional search paths, specify a key named
1244 C<search_extra> as an array reference. Items in the array beginning with C<::>
1245 will have the application class name prepended to them.
1249 sub locate_components {
1253 my @paths = qw( ::Controller ::C ::Model ::M ::View ::V );
1254 my $extra = delete $config->{ search_extra } || [];
1256 push @paths, @$extra;
1258 my $locator = Module::Pluggable::Object->new(
1259 search_path => [ map { s/^(?=::)/$class/; $_; } @paths ],
1263 my @comps = $locator->plugins;
1268 =head2 $c->expand_component_module( $component, $setup_component_config )
1270 Components found by C<locate_components> will be passed to this method, which
1271 is expected to return a list of component (package) names to be set up.
1275 sub expand_component_module {
1276 my ($class, $module) = @_;
1277 return Devel::InnerPackage::list_packages( $module );
1280 =head2 $c->setup_component
1284 # FIXME - Ugly, ugly hack to ensure the we force initialize non-moose base classes
1285 # nearest to Catalyst::Controller first, no matter what order stuff happens
1286 # to be loaded. There are TODO tests in Moose for this, see
1287 # f2391d17574eff81d911b97be15ea51080500003
1288 sub _controller_init_base_classes {
1289 my ($app_class, $component) = @_;
1290 return unless $component->isa('Catalyst::Controller');
1291 foreach my $class ( reverse @{ mro::get_linear_isa($component) } ) {
1292 Moose::Meta::Class->initialize( $class )
1293 unless find_meta($class);
1297 sub setup_component {
1298 my( $class, $component ) = @_;
1300 unless ( $component->can( 'COMPONENT' ) ) {
1304 my $suffix = Catalyst::Utils::class2classsuffix( $component );
1305 my $config = $class->config->{ $suffix } || {};
1306 # Stash catalyst_component_name in the config here, so that custom COMPONENT
1307 # methods also pass it. local to avoid pointlessly shitting in config
1308 # for the debug screen, as $component is already the key name.
1309 local $config->{catalyst_component_name} = $component;
1311 my $instance = eval { $component->COMPONENT( $class, $config ); };
1313 if ( my $error = $@ ) {
1315 Catalyst::Exception->throw(
1316 message => qq/Couldn't instantiate component "$component", "$error"/
1320 unless (blessed $instance) {
1321 my $metaclass = Moose::Util::find_meta($component);
1322 my $method_meta = $metaclass->find_method_by_name('COMPONENT');
1323 my $component_method_from = $method_meta->associated_metaclass->name;
1324 my $value = defined($instance) ? $instance : 'undef';
1325 Catalyst::Exception->throw(
1327 qq/Couldn't instantiate component "$component", COMPONENT() method (from $component_method_from) didn't return an object-like value (value was $value)./
1333 =head2 $c->setup_dispatcher
1339 sub setup_dispatcher {
1340 my ( $class, $dispatcher ) = @_;
1343 $dispatcher = 'Catalyst::Dispatcher::' . $dispatcher;
1346 if ( my $env = Catalyst::Utils::env_value( $class, 'DISPATCHER' ) ) {
1347 $dispatcher = 'Catalyst::Dispatcher::' . $env;
1350 unless ($dispatcher) {
1351 $dispatcher = $class->dispatcher_class;
1354 Class::MOP::load_class($dispatcher);
1356 # dispatcher instance
1357 $class->dispatcher( $dispatcher->new );
1360 =head2 $c->setup_engine
1367 my ( $class, $engine ) = @_;
1370 $engine = 'Catalyst::Engine::' . $engine;
1373 if ( my $env = Catalyst::Utils::env_value( $class, 'ENGINE' ) ) {
1374 $engine = 'Catalyst::Engine::' . $env;
1377 if ( $ENV{MOD_PERL} ) {
1378 my $meta = Class::MOP::get_metaclass_by_name($class);
1380 # create the apache method
1381 $meta->add_method('apache' => sub { shift->engine->apache });
1383 my ( $software, $version ) =
1384 $ENV{MOD_PERL} =~ /^(\S+)\/(\d+(?:[\.\_]\d+)+)/;
1387 $version =~ s/(\.[^.]+)\./$1/g;
1389 if ( $software eq 'mod_perl' ) {
1393 if ( $version >= 1.99922 ) {
1394 $engine = 'Catalyst::Engine::Apache2::MP20';
1397 elsif ( $version >= 1.9901 ) {
1398 $engine = 'Catalyst::Engine::Apache2::MP19';
1401 elsif ( $version >= 1.24 ) {
1402 $engine = 'Catalyst::Engine::Apache::MP13';
1406 Catalyst::Exception->throw( message =>
1407 qq/Unsupported mod_perl version: $ENV{MOD_PERL}/ );
1412 # install the correct mod_perl handler
1413 if ( $version >= 1.9901 ) {
1414 *handler = sub : method {
1415 shift->handle_request(@_);
1419 *handler = sub ($$) { shift->handle_request(@_) };
1424 elsif ( $software eq 'Zeus-Perl' ) {
1425 $engine = 'Catalyst::Engine::Zeus';
1429 Catalyst::Exception->throw(
1430 message => qq/Unsupported mod_perl: $ENV{MOD_PERL}/ );
1435 $engine = $class->engine_class;
1438 Class::MOP::load_class($engine);
1440 # check for old engines that are no longer compatible
1442 if ( $engine->isa('Catalyst::Engine::Apache')
1443 && !Catalyst::Engine::Apache->VERSION )
1448 elsif ( $engine->isa('Catalyst::Engine::Server::Base')
1449 && Catalyst::Engine::Server->VERSION le '0.02' )
1454 elsif ($engine->isa('Catalyst::Engine::HTTP::POE')
1455 && $engine->VERSION eq '0.01' )
1460 elsif ($engine->isa('Catalyst::Engine::Zeus')
1461 && $engine->VERSION eq '0.01' )
1467 Catalyst::Exception->throw( message =>
1468 qq/Engine "$engine" is not supported by this version of Catalyst/
1473 $class->engine( $engine->new );
1476 =head2 $c->setup_home
1478 Sets up the home directory.
1483 my ( $class, $home ) = @_;
1485 if ( my $env = Catalyst::Utils::env_value( $class, 'HOME' ) ) {
1489 $home ||= Catalyst::Utils::home($class);
1492 #I remember recently being scolded for assigning config values like this
1493 $class->config->{home} ||= $home;
1494 $class->config->{root} ||= Path::Class::Dir->new($home)->subdir('root');
1498 =head2 $c->setup_log
1500 Sets up log by instantiating a L<Catalyst::Log|Catalyst::Log> object and
1501 passing it to C<log()>. Pass in a comma-delimited list of levels to set the
1504 This method also installs a C<debug> method that returns a true value into the
1505 catalyst subclass if the "debug" level is passed in the comma-delimited list,
1506 or if the C<$CATALYST_DEBUG> environment variable is set to a true value.
1508 Note that if the log has already been setup, by either a previous call to
1509 C<setup_log> or by a call such as C<< __PACKAGE__->log( MyLogger->new ) >>,
1510 that this method won't actually set up the log object.
1515 my ( $class, $levels ) = @_;
1518 $levels =~ s/^\s+//;
1519 $levels =~ s/\s+$//;
1520 my %levels = map { $_ => 1 } split /\s*,\s*/, $levels;
1522 my $env_debug = Catalyst::Utils::env_value( $class, 'DEBUG' );
1523 if ( defined $env_debug ) {
1524 $levels{debug} = 1 if $env_debug; # Ugly!
1525 delete($levels{debug}) unless $env_debug;
1528 unless ( $class->log ) {
1529 $class->log( Catalyst::Log->new(keys %levels) );
1532 if ( $levels{debug} ) {
1533 Class::MOP::get_metaclass_by_name($class)->add_method('debug' => sub { 1 });
1534 $class->log->debug('Debug messages enabled');
1538 =head2 $c->setup_plugins
1544 =head2 $c->setup_stats
1546 Sets up timing statistics class.
1551 my ( $class, $stats ) = @_;
1553 Catalyst::Utils::ensure_class_loaded($class->stats_class);
1555 my $env = Catalyst::Utils::env_value( $class, 'STATS' );
1556 if ( defined($env) ? $env : ($stats || $class->debug ) ) {
1557 Class::MOP::get_metaclass_by_name($class)->add_method('use_stats' => sub { 1 });
1558 $class->log->debug('Statistics enabled');
1563 =head2 $c->registered_plugins
1565 Returns a sorted list of the plugins which have either been stated in the
1566 import list or which have been added via C<< MyApp->plugin(@args); >>.
1568 If passed a given plugin name, it will report a boolean value indicating
1569 whether or not that plugin is loaded. A fully qualified name is required if
1570 the plugin name does not begin with C<Catalyst::Plugin::>.
1572 if ($c->registered_plugins('Some::Plugin')) {
1580 sub registered_plugins {
1582 return sort keys %{ $proto->_plugins } unless @_;
1584 return 1 if exists $proto->_plugins->{$plugin};
1585 return exists $proto->_plugins->{"Catalyst::Plugin::$plugin"};
1588 sub _register_plugin {
1589 my ( $proto, $plugin, $instant ) = @_;
1590 my $class = ref $proto || $proto;
1592 Class::MOP::load_class( $plugin );
1594 $proto->_plugins->{$plugin} = 1;
1597 if ( my $meta = Class::MOP::get_metaclass_by_name($class) ) {
1598 my @superclasses = ($plugin, $meta->superclasses );
1599 $meta->superclasses(@superclasses);
1601 unshift @{"$class\::ISA"}, $plugin;
1608 my ( $class, $plugins ) = @_;
1610 $class->_plugins( {} ) unless $class->_plugins;
1613 my @plugins = Catalyst::Utils::resolve_namespace($class . '::Plugin', 'Catalyst::Plugin', @$plugins);
1615 for my $plugin ( reverse @plugins ) {
1616 Class::MOP::load_class($plugin);
1617 my $meta = find_meta($plugin);
1618 next if $meta && $meta->isa('Moose::Meta::Role');
1620 $class->_register_plugin($plugin);
1625 grep { $_ && blessed($_) && $_->isa('Moose::Meta::Role') }
1626 map { find_meta($_) }
1629 Moose::Util::apply_all_roles(
1635 =head2 $c->stats_class
1637 Returns or sets the stats (timing statistics) class.
1639 =head2 $c->use_stats
1641 Returns 1 when stats collection is enabled. Stats collection is enabled
1642 when the -Stats options is set, debug is on or when the <MYAPP>_STATS
1643 environment variable is set.
1645 Note that this is a static method, not an accessor and should be overridden
1646 by declaring C<sub use_stats { 1 }> in your MyApp.pm, not by calling C<< $c->use_stats(1) >>.
1654 Returns the Catalyst version number. Mostly useful for "powered by"
1655 messages in template systems.
1659 sub version { return $Catalyst::VERSION }
1661 =head1 CONFIGURATION
1663 There are a number of 'base' config variables which can be set:
1669 C<default_model> - The default model picked if you say C<< $c->model >>. See L</$c->model($name)>.
1673 C<default_view> - The default view to be rendered or returned when C<< $c->view >>. See L</$c->view($name)>.
1678 C<disable_component_resolution_regex_fallback> - Turns
1679 off the deprecated component resolution functionality so
1680 that if any of the component methods (e.g. C<< $c->controller('Foo') >>)
1681 are called then regex search will not be attempted on string values and
1682 instead C<undef> will be returned.
1686 C<home> - The application home directory. In an uninstalled application,
1687 this is the top level application directory. In an installed application,
1688 this will be the directory containing C<< MyApp.pm >>.
1692 C<ignore_frontend_proxy> - See L</PROXY SUPPORT>
1696 C<name> - The name of the application in debug messages and the debug and
1701 C<parse_on_demand> - The request body (for example file uploads) will not be parsed
1702 until it is accessed. This allows you to (for example) check authentication (and reject
1703 the upload) before actually recieving all the data. See L</ON-DEMAND PARSER>
1707 C<root> - The root directory for templates. Usually this is just a
1708 subdirectory of the home directory, but you can set it to change the
1709 templates to a different directory.
1713 C<search_extra> - Array reference passed to Module::Pluggable to for additional
1714 namespaces from which components will be loaded (and constructed and stored in
1715 C<< $c->components >>).
1719 C<show_internal_actions> - If true, causes internal actions such as C<< _DISPATCH >>
1720 to be shown in hit debug tables in the test server.
1724 C<using_frontend_proxy> - See L</PROXY SUPPORT>.
1728 =head1 INTERNAL ACTIONS
1730 Catalyst uses internal actions like C<_DISPATCH>, C<_BEGIN>, C<_AUTO>,
1731 C<_ACTION>, and C<_END>. These are by default not shown in the private
1732 action table, but you can make them visible with a config parameter.
1734 MyApp->config(show_internal_actions => 1);
1736 =head1 ON-DEMAND PARSER
1738 The request body is usually parsed at the beginning of a request,
1739 but if you want to handle input yourself, you can enable on-demand
1740 parsing with a config parameter.
1742 MyApp->config(parse_on_demand => 1);
1744 =head1 PROXY SUPPORT
1746 Many production servers operate using the common double-server approach,
1747 with a lightweight frontend web server passing requests to a larger
1748 backend server. An application running on the backend server must deal
1749 with two problems: the remote user always appears to be C<127.0.0.1> and
1750 the server's hostname will appear to be C<localhost> regardless of the
1751 virtual host that the user connected through.
1753 Catalyst will automatically detect this situation when you are running
1754 the frontend and backend servers on the same machine. The following
1755 changes are made to the request.
1757 $c->req->address is set to the user's real IP address, as read from
1758 the HTTP X-Forwarded-For header.
1760 The host value for $c->req->base and $c->req->uri is set to the real
1761 host, as read from the HTTP X-Forwarded-Host header.
1763 Additionally, you may be running your backend application on an insecure
1764 connection (port 80) while your frontend proxy is running under SSL. If there
1765 is a discrepancy in the ports, use the HTTP header C<X-Forwarded-Port> to
1766 tell Catalyst what port the frontend listens on. This will allow all URIs to
1767 be created properly.
1769 In the case of passing in:
1771 X-Forwarded-Port: 443
1773 All calls to C<uri_for> will result in an https link, as is expected.
1775 Obviously, your web server must support these headers for this to work.
1777 In a more complex server farm environment where you may have your
1778 frontend proxy server(s) on different machines, you will need to set a
1779 configuration option to tell Catalyst to read the proxied data from the
1782 MyApp->config(using_frontend_proxy => 1);
1784 If you do not wish to use the proxy support at all, you may set:
1786 MyApp->config(ignore_frontend_proxy => 1);
1788 =head1 THREAD SAFETY
1790 Catalyst has been tested under Apache 2's threading C<mpm_worker>,
1791 C<mpm_winnt>, and the standalone forking HTTP server on Windows. We
1792 believe the Catalyst core to be thread-safe.
1794 If you plan to operate in a threaded environment, remember that all other
1795 modules you are using must also be thread-safe. Some modules, most notably
1796 L<DBD::SQLite>, are not thread-safe.
1802 Join #catalyst on irc.perl.org.
1806 http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
1807 http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst-dev
1811 http://catalyst.perl.org
1815 http://dev.catalyst.perl.org
1819 =head2 L<Task::Catalyst> - All you need to start with Catalyst
1821 =head2 L<Catalyst::Manual> - The Catalyst Manual
1823 =head2 L<Catalyst::Component>, L<Catalyst::Controller> - Base classes for components
1825 =head2 L<Catalyst::Engine> - Core engine
1827 =head2 L<Catalyst::Log> - Log class.
1829 =head2 L<Catalyst::Request> - Request object
1831 =head2 L<Catalyst::Response> - Response object
1833 =head2 L<Catalyst::Test> - The test suite.
1835 =head1 PROJECT FOUNDER
1837 sri: Sebastian Riedel <sri@cpan.org>
1843 acme: Leon Brocard <leon@astray.com>
1845 abraxxa: Alexander Hartmaier <abraxxa@cpan.org>
1849 Andrew Ford E<lt>A.Ford@ford-mason.co.ukE<gt>
1853 andyg: Andy Grundman <andy@hybridized.org>
1855 audreyt: Audrey Tang
1857 bricas: Brian Cassidy <bricas@cpan.org>
1859 Caelum: Rafael Kitover <rkitover@io.com>
1861 chansen: Christian Hansen
1863 chicks: Christopher Hicks
1865 Chisel Wright C<pause@herlpacker.co.uk>
1867 Danijel Milicevic C<me@danijel.de>
1869 David Kamholz E<lt>dkamholz@cpan.orgE<gt>
1871 David Naughton, C<naughton@umn.edu>
1875 dkubb: Dan Kubb <dan.kubb-cpan@onautopilot.com>
1879 dwc: Daniel Westermann-Clark <danieltwc@cpan.org>
1881 esskar: Sascha Kiefer
1883 fireartist: Carl Franks <cfranks@cpan.org>
1885 frew: Arthur Axel "fREW" Schmidt <frioux@gmail.com>
1887 gabb: Danijel Milicevic
1891 Gavin Henry C<ghenry@perl.me.uk>
1895 groditi: Guillermo Roditi <groditi@gmail.com>
1897 hobbs: Andrew Rodland <andrew@cleverdomain.org>
1899 ilmari: Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>
1901 jcamacho: Juan Camacho
1903 jester: Jesse Sheidlower C<jester@panix.com>
1905 jhannah: Jay Hannah <jay@jays.net>
1911 jon: Jon Schutz <jjschutz@cpan.org>
1913 Jonathan Rockway C<< <jrockway@cpan.org> >>
1915 Kieren Diment C<kd@totaldatasolution.com>
1917 konobi: Scott McWhirter <konobi@cpan.org>
1919 marcus: Marcus Ramberg <mramberg@cpan.org>
1921 miyagawa: Tatsuhiko Miyagawa <miyagawa@bulknews.net>
1923 mst: Matt S. Trout <mst@shadowcatsystems.co.uk>
1927 naughton: David Naughton
1929 ningu: David Kamholz <dkamholz@cpan.org>
1931 nothingmuch: Yuval Kogman <nothingmuch@woobling.org>
1933 numa: Dan Sully <daniel@cpan.org>
1937 omega: Andreas Marienborg
1939 Oleg Kostyuk <cub.uanic@gmail.com>
1941 phaylon: Robert Sedlacek <phaylon@dunkelheit.at>
1943 rafl: Florian Ragwitz <rafl@debian.org>
1945 random: Roland Lammel <lammel@cpan.org>
1947 Robert Sedlacek C<< <rs@474.at> >>
1951 t0m: Tomas Doran <bobtfish@bobtfish.net>
1955 Viljo Marrandi C<vilts@yahoo.com>
1957 Will Hawes C<info@whawes.co.uk>
1959 willert: Sebastian Willert <willert@cpan.org>
1961 Yuval Kogman, C<nothingmuch@woobling.org>
1965 This library is free software. You can redistribute it and/or modify it under
1966 the same terms as Perl itself.
1972 __PACKAGE__->meta->make_immutable;