4 use Moose::Meta::Class ();
5 extends 'Catalyst::Component';
7 MooseX::Emulate::Class::Accessor::Fast
11 use Moose::Util qw/find_meta/;
12 use B::Hooks::EndOfScope ();
13 use Catalyst::Exception;
16 use Catalyst::Controller;
17 use Catalyst::Context;
18 use Catalyst::Exception::Detach;
19 use Catalyst::Exception::Go;
20 use Devel::InnerPackage ();
21 use Module::Pluggable::Object ();
22 use Text::SimpleTable ();
23 use Path::Class::Dir ();
24 use Path::Class::File ();
25 use Tree::Simple::Visitor::FindByUID;
26 use Class::C3::Adopt::NEXT;
29 use Carp qw/croak carp shortmess/;
31 BEGIN { require 5.008004; }
33 sub comp { shift->component(@_) }
35 #I imagine that very few of these really need to be class variables. if any.
36 #maybe we should just make them attributes with a default?
37 __PACKAGE__->mk_classdata($_)
38 for qw/components arguments dispatcher engine log dispatcher_class
39 engine_class context_class request_class response_class stats_class
42 __PACKAGE__->context_class('Catalyst::Context');
43 __PACKAGE__->dispatcher_class('Catalyst::Dispatcher');
44 __PACKAGE__->engine_class('Catalyst::Engine::CGI');
45 __PACKAGE__->request_class('Catalyst::Request');
46 __PACKAGE__->response_class('Catalyst::Response');
47 __PACKAGE__->stats_class('Catalyst::Stats');
49 # Remember to update this in Catalyst::Runtime as well!
51 our $VERSION = '5.80013';
54 my $dev_version = $VERSION =~ /_\d{2}$/;
55 *_IS_DEVELOPMENT_VERSION = sub () { $dev_version };
58 $VERSION = eval $VERSION;
62 our $DETACH = Catalyst::Exception::Detach->new;
63 our $GO = Catalyst::Exception::Go->new;
66 my ( $class, @arguments ) = @_;
68 # We have to limit $class to Catalyst to avoid pushing Catalyst upon every
70 return unless $class eq 'Catalyst';
72 my $caller = caller();
73 return if $caller eq 'main';
75 # Kill Adopt::NEXT warnings if we're a non-RC version
76 unless (_IS_DEVELOPMENT_VERSION()) {
77 Class::C3::Adopt::NEXT->unimport(qr/^Catalyst::/);
80 my $meta = Moose::Meta::Class->initialize($caller);
81 # Make the caller inherit from Catalyst
82 unless ( $caller->isa('Catalyst') ) {
83 $meta->superclasses($meta->superclasses, 'Catalyst');
85 # Avoid possible C3 issues if 'Moose::Object' is already on RHS of MyApp
86 $meta->superclasses(grep { $_ ne 'Moose::Object' } $meta->superclasses);
88 unless( $meta->has_method('meta') ){
89 $meta->add_method(meta => sub { Moose::Meta::Class->initialize("${caller}") } );
92 $caller->arguments( [@arguments] );
96 sub _application { $_[0] }
100 Catalyst - The Elegant MVC Web Application Framework
104 See the L<Catalyst::Manual> distribution for comprehensive
105 documentation and tutorials.
107 # Install Catalyst::Devel for helpers and other development tools
108 # use the helper to create a new application
111 # add models, views, controllers
112 script/myapp_create.pl model MyDatabase DBIC::Schema create=static dbi:SQLite:/path/to/db
113 script/myapp_create.pl view MyTemplate TT
114 script/myapp_create.pl controller Search
116 # built in testserver -- use -r to restart automatically on changes
117 # --help to see all available options
118 script/myapp_server.pl
120 # command line testing interface
121 script/myapp_test.pl /yada
124 use Catalyst qw/-Debug/; # include plugins here as well
126 ### In lib/MyApp/Controller/Root.pm (autocreated)
127 sub foo : Global { # called for /foo, /foo/1, /foo/1/2, etc.
128 my ( $self, $c, @args ) = @_; # args are qw/1 2/ for /foo/1/2
129 $c->stash->{template} = 'foo.tt'; # set the template
130 # lookup something from db -- stash vars are passed to TT
132 $c->model('Database::Foo')->search( { country => $args[0] } );
133 if ( $c->req->params->{bar} ) { # access GET or POST parameters
134 $c->forward( 'bar' ); # process another action
135 # do something else after forward returns
139 # The foo.tt TT template can use the stash data from the database
140 [% WHILE (item = data.next) %]
144 # called for /bar/of/soap, /bar/of/soap/10, etc.
145 sub bar : Path('/bar/of/soap') { ... }
147 # called for all actions, from the top-most controller downwards
149 my ( $self, $c ) = @_;
150 if ( !$c->user_exists ) { # Catalyst::Plugin::Authentication
151 $c->res->redirect( '/login' ); # require login
152 return 0; # abort request and go immediately to end()
154 return 1; # success; carry on to next action
157 # called after all actions are finished
159 my ( $self, $c ) = @_;
160 if ( scalar @{ $c->error } ) { ... } # handle errors
161 return if $c->res->body; # already have a response
162 $c->forward( 'MyApp::View::TT' ); # render template
165 ### in MyApp/Controller/Foo.pm
166 # called for /foo/bar
167 sub bar : Local { ... }
169 # called for /blargle
170 sub blargle : Global { ... }
172 # an index action matches /foo, but not /foo/1, etc.
173 sub index : Private { ... }
175 ### in MyApp/Controller/Foo/Bar.pm
176 # called for /foo/bar/baz
177 sub baz : Local { ... }
179 # first Root auto is called, then Foo auto, then this
180 sub auto : Private { ... }
182 # powerful regular expression paths are also possible
183 sub details : Regex('^product/(\w+)/details$') {
184 my ( $self, $c ) = @_;
185 # extract the (\w+) from the URI
186 my $product = $c->req->captures->[0];
189 See L<Catalyst::Manual::Intro> for additional information.
193 Catalyst is a modern framework for making web applications without the
194 pain usually associated with this process. This document is a reference
195 to the main Catalyst application. If you are a new user, we suggest you
196 start with L<Catalyst::Manual::Tutorial> or L<Catalyst::Manual::Intro>.
198 See L<Catalyst::Manual> for more documentation.
200 Catalyst plugins can be loaded by naming them as arguments to the "use
201 Catalyst" statement. Omit the C<Catalyst::Plugin::> prefix from the
202 plugin name, i.e., C<Catalyst::Plugin::My::Module> becomes
205 use Catalyst qw/My::Module/;
207 If your plugin starts with a name other than C<Catalyst::Plugin::>, you can
208 fully qualify the name by using a unary plus:
212 +Fully::Qualified::Plugin::Name
215 Special flags like C<-Debug> and C<-Engine> can also be specified as
216 arguments when Catalyst is loaded:
218 use Catalyst qw/-Debug My::Module/;
220 The position of plugins and flags in the chain is important, because
221 they are loaded in the order in which they appear.
223 The following flags are supported:
227 Enables debug output. You can also force this setting from the system
228 environment with CATALYST_DEBUG or <MYAPP>_DEBUG. The environment
229 settings override the application, with <MYAPP>_DEBUG having the highest
234 Forces Catalyst to use a specific engine. Omit the
235 C<Catalyst::Engine::> prefix of the engine name, i.e.:
237 use Catalyst qw/-Engine=CGI/;
241 Forces Catalyst to use a specific home directory, e.g.:
243 use Catalyst qw[-Home=/usr/mst];
245 This can also be done in the shell environment by setting either the
246 C<CATALYST_HOME> environment variable or C<MYAPP_HOME>; where C<MYAPP>
247 is replaced with the uppercased name of your application, any "::" in
248 the name will be replaced with underscores, e.g. MyApp::Web should use
249 MYAPP_WEB_HOME. If both variables are set, the MYAPP_HOME one will be used.
253 use Catalyst '-Log=warn,fatal,error';
255 Specifies a comma-delimited list of log levels.
259 Enables statistics collection and reporting. You can also force this setting
260 from the system environment with CATALYST_STATS or <MYAPP>_STATS. The
261 environment settings override the application, with <MYAPP>_STATS having the
266 use Catalyst qw/-Stats=1/
272 =head2 $c->controller($name)
274 Gets a L<Catalyst::Controller> instance by name.
276 $c->controller('Foo')->do_stuff;
278 If the name is omitted, will return the controller for the dispatched
281 If you want to search for controllers, pass in a regexp as the argument.
283 # find all controllers that start with Foo
284 my @foo_controllers = $c->controller(qr{^Foo});
290 my ( $c, $name, @args ) = @_;
293 my @result = $c->_comp_search_prefixes( $name, qw/Controller C/ );
294 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
295 return $c->_filter_component( $result[ 0 ], @args );
298 return $c->component( $c->action->class );
301 =head2 $c->view($name)
303 Gets a L<Catalyst::View> instance by name.
308 my ( $c, $name, @args ) = @_;
311 my @result = $c->_comp_search_prefixes( $name, qw/View V/ );
312 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
313 return $c->_filter_component( $result[ 0 ], @args );
316 return $c->view( $c->config->{default_view} )
317 if $c->config->{default_view};
318 my( $comp, $rest ) = $c->_comp_search_prefixes( undef, qw/View V/);
321 $c->log->warn( 'Calling $c->view() will return a random view unless you specify one of:' );
322 $c->log->warn( '* $c->config(default_view => "the name of the default view to use")' );
323 $c->log->warn( '* $c->stash->{current_view} # the name of the view to use for this request' );
324 $c->log->warn( '* $c->stash->{current_view_instance} # the instance of the view to use for this request' );
325 $c->log->warn( 'NB: in version 5.81, the "random" behavior will not work at all.' );
328 return $c->_filter_component( $comp );
331 =head2 $c->model($name)
333 Gets a L<Catalyst::Model> instance by name.
338 my ( $c, $name, @args ) = @_;
340 my @result = $c->_comp_search_prefixes( $name, qw/Model M/ );
341 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
342 return $c->_filter_component( $result[ 0 ], @args );
345 return $c->model( $c->config->{default_model} )
346 if $c->config->{default_model};
348 my( $comp, $rest ) = $c->_comp_search_prefixes( undef, qw/Model M/);
351 $c->log->warn( Carp::shortmess('Calling $c->model() will return a random model unless you specify one of:') );
352 $c->log->warn( '* $c->config(default_model => "the name of the default model to use")' );
353 $c->log->warn( '* $c->stash->{current_model} # the name of the model to use for this request' );
354 $c->log->warn( '* $c->stash->{current_model_instance} # the instance of the model to use for this request' );
355 $c->log->warn( 'NB: in version 5.81, the "random" behavior will not work at all.' );
358 return $c->_filter_component( $comp );
362 sub _comp_search_prefixes {
364 return map $c->components->{ $_ }, $c->_comp_names_search_prefixes(@_);
367 # search components given a name and some prefixes
368 sub _comp_names_search_prefixes {
369 my ( $c, $name, @prefixes ) = @_;
370 my $appclass = ref $c || $c;
371 my $filter = "^${appclass}::(" . join( '|', @prefixes ) . ')::';
372 $filter = qr/$filter/; # Compile regex now rather than once per loop
374 # map the original component name to the sub part that we will search against
375 my %eligible = map { my $n = $_; $n =~ s{^$appclass\::[^:]+::}{}; $_ => $n; }
376 grep { /$filter/ } keys %{ $c->components };
378 # undef for a name will return all
379 return keys %eligible if !defined $name;
381 my $query = ref $name ? $name : qr/^$name$/i;
382 my @result = grep { $eligible{$_} =~ m{$query} } keys %eligible;
384 return @result if @result;
386 # if we were given a regexp to search against, we're done.
389 # skip regexp fallback if configured
391 if $appclass->config->{disable_component_resolution_regex_fallback};
395 @result = grep { $eligible{ $_ } =~ m{$query} } keys %eligible;
397 # no results? try against full names
399 @result = grep { m{$query} } keys %eligible;
402 # don't warn if we didn't find any results, it just might not exist
404 # Disgusting hack to work out correct method name
405 my $warn_for = lc $prefixes[0];
406 my $msg = "Used regexp fallback for \$c->${warn_for}('${name}'), which found '" .
407 (join '", "', @result) . "'. Relying on regexp fallback behavior for " .
408 "component resolution is unreliable and unsafe.";
409 my $short = $result[0];
410 # remove the component namespace prefix
411 $short =~ s/.*?(Model|Controller|View):://;
412 my $shortmess = Carp::shortmess('');
413 if ($shortmess =~ m#Catalyst/Plugin#) {
414 $msg .= " You probably need to set '$short' instead of '${name}' in this " .
416 } elsif ($shortmess =~ m#Catalyst/lib/(View|Controller)#) {
417 $msg .= " You probably need to set '$short' instead of '${name}' in this " .
418 "component's config";
420 $msg .= " You probably meant \$c->${warn_for}('$short') instead of \$c->${warn_for}('${name}'), " .
421 "but if you really wanted to search, pass in a regexp as the argument " .
422 "like so: \$c->${warn_for}(qr/${name}/)";
424 $c->log->warn( "${msg}$shortmess" );
430 # Find possible names for a prefix
432 my ( $c, @prefixes ) = @_;
433 my $appclass = ref $c || $c;
435 my $filter = "^${appclass}::(" . join( '|', @prefixes ) . ')::';
437 my @names = map { s{$filter}{}; $_; }
438 $c->_comp_names_search_prefixes( undef, @prefixes );
443 # Filter a component before returning by calling ACCEPT_CONTEXT if available
444 sub _filter_component {
445 my ( $c, $comp, @args ) = @_;
447 if ( eval { $comp->can('ACCEPT_CONTEXT'); } ) {
448 return $comp->ACCEPT_CONTEXT( $c, @args );
454 =head2 COMPONENT ACCESSORS
456 =head2 $c->controllers
458 Returns the available names which can be passed to $c->controller
464 return $c->_comp_names(qw/Controller C/);
469 Returns the available names which can be passed to $c->model
475 return $c->_comp_names(qw/Model M/);
481 Returns the available names which can be passed to $c->view
487 return $c->_comp_names(qw/View V/);
490 =head2 $c->comp($name)
492 =head2 $c->component($name)
494 Gets a component object by name. This method is not recommended,
495 unless you want to get a specific component by full
496 class. C<< $c->controller >>, C<< $c->model >>, and C<< $c->view >>
497 should be used instead.
499 If C<$name> is a regexp, a list of components matched against the full
500 component name will be returned.
502 If Catalyst can't find a component by name, it will fallback to regex
503 matching by default. To disable this behaviour set
504 disable_component_resolution_regex_fallback to a true value.
506 __PACKAGE__->config( disable_component_resolution_regex_fallback => 1 );
511 my ( $c, $name, @args ) = @_;
514 my $comps = $c->components;
517 # is it the exact name?
518 return $c->_filter_component( $comps->{ $name }, @args )
519 if exists $comps->{ $name };
521 # perhaps we just omitted "MyApp"?
522 my $composed = ( ref $c || $c ) . "::${name}";
523 return $c->_filter_component( $comps->{ $composed }, @args )
524 if exists $comps->{ $composed };
526 # search all of the models, views and controllers
527 my( $comp ) = $c->_comp_search_prefixes( $name, qw/Model M Controller C View V/ );
528 return $c->_filter_component( $comp, @args ) if $comp;
531 return if $c->config->{disable_component_resolution_regex_fallback};
532 # This is here so $c->comp( '::M::' ) works
533 my $query = ref $name ? $name : qr{$name}i;
535 my @result = grep { m{$query} } keys %{ $c->components };
536 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
539 $c->log->warn( Carp::shortmess(qq(Found results for "${name}" using regexp fallback)) );
540 $c->log->warn( 'Relying on the regexp fallback behavior for component resolution' );
541 $c->log->warn( 'is unreliable and unsafe. You have been warned' );
542 return $c->_filter_component( $result[ 0 ], @args );
545 # I would expect to return an empty list here, but that breaks back-compat
549 return sort keys %{ $c->components };
552 =head2 CLASS DATA AND HELPER CLASSES
556 Returns or takes a hashref containing the application's configuration.
558 __PACKAGE__->config( { db => 'dsn:SQLite:foo.db' } );
560 You can also use a C<YAML>, C<XML> or L<Config::General> config file
561 like C<myapp.conf> in your applications home directory. See
562 L<Catalyst::Plugin::ConfigLoader>.
564 =head3 Cascading configuration
566 The config method is present on all Catalyst components, and configuration
567 will be merged when an application is started. Configuration loaded with
568 L<Catalyst::Plugin::ConfigLoader> takes precedence over other configuration,
569 followed by configuration in your top level C<MyApp> class. These two
570 configurations are merged, and then configuration data whose hash key matches a
571 component name is merged with configuration for that component.
573 The configuration for a component is then passed to the C<new> method when a
574 component is constructed.
578 MyApp->config({ 'Model::Foo' => { bar => 'baz', overrides => 'me' } });
579 MyApp::Model::Foo->config({ quux => 'frob', 'overrides => 'this' });
581 will mean that C<MyApp::Model::Foo> receives the following data when
584 MyApp::Model::Foo->new({
592 around config => sub {
596 croak('Setting config after setup has been run is not allowed.')
597 if ( @_ and $c->setup_finished );
604 Returns the logging object instance. Unless it is already set, Catalyst
605 sets this up with a L<Catalyst::Log> object. To use your own log class,
606 set the logger with the C<< __PACKAGE__->log >> method prior to calling
607 C<< __PACKAGE__->setup >>.
609 __PACKAGE__->log( MyLogger->new );
614 $c->log->info( 'Now logging with my own logger!' );
616 Your log class should implement the methods described in
622 Returns 1 if debug mode is enabled, 0 otherwise.
624 You can enable debug mode in several ways:
628 =item By calling myapp_server.pl with the -d flag
630 =item With the environment variables MYAPP_DEBUG, or CATALYST_DEBUG
632 =item The -Debug option in your MyApp.pm
634 =item By declaring C<sub debug { 1 }> in your MyApp.pm.
638 Calling C<< $c->debug(1) >> has no effect.
644 =head2 $c->dispatcher
646 Returns the dispatcher instance. See L<Catalyst::Dispatcher>.
650 Returns the engine instance. See L<Catalyst::Engine>.
653 =head2 UTILITY METHODS
655 =head2 $c->path_to(@path)
657 Merges C<@path> with C<< $c->config->{home} >> and returns a
658 L<Path::Class::Dir> object. Note you can usually use this object as
659 a filename, but sometimes you will have to explicitly stringify it
660 yourself by calling the C<< ->stringify >> method.
664 $c->path_to( 'db', 'sqlite.db' );
669 my ( $c, @path ) = @_;
670 my $path = Path::Class::Dir->new( $c->config->{home}, @path );
671 if ( -d $path ) { return $path }
672 else { return Path::Class::File->new( $c->config->{home}, @path ) }
675 =head2 $c->plugin( $name, $class, @args )
677 Helper method for plugins. It creates a class data accessor/mutator and
678 loads and instantiates the given class.
680 MyApp->plugin( 'prototype', 'HTML::Prototype' );
682 $c->prototype->define_javascript_functions;
684 B<Note:> This method of adding plugins is deprecated. The ability
685 to add plugins like this B<will be removed> in a Catalyst 5.81.
686 Please do not use this functionality in new code.
691 my ( $class, $name, $plugin, @args ) = @_;
693 # See block comment in t/unit_core_plugin.t
694 $class->log->warn(qq/Adding plugin using the ->plugin method is deprecated, and will be removed in Catalyst 5.81/);
696 $class->_register_plugin( $plugin, 1 );
698 eval { $plugin->import };
699 $class->mk_classdata($name);
701 eval { $obj = $plugin->new(@args) };
704 Catalyst::Exception->throw( message =>
705 qq/Couldn't instantiate instant plugin "$plugin", "$@"/ );
709 $class->log->debug(qq/Initialized instant plugin "$plugin" as "$name"/)
715 Initializes the dispatcher and engine, loads any plugins, and loads the
716 model, view, and controller components. You may also specify an array
717 of plugins to load here, if you choose to not load them in the C<use
721 MyApp->setup( qw/-Debug/ );
726 my ( $class, @arguments ) = @_;
727 croak('Running setup more than once')
728 if ( $class->setup_finished );
730 unless ( $class->isa('Catalyst') ) {
732 Catalyst::Exception->throw(
733 message => qq/'$class' does not inherit from Catalyst/ );
736 if ( $class->arguments ) {
737 @arguments = ( @arguments, @{ $class->arguments } );
743 foreach (@arguments) {
747 ( $flags->{log} ) ? 'debug,' . $flags->{log} : 'debug';
749 elsif (/^-(\w+)=?(.*)$/) {
750 $flags->{ lc $1 } = $2;
753 push @{ $flags->{plugins} }, $_;
757 $class->setup_home( delete $flags->{home} );
759 $class->setup_log( delete $flags->{log} );
760 $class->setup_plugins( delete $flags->{plugins} );
761 $class->setup_dispatcher( delete $flags->{dispatcher} );
762 $class->setup_engine( delete $flags->{engine} );
763 $class->setup_stats( delete $flags->{stats} );
765 for my $flag ( sort keys %{$flags} ) {
767 if ( my $code = $class->can( 'setup_' . $flag ) ) {
768 &$code( $class, delete $flags->{$flag} );
771 $class->log->warn(qq/Unknown flag "$flag"/);
775 eval { require Catalyst::Devel; };
776 if( !$@ && $ENV{CATALYST_SCRIPT_GEN} && ( $ENV{CATALYST_SCRIPT_GEN} < $Catalyst::Devel::CATALYST_SCRIPT_GEN ) ) {
777 $class->log->warn(<<"EOF");
778 You are running an old script!
780 Please update by running (this will overwrite existing files):
781 catalyst.pl -force -scripts $class
783 or (this will not overwrite existing files):
784 catalyst.pl -scripts $class
789 if ( $class->debug ) {
790 my @plugins = map { "$_ " . ( $_->VERSION || '' ) } $class->registered_plugins;
793 my $column_width = Catalyst::Utils::term_width() - 6;
794 my $t = Text::SimpleTable->new($column_width);
795 $t->row($_) for @plugins;
796 $class->log->debug( "Loaded plugins:\n" . $t->draw . "\n" );
799 my $dispatcher = $class->dispatcher;
800 my $engine = $class->engine;
801 my $home = $class->config->{home};
803 $class->log->debug(sprintf(q/Loaded dispatcher "%s"/, blessed($dispatcher)));
804 $class->log->debug(sprintf(q/Loaded engine "%s"/, blessed($engine)));
808 ? $class->log->debug(qq/Found home "$home"/)
809 : $class->log->debug(qq/Home "$home" doesn't exist/)
810 : $class->log->debug(q/Couldn't find home/);
813 # Call plugins setup, this is stupid and evil.
814 # Also screws C3 badly on 5.10, hack to avoid.
816 no warnings qw/redefine/;
817 local *setup = sub { };
818 $class->setup unless $Catalyst::__AM_RESTARTING;
821 # Initialize our data structure
822 $class->components( {} );
824 $class->setup_components;
826 if ( $class->debug ) {
827 my $column_width = Catalyst::Utils::term_width() - 8 - 9;
828 my $t = Text::SimpleTable->new( [ $column_width, 'Class' ], [ 8, 'Type' ] );
829 for my $comp ( sort keys %{ $class->components } ) {
830 my $type = ref $class->components->{$comp} ? 'instance' : 'class';
831 $t->row( $comp, $type );
833 $class->log->debug( "Loaded components:\n" . $t->draw . "\n" )
834 if ( keys %{ $class->components } );
837 $class->setup_actions;
839 if ( $class->debug ) {
840 my $name = $class->config->{name} || 'Application';
841 $class->log->info("$name powered by Catalyst $Catalyst::VERSION");
844 # Make sure that the application class becomes immutable at this point,
845 B::Hooks::EndOfScope::on_scope_end {
847 my $meta = Class::MOP::get_metaclass_by_name($class);
850 && ! { $meta->immutable_options }->{replace_constructor}
852 $class->isa('Class::Accessor::Fast')
853 || $class->isa('Class::Accessor')
856 warn "You made your application class ($class) immutable, "
857 . "but did not inline the\nconstructor. "
858 . "This will break catalyst, as your app \@ISA "
859 . "Class::Accessor(::Fast)?\nPlease pass "
860 . "(replace_constructor => 1)\nwhen making your class immutable.\n";
862 $meta->make_immutable(
863 replace_constructor => 1,
864 ) unless $meta->is_immutable;
867 $class->setup_finalize;
868 # Should be the last thing we do so that user things hooking
869 # setup_finalize can log..
870 $class->log->_flush() if $class->log->can('_flush');
871 return 1; # Explicit return true as people have __PACKAGE__->setup as the last thing in their class. HATE.
875 =head2 $app->setup_finalize
877 A hook to attach modifiers to.
878 Using C<< after setup => sub{}; >> doesn't work, because of quirky things done for plugin setup.
879 Also better than C< setup_finished(); >, as that is a getter method.
885 ## do stuff, i.e., determine a primary key column for sessions stored in a DB
887 $app->next::method(@_);
896 $class->setup_finished(1);
899 =head2 $c->welcome_message
901 Returns the Catalyst welcome HTML page.
905 sub welcome_message {
907 my $name = $c->config->{name};
908 my $logo = $c->uri_for('/static/images/catalyst_logo.png');
909 my $prefix = Catalyst::Utils::appprefix( ref $c );
910 $c->response->content_type('text/html; charset=utf-8');
912 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
913 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
914 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
916 <meta http-equiv="Content-Language" content="en" />
917 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
918 <title>$name on Catalyst $VERSION</title>
919 <style type="text/css">
922 background-color: #eee;
931 background-color: #ccc;
932 border: 1px solid #aaa;
937 font-family: verdana, tahoma, sans-serif;
940 font-family: verdana, tahoma, sans-serif;
943 text-decoration: none;
945 border-bottom: 1px dotted #bbb;
947 :link:hover, :visited:hover {
960 background-color: #fff;
961 border: 1px solid #aaa;
987 <h1><span id="appname">$name</span> on <a href="http://catalyst.perl.org">Catalyst</a>
992 <img src="$logo" alt="Catalyst Logo" />
994 <p>Welcome to the world of Catalyst.
995 This <a href="http://en.wikipedia.org/wiki/MVC">MVC</a>
996 framework will make web development something you had
997 never expected it to be: Fun, rewarding, and quick.</p>
998 <h2>What to do now?</h2>
999 <p>That really depends on what <b>you</b> want to do.
1000 We do, however, provide you with a few starting points.</p>
1001 <p>If you want to jump right into web development with Catalyst
1002 you might want to start with a tutorial.</p>
1003 <pre>perldoc <a href="http://cpansearch.perl.org/dist/Catalyst-Manual/lib/Catalyst/Manual/Tutorial.pod">Catalyst::Manual::Tutorial</a></code>
1005 <p>Afterwards you can go on to check out a more complete look at our features.</p>
1007 <code>perldoc <a href="http://cpansearch.perl.org/dist/Catalyst-Manual/lib/Catalyst/Manual/Intro.pod">Catalyst::Manual::Intro</a>
1008 <!-- Something else should go here, but the Catalyst::Manual link seems unhelpful -->
1010 <h2>What to do next?</h2>
1011 <p>Next it's time to write an actual application. Use the
1012 helper scripts to generate <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AController%3A%3A&mode=all">controllers</a>,
1013 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AModel%3A%3A&mode=all">models</a>, and
1014 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AView%3A%3A&mode=all">views</a>;
1015 they can save you a lot of work.</p>
1016 <pre><code>script/${prefix}_create.pl -help</code></pre>
1017 <p>Also, be sure to check out the vast and growing
1018 collection of <a href="http://search.cpan.org/search?query=Catalyst">plugins for Catalyst on CPAN</a>;
1019 you are likely to find what you need there.
1023 <p>Catalyst has a very active community. Here are the main places to
1024 get in touch with us.</p>
1027 <a href="http://dev.catalyst.perl.org">Wiki</a>
1030 <a href="http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst">Mailing-List</a>
1033 <a href="irc://irc.perl.org/catalyst">IRC channel #catalyst on irc.perl.org</a>
1036 <h2>In conclusion</h2>
1037 <p>The Catalyst team hopes you will enjoy using Catalyst as much
1038 as we enjoyed making it. Please contact us if you have ideas
1039 for improvement or other feedback.</p>
1047 =head1 INTERNAL METHODS
1049 These methods are not meant to be used by end users.
1051 =head2 $c->components
1053 Returns a hash of components.
1055 =head2 $c->context_class
1057 Returns or sets the context class.
1059 =head2 $c->dispatcher_class
1061 Returns or sets the dispatcher class.
1063 =head2 $c->engine_class
1065 Returns or sets the engine class.
1067 =head2 $c->handle_request( $class, @arguments )
1069 Called to handle each HTTP request.
1073 sub handle_request {
1074 my ( $class, @arguments ) = @_;
1076 # Always expect worst case!
1079 if ($class->debug) {
1080 my $secs = time - $START || 1;
1081 my $av = sprintf '%.3f', $COUNT / $secs;
1082 my $time = localtime time;
1083 $class->log->info("*** Request $COUNT ($av/s) [$$] [$time] ***");
1086 my $c = $class->prepare(@arguments);
1088 $status = $c->finalize;
1091 if ( my $error = $@ ) {
1093 $class->log->error(qq/Caught exception in engine "$error"/);
1098 if(my $coderef = $class->log->can('_flush')){
1099 $class->log->$coderef();
1104 =head2 $c->prepare( @arguments )
1106 Creates a Catalyst context from an engine-specific request (Apache, CGI,
1112 my ( $class, @arguments ) = @_;
1115 # After the app/ctxt split, this should become an attribute based on something passed
1116 # into the application.
1117 $class->context_class( ref $class || $class ) unless $class->context_class;
1119 my $app = $class->new({});
1120 my $c = $class->context_class->new( application => $app );
1122 # For on-demand data
1123 $c->request->_context($c);
1124 $c->response->_context($c);
1126 #surely this is not the most efficient way to do things...
1127 $c->stats($class->stats_class->new)->enable($c->use_stats);
1129 $c->res->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
1132 #XXX reuse coderef from can
1133 # Allow engine to direct the prepare flow (for POE)
1134 if ( $c->engine->can('prepare') ) {
1135 $c->engine->prepare( $c, @arguments );
1138 $c->prepare_request(@arguments);
1139 $c->prepare_connection;
1140 $c->prepare_query_parameters;
1141 $c->prepare_headers;
1142 $c->prepare_cookies;
1145 # Prepare the body for reading, either by prepare_body
1146 # or the user, if they are using $c->read
1149 # Parse the body unless the user wants it on-demand
1150 unless ( $app->config->{parse_on_demand} ) {
1155 my $method = $c->req->method || '';
1156 my $path = $c->req->path;
1157 $path = '/' unless length $path;
1158 my $address = $c->req->address || '';
1160 $c->log->debug(qq/"$method" request for "$path" from "$address"/)
1168 =head2 $c->request_class
1170 Returns or sets the request class.
1172 =head2 $c->response_class
1174 Returns or sets the response class.
1182 sub run { my $c = shift; return $c->engine->run( $c, @_ ) }
1184 =head2 $c->set_action( $action, $code, $namespace, $attrs )
1186 Sets an action in a given namespace.
1190 sub set_action { my $c = shift; $c->dispatcher->set_action( $c, @_ ) }
1192 =head2 $c->setup_actions($component)
1194 Sets up actions for a component.
1198 sub setup_actions { my $c = shift; $c->dispatcher->setup_actions( $c, @_ ) }
1200 =head2 $c->setup_components
1202 This method is called internally to set up the application's components.
1204 It finds modules by calling the L<locate_components> method, expands them to
1205 package names with the L<expand_component_module> method, and then installs
1206 each component into the application.
1208 The C<setup_components> config option is passed to both of the above methods.
1210 Installation of each component is performed by the L<setup_component> method,
1215 sub setup_components {
1218 my $config = $class->config->{ setup_components };
1220 my @comps = sort { length $a <=> length $b }
1221 $class->locate_components($config);
1222 my %comps = map { $_ => 1 } @comps;
1224 my $deprecatedcatalyst_component_names = grep { /::[CMV]::/ } @comps;
1225 $class->log->warn(qq{Your application is using the deprecated ::[MVC]:: type naming scheme.\n}.
1226 qq{Please switch your class names to ::Model::, ::View:: and ::Controller: as appropriate.\n}
1227 ) if $deprecatedcatalyst_component_names;
1229 for my $component ( @comps ) {
1231 # We pass ignore_loaded here so that overlay files for (e.g.)
1232 # Model::DBI::Schema sub-classes are loaded - if it's in @comps
1233 # we know M::P::O found a file on disk so this is safe
1235 Catalyst::Utils::ensure_class_loaded( $component, { ignore_loaded => 1 } );
1237 # Needs to be done as soon as the component is loaded, as loading a sub-component
1238 # (next time round the loop) can cause us to get the wrong metaclass..
1239 $class->_controller_init_base_classes($component);
1242 for my $component (@comps) {
1243 $class->components->{ $component } = $class->setup_component($component);
1244 for my $component ($class->expand_component_module( $component, $config )) {
1245 next if $comps{$component};
1246 $class->_controller_init_base_classes($component); # Also cover inner packages
1247 $class->components->{ $component } = $class->setup_component($component);
1252 =head2 $c->locate_components( $setup_component_config )
1254 This method is meant to provide a list of component modules that should be
1255 setup for the application. By default, it will use L<Module::Pluggable>.
1257 Specify a C<setup_components> config option to pass additional options directly
1258 to L<Module::Pluggable>. To add additional search paths, specify a key named
1259 C<search_extra> as an array reference. Items in the array beginning with C<::>
1260 will have the application class name prepended to them.
1264 sub locate_components {
1268 my @paths = qw( ::Controller ::C ::Model ::M ::View ::V );
1269 my $extra = delete $config->{ search_extra } || [];
1271 push @paths, @$extra;
1273 my $locator = Module::Pluggable::Object->new(
1274 search_path => [ map { s/^(?=::)/$class/; $_; } @paths ],
1278 my @comps = $locator->plugins;
1283 =head2 $c->expand_component_module( $component, $setup_component_config )
1285 Components found by C<locate_components> will be passed to this method, which
1286 is expected to return a list of component (package) names to be set up.
1290 sub expand_component_module {
1291 my ($class, $module) = @_;
1292 return Devel::InnerPackage::list_packages( $module );
1295 =head2 $c->setup_component
1299 # FIXME - Ugly, ugly hack to ensure the we force initialize non-moose base classes
1300 # nearest to Catalyst::Controller first, no matter what order stuff happens
1301 # to be loaded. There are TODO tests in Moose for this, see
1302 # f2391d17574eff81d911b97be15ea51080500003
1303 sub _controller_init_base_classes {
1304 my ($app_class, $component) = @_;
1305 return unless $component->isa('Catalyst::Controller');
1306 foreach my $class ( reverse @{ mro::get_linear_isa($component) } ) {
1307 Moose::Meta::Class->initialize( $class )
1308 unless find_meta($class);
1312 sub setup_component {
1313 my( $class, $component ) = @_;
1315 unless ( $component->can( 'COMPONENT' ) ) {
1319 my $suffix = Catalyst::Utils::class2classsuffix( $component );
1320 my $config = $class->config->{ $suffix } || {};
1321 # Stash catalyst_component_name in the config here, so that custom COMPONENT
1322 # methods also pass it. local to avoid pointlessly shitting in config
1323 # for the debug screen, as $component is already the key name.
1324 local $config->{catalyst_component_name} = $component;
1326 my $instance = eval { $component->COMPONENT( $class, $config ); };
1328 if ( my $error = $@ ) {
1330 Catalyst::Exception->throw(
1331 message => qq/Couldn't instantiate component "$component", "$error"/
1335 unless (blessed $instance) {
1336 my $metaclass = Moose::Util::find_meta($component);
1337 my $method_meta = $metaclass->find_method_by_name('COMPONENT');
1338 my $component_method_from = $method_meta->associated_metaclass->name;
1339 my $value = defined($instance) ? $instance : 'undef';
1340 Catalyst::Exception->throw(
1342 qq/Couldn't instantiate component "$component", COMPONENT() method (from $component_method_from) didn't return an object-like value (value was $value)./
1348 =head2 $c->setup_dispatcher
1354 sub setup_dispatcher {
1355 my ( $class, $dispatcher ) = @_;
1358 $dispatcher = 'Catalyst::Dispatcher::' . $dispatcher;
1361 if ( my $env = Catalyst::Utils::env_value( $class, 'DISPATCHER' ) ) {
1362 $dispatcher = 'Catalyst::Dispatcher::' . $env;
1365 unless ($dispatcher) {
1366 $dispatcher = $class->dispatcher_class;
1369 Class::MOP::load_class($dispatcher);
1371 # dispatcher instance
1372 $class->dispatcher( $dispatcher->new );
1375 =head2 $c->setup_engine
1382 my ( $class, $engine ) = @_;
1385 $engine = 'Catalyst::Engine::' . $engine;
1388 if ( my $env = Catalyst::Utils::env_value( $class, 'ENGINE' ) ) {
1389 $engine = 'Catalyst::Engine::' . $env;
1392 if ( $ENV{MOD_PERL} ) {
1393 my $meta = Class::MOP::get_metaclass_by_name($class);
1395 # create the apache method
1396 $meta->add_method('apache' => sub { shift->engine->apache });
1398 my ( $software, $version ) =
1399 $ENV{MOD_PERL} =~ /^(\S+)\/(\d+(?:[\.\_]\d+)+)/;
1402 $version =~ s/(\.[^.]+)\./$1/g;
1404 if ( $software eq 'mod_perl' ) {
1408 if ( $version >= 1.99922 ) {
1409 $engine = 'Catalyst::Engine::Apache2::MP20';
1412 elsif ( $version >= 1.9901 ) {
1413 $engine = 'Catalyst::Engine::Apache2::MP19';
1416 elsif ( $version >= 1.24 ) {
1417 $engine = 'Catalyst::Engine::Apache::MP13';
1421 Catalyst::Exception->throw( message =>
1422 qq/Unsupported mod_perl version: $ENV{MOD_PERL}/ );
1427 # install the correct mod_perl handler
1428 if ( $version >= 1.9901 ) {
1429 *handler = sub : method {
1430 shift->handle_request(@_);
1434 *handler = sub ($$) { shift->handle_request(@_) };
1439 elsif ( $software eq 'Zeus-Perl' ) {
1440 $engine = 'Catalyst::Engine::Zeus';
1444 Catalyst::Exception->throw(
1445 message => qq/Unsupported mod_perl: $ENV{MOD_PERL}/ );
1450 $engine = $class->engine_class;
1453 Class::MOP::load_class($engine);
1455 # check for old engines that are no longer compatible
1457 if ( $engine->isa('Catalyst::Engine::Apache')
1458 && !Catalyst::Engine::Apache->VERSION )
1463 elsif ( $engine->isa('Catalyst::Engine::Server::Base')
1464 && Catalyst::Engine::Server->VERSION le '0.02' )
1469 elsif ($engine->isa('Catalyst::Engine::HTTP::POE')
1470 && $engine->VERSION eq '0.01' )
1475 elsif ($engine->isa('Catalyst::Engine::Zeus')
1476 && $engine->VERSION eq '0.01' )
1482 Catalyst::Exception->throw( message =>
1483 qq/Engine "$engine" is not supported by this version of Catalyst/
1488 $class->engine( $engine->new );
1491 =head2 $c->setup_home
1493 Sets up the home directory.
1498 my ( $class, $home ) = @_;
1500 if ( my $env = Catalyst::Utils::env_value( $class, 'HOME' ) ) {
1504 $home ||= Catalyst::Utils::home($class);
1507 #I remember recently being scolded for assigning config values like this
1508 $class->config->{home} ||= $home;
1509 $class->config->{root} ||= Path::Class::Dir->new($home)->subdir('root');
1513 =head2 $c->setup_log
1515 Sets up log by instantiating a L<Catalyst::Log|Catalyst::Log> object and
1516 passing it to C<log()>. Pass in a comma-delimited list of levels to set the
1519 This method also installs a C<debug> method that returns a true value into the
1520 catalyst subclass if the "debug" level is passed in the comma-delimited list,
1521 or if the C<$CATALYST_DEBUG> environment variable is set to a true value.
1523 Note that if the log has already been setup, by either a previous call to
1524 C<setup_log> or by a call such as C<< __PACKAGE__->log( MyLogger->new ) >>,
1525 that this method won't actually set up the log object.
1530 my ( $class, $levels ) = @_;
1533 $levels =~ s/^\s+//;
1534 $levels =~ s/\s+$//;
1535 my %levels = map { $_ => 1 } split /\s*,\s*/, $levels;
1537 my $env_debug = Catalyst::Utils::env_value( $class, 'DEBUG' );
1538 if ( defined $env_debug ) {
1539 $levels{debug} = 1 if $env_debug; # Ugly!
1540 delete($levels{debug}) unless $env_debug;
1543 unless ( $class->log ) {
1544 $class->log( Catalyst::Log->new(keys %levels) );
1547 if ( $levels{debug} ) {
1548 Class::MOP::get_metaclass_by_name($class)->add_method('debug' => sub { 1 });
1549 $class->log->debug('Debug messages enabled');
1553 =head2 $c->setup_plugins
1559 =head2 $c->setup_stats
1561 Sets up timing statistics class.
1566 my ( $class, $stats ) = @_;
1568 Catalyst::Utils::ensure_class_loaded($class->stats_class);
1570 my $env = Catalyst::Utils::env_value( $class, 'STATS' );
1571 if ( defined($env) ? $env : ($stats || $class->debug ) ) {
1572 Class::MOP::get_metaclass_by_name($class)->add_method('use_stats' => sub { 1 });
1573 $class->log->debug('Statistics enabled');
1578 =head2 $c->registered_plugins
1580 Returns a sorted list of the plugins which have either been stated in the
1581 import list or which have been added via C<< MyApp->plugin(@args); >>.
1583 If passed a given plugin name, it will report a boolean value indicating
1584 whether or not that plugin is loaded. A fully qualified name is required if
1585 the plugin name does not begin with C<Catalyst::Plugin::>.
1587 if ($c->registered_plugins('Some::Plugin')) {
1595 sub registered_plugins {
1597 return sort keys %{ $proto->_plugins } unless @_;
1599 return 1 if exists $proto->_plugins->{$plugin};
1600 return exists $proto->_plugins->{"Catalyst::Plugin::$plugin"};
1603 sub _register_plugin {
1604 my ( $proto, $plugin, $instant ) = @_;
1605 my $class = ref $proto || $proto;
1607 Class::MOP::load_class( $plugin );
1609 $proto->_plugins->{$plugin} = 1;
1612 if ( my $meta = Class::MOP::get_metaclass_by_name($class) ) {
1613 my @superclasses = ($plugin, $meta->superclasses );
1614 $meta->superclasses(@superclasses);
1616 unshift @{"$class\::ISA"}, $plugin;
1623 my ( $class, $plugins ) = @_;
1625 $class->_plugins( {} ) unless $class->_plugins;
1628 my @plugins = Catalyst::Utils::resolve_namespace($class . '::Plugin', 'Catalyst::Plugin', @$plugins);
1630 for my $plugin ( reverse @plugins ) {
1631 Class::MOP::load_class($plugin);
1632 my $meta = find_meta($plugin);
1633 next if $meta && $meta->isa('Moose::Meta::Role');
1635 $class->_register_plugin($plugin);
1640 grep { $_ && blessed($_) && $_->isa('Moose::Meta::Role') }
1641 map { find_meta($_) }
1644 Moose::Util::apply_all_roles(
1650 =head2 $c->stats_class
1652 Returns or sets the stats (timing statistics) class.
1654 =head2 $c->use_stats
1656 Returns 1 when stats collection is enabled. Stats collection is enabled
1657 when the -Stats options is set, debug is on or when the <MYAPP>_STATS
1658 environment variable is set.
1660 Note that this is a static method, not an accessor and should be overridden
1661 by declaring C<sub use_stats { 1 }> in your MyApp.pm, not by calling C<< $c->use_stats(1) >>.
1669 Returns the Catalyst version number. Mostly useful for "powered by"
1670 messages in template systems.
1674 sub version { return $Catalyst::VERSION }
1676 =head1 CONFIGURATION
1678 There are a number of 'base' config variables which can be set:
1684 C<default_model> - The default model picked if you say C<< $c->model >>. See L</$c->model($name)>.
1688 C<default_view> - The default view to be rendered or returned when C<< $c->view >>. See L</$c->view($name)>.
1693 C<disable_component_resolution_regex_fallback> - Turns
1694 off the deprecated component resolution functionality so
1695 that if any of the component methods (e.g. C<< $c->controller('Foo') >>)
1696 are called then regex search will not be attempted on string values and
1697 instead C<undef> will be returned.
1701 C<home> - The application home directory. In an uninstalled application,
1702 this is the top level application directory. In an installed application,
1703 this will be the directory containing C<< MyApp.pm >>.
1707 C<ignore_frontend_proxy> - See L</PROXY SUPPORT>
1711 C<name> - The name of the application in debug messages and the debug and
1716 C<parse_on_demand> - The request body (for example file uploads) will not be parsed
1717 until it is accessed. This allows you to (for example) check authentication (and reject
1718 the upload) before actually recieving all the data. See L</ON-DEMAND PARSER>
1722 C<root> - The root directory for templates. Usually this is just a
1723 subdirectory of the home directory, but you can set it to change the
1724 templates to a different directory.
1728 C<search_extra> - Array reference passed to Module::Pluggable to for additional
1729 namespaces from which components will be loaded (and constructed and stored in
1730 C<< $c->components >>).
1734 C<show_internal_actions> - If true, causes internal actions such as C<< _DISPATCH >>
1735 to be shown in hit debug tables in the test server.
1739 C<using_frontend_proxy> - See L</PROXY SUPPORT>.
1743 =head1 INTERNAL ACTIONS
1745 Catalyst uses internal actions like C<_DISPATCH>, C<_BEGIN>, C<_AUTO>,
1746 C<_ACTION>, and C<_END>. These are by default not shown in the private
1747 action table, but you can make them visible with a config parameter.
1749 MyApp->config(show_internal_actions => 1);
1751 =head1 ON-DEMAND PARSER
1753 The request body is usually parsed at the beginning of a request,
1754 but if you want to handle input yourself, you can enable on-demand
1755 parsing with a config parameter.
1757 MyApp->config(parse_on_demand => 1);
1759 =head1 PROXY SUPPORT
1761 Many production servers operate using the common double-server approach,
1762 with a lightweight frontend web server passing requests to a larger
1763 backend server. An application running on the backend server must deal
1764 with two problems: the remote user always appears to be C<127.0.0.1> and
1765 the server's hostname will appear to be C<localhost> regardless of the
1766 virtual host that the user connected through.
1768 Catalyst will automatically detect this situation when you are running
1769 the frontend and backend servers on the same machine. The following
1770 changes are made to the request.
1772 $c->req->address is set to the user's real IP address, as read from
1773 the HTTP X-Forwarded-For header.
1775 The host value for $c->req->base and $c->req->uri is set to the real
1776 host, as read from the HTTP X-Forwarded-Host header.
1778 Additionally, you may be running your backend application on an insecure
1779 connection (port 80) while your frontend proxy is running under SSL. If there
1780 is a discrepancy in the ports, use the HTTP header C<X-Forwarded-Port> to
1781 tell Catalyst what port the frontend listens on. This will allow all URIs to
1782 be created properly.
1784 In the case of passing in:
1786 X-Forwarded-Port: 443
1788 All calls to C<uri_for> will result in an https link, as is expected.
1790 Obviously, your web server must support these headers for this to work.
1792 In a more complex server farm environment where you may have your
1793 frontend proxy server(s) on different machines, you will need to set a
1794 configuration option to tell Catalyst to read the proxied data from the
1797 MyApp->config(using_frontend_proxy => 1);
1799 If you do not wish to use the proxy support at all, you may set:
1801 MyApp->config(ignore_frontend_proxy => 1);
1803 =head1 THREAD SAFETY
1805 Catalyst has been tested under Apache 2's threading C<mpm_worker>,
1806 C<mpm_winnt>, and the standalone forking HTTP server on Windows. We
1807 believe the Catalyst core to be thread-safe.
1809 If you plan to operate in a threaded environment, remember that all other
1810 modules you are using must also be thread-safe. Some modules, most notably
1811 L<DBD::SQLite>, are not thread-safe.
1817 Join #catalyst on irc.perl.org.
1821 http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
1822 http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst-dev
1826 http://catalyst.perl.org
1830 http://dev.catalyst.perl.org
1834 =head2 L<Task::Catalyst> - All you need to start with Catalyst
1836 =head2 L<Catalyst::Manual> - The Catalyst Manual
1838 =head2 L<Catalyst::Component>, L<Catalyst::Controller> - Base classes for components
1840 =head2 L<Catalyst::Engine> - Core engine
1842 =head2 L<Catalyst::Log> - Log class.
1844 =head2 L<Catalyst::Request> - Request object
1846 =head2 L<Catalyst::Response> - Response object
1848 =head2 L<Catalyst::Test> - The test suite.
1850 =head1 PROJECT FOUNDER
1852 sri: Sebastian Riedel <sri@cpan.org>
1858 acme: Leon Brocard <leon@astray.com>
1860 abraxxa: Alexander Hartmaier <abraxxa@cpan.org>
1864 Andrew Ford E<lt>A.Ford@ford-mason.co.ukE<gt>
1868 andyg: Andy Grundman <andy@hybridized.org>
1870 audreyt: Audrey Tang
1872 bricas: Brian Cassidy <bricas@cpan.org>
1874 Caelum: Rafael Kitover <rkitover@io.com>
1876 chansen: Christian Hansen
1878 chicks: Christopher Hicks
1880 Chisel Wright C<pause@herlpacker.co.uk>
1882 Danijel Milicevic C<me@danijel.de>
1884 David Kamholz E<lt>dkamholz@cpan.orgE<gt>
1886 David Naughton, C<naughton@umn.edu>
1890 dkubb: Dan Kubb <dan.kubb-cpan@onautopilot.com>
1894 dwc: Daniel Westermann-Clark <danieltwc@cpan.org>
1896 esskar: Sascha Kiefer
1898 fireartist: Carl Franks <cfranks@cpan.org>
1900 frew: Arthur Axel "fREW" Schmidt <frioux@gmail.com>
1902 gabb: Danijel Milicevic
1906 Gavin Henry C<ghenry@perl.me.uk>
1910 groditi: Guillermo Roditi <groditi@gmail.com>
1912 hobbs: Andrew Rodland <andrew@cleverdomain.org>
1914 ilmari: Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>
1916 jcamacho: Juan Camacho
1918 jester: Jesse Sheidlower C<jester@panix.com>
1920 jhannah: Jay Hannah <jay@jays.net>
1926 jon: Jon Schutz <jjschutz@cpan.org>
1928 Jonathan Rockway C<< <jrockway@cpan.org> >>
1930 Kieren Diment C<kd@totaldatasolution.com>
1932 konobi: Scott McWhirter <konobi@cpan.org>
1934 marcus: Marcus Ramberg <mramberg@cpan.org>
1936 miyagawa: Tatsuhiko Miyagawa <miyagawa@bulknews.net>
1938 mst: Matt S. Trout <mst@shadowcatsystems.co.uk>
1942 naughton: David Naughton
1944 ningu: David Kamholz <dkamholz@cpan.org>
1946 nothingmuch: Yuval Kogman <nothingmuch@woobling.org>
1948 numa: Dan Sully <daniel@cpan.org>
1952 omega: Andreas Marienborg
1954 Oleg Kostyuk <cub.uanic@gmail.com>
1956 phaylon: Robert Sedlacek <phaylon@dunkelheit.at>
1958 rafl: Florian Ragwitz <rafl@debian.org>
1960 random: Roland Lammel <lammel@cpan.org>
1962 Robert Sedlacek C<< <rs@474.at> >>
1966 t0m: Tomas Doran <bobtfish@bobtfish.net>
1970 Viljo Marrandi C<vilts@yahoo.com>
1972 Will Hawes C<info@whawes.co.uk>
1974 willert: Sebastian Willert <willert@cpan.org>
1976 Yuval Kogman, C<nothingmuch@woobling.org>
1980 This library is free software. You can redistribute it and/or modify it under
1981 the same terms as Perl itself.
1987 __PACKAGE__->meta->make_immutable;