Add myself to CONTRIBUTORS.
[catagits/Catalyst-Runtime.git] / lib / Catalyst.pm
CommitLineData
fc7ec1d9 1package Catalyst;
2
a7caa492 3use Moose;
4extends 'Catalyst::Component';
fbcc39ad 5use bytes;
a2f2cde9 6use Catalyst::Exception;
fc7ec1d9 7use Catalyst::Log;
fbcc39ad 8use Catalyst::Request;
9use Catalyst::Request::Upload;
10use Catalyst::Response;
812a28c9 11use Catalyst::Utils;
31375184 12use Catalyst::Controller;
364d7324 13use Devel::InnerPackage ();
8f62c91a 14use File::stat;
c50f595c 15use Module::Pluggable::Object ();
c50f595c 16use Text::SimpleTable ();
17use Path::Class::Dir ();
18use Path::Class::File ();
fbcc39ad 19use Time::HiRes qw/gettimeofday tv_interval/;
c50f595c 20use URI ();
933ba403 21use URI::http;
22use URI::https;
6a4a7002 23use Scalar::Util qw/weaken blessed/;
5513038d 24use Tree::Simple qw/use_weak_refs/;
25use Tree::Simple::Visitor::FindByUID;
261c571e 26use attributes;
5789a3d8 27use utf8;
c45c5d37 28use Carp qw/croak carp/;
fc7ec1d9 29
f63c03e4 30BEGIN { require 5.008001; }
31
6680c772 32has stack => (is => 'rw', default => sub { [] });
33has stash => (is => 'rw', default => sub { {} });
34has state => (is => 'rw', default => 0);
b6d4ee6e 35has stats => (is => 'rw');
36has action => (is => 'rw');
6680c772 37has counter => (is => 'rw', default => sub { {} });
38has request => (is => 'rw', default => sub { $_[0]->request_class->new({}) }, required => 1, lazy => 1);
39has response => (is => 'rw', default => sub { $_[0]->response_class->new({}) }, required => 1, lazy => 1);
e63bdf38 40has namespace => (is => 'rw');
41
8767c5a3 42sub depth { scalar @{ shift->stack || [] }; }
0fc2d522 43sub comp { shift->component(@_) }
6680c772 44
45sub req {
46 # carp "the use of req() is deprecated in favour of request()";
47 my $self = shift; return $self->request(@_);
48}
49sub res {
50 # carp "the use of res() is deprecated in favour of response()";
51 my $self = shift; return $self->response(@_);
52}
fbcc39ad 53
54# For backwards compatibility
0fc2d522 55sub finalize_output { shift->finalize_body(@_) };
fbcc39ad 56
57# For statistics
58our $COUNT = 1;
59our $START = time;
60our $RECURSION = 1000;
61our $DETACH = "catalyst_detach\n";
2f381252 62our $GO = "catalyst_go\n";
fbcc39ad 63
b6d4ee6e 64#I imagine that very few of these really need to be class variables. if any.
65#maybe we should just make them attributes with a default?
fbcc39ad 66__PACKAGE__->mk_classdata($_)
3cec521a 67 for qw/components arguments dispatcher engine log dispatcher_class
ac5c933b 68 engine_class context_class request_class response_class stats_class
dc5f035e 69 setup_finished/;
cb0354c6 70
3cec521a 71__PACKAGE__->dispatcher_class('Catalyst::Dispatcher');
72__PACKAGE__->engine_class('Catalyst::Engine::CGI');
73__PACKAGE__->request_class('Catalyst::Request');
74__PACKAGE__->response_class('Catalyst::Response');
dc5f035e 75__PACKAGE__->stats_class('Catalyst::Stats');
fbcc39ad 76
6415bb4d 77# Remember to update this in Catalyst::Runtime as well!
78
2f381252 79our $VERSION = '5.7099_03';
189e2a51 80
fbcc39ad 81sub import {
82 my ( $class, @arguments ) = @_;
83
84 # We have to limit $class to Catalyst to avoid pushing Catalyst upon every
85 # callers @ISA.
86 return unless $class eq 'Catalyst';
87
84ff88cf 88 my $caller = caller();
89 return if $caller eq 'main';
90 my $meta = Moose::Meta::Class->initialize($caller);
91 #Moose->import({ into => $caller }); #do we want to do this?
fbcc39ad 92
93 unless ( $caller->isa('Catalyst') ) {
84ff88cf 94 my @superclasses = ($meta->superclasses, $class, 'Catalyst::Controller');
95 $meta->superclasses(@superclasses);
96 }
97 unless( $meta->has_method('meta') ){
98 $meta->add_method(meta => sub { Moose::Meta::Class->initialize("${caller}") } );
fbcc39ad 99 }
100
101 $caller->arguments( [@arguments] );
102 $caller->setup_home;
103}
fc7ec1d9 104
105=head1 NAME
106
107Catalyst - The Elegant MVC Web Application Framework
108
109=head1 SYNOPSIS
110
e7ad3b81 111See the L<Catalyst::Manual> distribution for comprehensive
112documentation and tutorials.
113
86418559 114 # Install Catalyst::Devel for helpers and other development tools
b4b01a8a 115 # use the helper to create a new application
91864987 116 catalyst.pl MyApp
fc7ec1d9 117
118 # add models, views, controllers
2f381252 119 script/myapp_create.pl model MyDatabase DBIC::Schema create=static dbi:SQLite:/path/to/db
cc95842f 120 script/myapp_create.pl view MyTemplate TT
0ef52a96 121 script/myapp_create.pl controller Search
fc7ec1d9 122
e7f1cf73 123 # built in testserver -- use -r to restart automatically on changes
cc95842f 124 # --help to see all available options
ae4e40a7 125 script/myapp_server.pl
fc7ec1d9 126
0ef52a96 127 # command line testing interface
ae4e40a7 128 script/myapp_test.pl /yada
fc7ec1d9 129
b4b01a8a 130 ### in lib/MyApp.pm
0ef52a96 131 use Catalyst qw/-Debug/; # include plugins here as well
ac5c933b 132
85d9fce6 133 ### In lib/MyApp/Controller/Root.pm (autocreated)
0ef52a96 134 sub foo : Global { # called for /foo, /foo/1, /foo/1/2, etc.
ae1e6b59 135 my ( $self, $c, @args ) = @_; # args are qw/1 2/ for /foo/1/2
136 $c->stash->{template} = 'foo.tt'; # set the template
0ef52a96 137 # lookup something from db -- stash vars are passed to TT
ac5c933b 138 $c->stash->{data} =
b4b01a8a 139 $c->model('Database::Foo')->search( { country => $args[0] } );
0ef52a96 140 if ( $c->req->params->{bar} ) { # access GET or POST parameters
141 $c->forward( 'bar' ); # process another action
ac5c933b 142 # do something else after forward returns
0ef52a96 143 }
144 }
ac5c933b 145
ae1e6b59 146 # The foo.tt TT template can use the stash data from the database
0ef52a96 147 [% WHILE (item = data.next) %]
148 [% item.foo %]
149 [% END %]
ac5c933b 150
0ef52a96 151 # called for /bar/of/soap, /bar/of/soap/10, etc.
152 sub bar : Path('/bar/of/soap') { ... }
fc7ec1d9 153
ae1e6b59 154 # called for all actions, from the top-most controller downwards
ac5c933b 155 sub auto : Private {
0ef52a96 156 my ( $self, $c ) = @_;
b4b01a8a 157 if ( !$c->user_exists ) { # Catalyst::Plugin::Authentication
0ef52a96 158 $c->res->redirect( '/login' ); # require login
159 return 0; # abort request and go immediately to end()
160 }
ae1e6b59 161 return 1; # success; carry on to next action
0ef52a96 162 }
ac5c933b 163
ae1e6b59 164 # called after all actions are finished
ac5c933b 165 sub end : Private {
5a8ed4fe 166 my ( $self, $c ) = @_;
0ef52a96 167 if ( scalar @{ $c->error } ) { ... } # handle errors
168 return if $c->res->body; # already have a response
169 $c->forward( 'MyApp::View::TT' ); # render template
5a8ed4fe 170 }
171
0ef52a96 172 ### in MyApp/Controller/Foo.pm
173 # called for /foo/bar
174 sub bar : Local { ... }
ac5c933b 175
5400c668 176 # called for /blargle
177 sub blargle : Global { ... }
ac5c933b 178
5400c668 179 # an index action matches /foo, but not /foo/1, etc.
180 sub index : Private { ... }
ac5c933b 181
0ef52a96 182 ### in MyApp/Controller/Foo/Bar.pm
183 # called for /foo/bar/baz
184 sub baz : Local { ... }
ac5c933b 185
b4b01a8a 186 # first Root auto is called, then Foo auto, then this
0ef52a96 187 sub auto : Private { ... }
ac5c933b 188
0ef52a96 189 # powerful regular expression paths are also possible
190 sub details : Regex('^product/(\w+)/details$') {
5a8ed4fe 191 my ( $self, $c ) = @_;
0ef52a96 192 # extract the (\w+) from the URI
2982e768 193 my $product = $c->req->captures->[0];
5a8ed4fe 194 }
fc7ec1d9 195
0ef52a96 196See L<Catalyst::Manual::Intro> for additional information.
3803e98f 197
fc7ec1d9 198=head1 DESCRIPTION
199
86418559 200Catalyst is a modern framework for making web applications without the
201pain usually associated with this process. This document is a reference
202to the main Catalyst application. If you are a new user, we suggest you
203start with L<Catalyst::Manual::Tutorial> or L<Catalyst::Manual::Intro>.
fc7ec1d9 204
205See L<Catalyst::Manual> for more documentation.
206
ae1e6b59 207Catalyst plugins can be loaded by naming them as arguments to the "use
208Catalyst" statement. Omit the C<Catalyst::Plugin::> prefix from the
209plugin name, i.e., C<Catalyst::Plugin::My::Module> becomes
210C<My::Module>.
fc7ec1d9 211
0ef52a96 212 use Catalyst qw/My::Module/;
fc7ec1d9 213
836e1134 214If your plugin starts with a name other than C<Catalyst::Plugin::>, you can
215fully qualify the name by using a unary plus:
216
217 use Catalyst qw/
218 My::Module
219 +Fully::Qualified::Plugin::Name
220 /;
221
ae1e6b59 222Special flags like C<-Debug> and C<-Engine> can also be specified as
223arguments when Catalyst is loaded:
fc7ec1d9 224
225 use Catalyst qw/-Debug My::Module/;
226
ae1e6b59 227The position of plugins and flags in the chain is important, because
86418559 228they are loaded in the order in which they appear.
fc7ec1d9 229
23f9d934 230The following flags are supported:
231
b5ecfcf0 232=head2 -Debug
23f9d934 233
f8ad6ea5 234Enables debug output. You can also force this setting from the system
86418559 235environment with CATALYST_DEBUG or <MYAPP>_DEBUG. The environment
236settings override the application, with <MYAPP>_DEBUG having the highest
237priority.
fc7ec1d9 238
b5ecfcf0 239=head2 -Engine
fc7ec1d9 240
ae1e6b59 241Forces Catalyst to use a specific engine. Omit the
242C<Catalyst::Engine::> prefix of the engine name, i.e.:
fc7ec1d9 243
0ef52a96 244 use Catalyst qw/-Engine=CGI/;
fc7ec1d9 245
b5ecfcf0 246=head2 -Home
fbcc39ad 247
ae1e6b59 248Forces Catalyst to use a specific home directory, e.g.:
249
86418559 250 use Catalyst qw[-Home=/usr/mst];
fbcc39ad 251
cc95842f 252This can also be done in the shell environment by setting either the
253C<CATALYST_HOME> environment variable or C<MYAPP_HOME>; where C<MYAPP>
254is replaced with the uppercased name of your application, any "::" in
255the name will be replaced with underscores, e.g. MyApp::Web should use
256MYAPP_WEB_HOME. If both variables are set, the MYAPP_HOME one will be used.
257
b5ecfcf0 258=head2 -Log
fbcc39ad 259
0ef52a96 260Specifies log level.
fbcc39ad 261
dc5f035e 262=head2 -Stats
263
264Enables statistics collection and reporting. You can also force this setting
265from the system environment with CATALYST_STATS or <MYAPP>_STATS. The
266environment settings override the application, with <MYAPP>_STATS having the
267highest priority.
268
ac5c933b 269e.g.
dc5f035e 270
271 use Catalyst qw/-Stats=1/
272
23f9d934 273=head1 METHODS
274
f7b672ef 275=head2 INFORMATION ABOUT THE CURRENT REQUEST
0ef52a96 276
b5ecfcf0 277=head2 $c->action
66e28e3f 278
ae1e6b59 279Returns a L<Catalyst::Action> object for the current action, which
280stringifies to the action name. See L<Catalyst::Action>.
0ef52a96 281
b5ecfcf0 282=head2 $c->namespace
0ef52a96 283
86418559 284Returns the namespace of the current action, i.e., the URI prefix
ae1e6b59 285corresponding to the controller of the current action. For example:
286
287 # in Controller::Foo::Bar
288 $c->namespace; # returns 'foo/bar';
0ef52a96 289
b5ecfcf0 290=head2 $c->request
0ef52a96 291
b5ecfcf0 292=head2 $c->req
0ef52a96 293
86418559 294Returns the current L<Catalyst::Request> object, giving access to
295information about the current client request (including parameters,
296cookies, HTTP headers, etc.). See L<Catalyst::Request>.
0ef52a96 297
b4b01a8a 298=head2 REQUEST FLOW HANDLING
0ef52a96 299
b5ecfcf0 300=head2 $c->forward( $action [, \@arguments ] )
0ef52a96 301
b5ecfcf0 302=head2 $c->forward( $class, $method, [, \@arguments ] )
0ef52a96 303
86418559 304Forwards processing to another action, by its private name. If you give a
b4b01a8a 305class name but no method, C<process()> is called. You may also optionally
306pass arguments in an arrayref. The action will receive the arguments in
cc95842f 307C<@_> and C<< $c->req->args >>. Upon returning from the function,
308C<< $c->req->args >> will be restored to the previous values.
0ef52a96 309
3b984c64 310Any data C<return>ed from the action forwarded to, will be returned by the
d759db1e 311call to forward.
3b984c64 312
313 my $foodata = $c->forward('/foo');
0ef52a96 314 $c->forward('index');
e112461a 315 $c->forward(qw/MyApp::Model::DBIC::Foo do_stuff/);
0ef52a96 316 $c->forward('MyApp::View::TT');
317
86418559 318Note that forward implies an C<<eval { }>> around the call (actually
319C<execute> does), thus de-fatalizing all 'dies' within the called
320action. If you want C<die> to propagate you need to do something like:
f3e6a8c0 321
322 $c->forward('foo');
323 die $c->error if $c->error;
324
86418559 325Or make sure to always return true values from your actions and write
326your code like this:
f3e6a8c0 327
328 $c->forward('foo') || return;
329
0ef52a96 330=cut
331
6680c772 332sub forward { my $c = shift; no warnings 'recursion'; $c->dispatcher->forward( $c, @_ ) }
0ef52a96 333
b5ecfcf0 334=head2 $c->detach( $action [, \@arguments ] )
0ef52a96 335
b5ecfcf0 336=head2 $c->detach( $class, $method, [, \@arguments ] )
0ef52a96 337
264bac8c 338=head2 $c->detach()
339
ac5c933b 340The same as C<forward>, but doesn't return to the previous action when
341processing is finished.
0ef52a96 342
264bac8c 343When called with no arguments it escapes the processing chain entirely.
344
0ef52a96 345=cut
346
347sub detach { my $c = shift; $c->dispatcher->detach( $c, @_ ) }
348
2f381252 349=head2 $c->go( $action [, \@arguments ] )
350
351=head2 $c->go( $class, $method, [, \@arguments ] )
352
353Almost the same as C<detach>, but does a full dispatch, instead of just
354calling the new C<$action> / C<$class-E<gt>$method>. This means that C<begin>,
355C<auto> and the method you go to is called, just like a new request.
356
357C<$c-E<gt>stash> is kept unchanged.
358
359=cut
360
361sub go { my $c = shift; $c->dispatcher->go( $c, @_ ) }
362
b4b01a8a 363=head2 $c->response
364
365=head2 $c->res
366
cc95842f 367Returns the current L<Catalyst::Response> object, see there for details.
b4b01a8a 368
369=head2 $c->stash
370
371Returns a hashref to the stash, which may be used to store data and pass
372it between components during a request. You can also set hash keys by
373passing arguments. The stash is automatically sent to the view. The
374stash is cleared at the end of a request; it cannot be used for
86418559 375persistent storage (for this you must use a session; see
376L<Catalyst::Plugin::Session> for a complete system integrated with
377Catalyst).
b4b01a8a 378
379 $c->stash->{foo} = $bar;
380 $c->stash( { moose => 'majestic', qux => 0 } );
381 $c->stash( bar => 1, gorch => 2 ); # equivalent to passing a hashref
ac5c933b 382
b4b01a8a 383 # stash is automatically passed to the view for use in a template
cc95842f 384 $c->forward( 'MyApp::View::TT' );
b4b01a8a 385
386=cut
387
4090e3bb 388around stash => sub {
389 my $orig = shift;
b4b01a8a 390 my $c = shift;
4090e3bb 391 my $stash = $orig->($c);
b4b01a8a 392 if (@_) {
4090e3bb 393 my $new_stash = @_ > 1 ? {@_} : $_[0];
394 croak('stash takes a hash or hashref') unless ref $new_stash;
395 foreach my $key ( keys %$new_stash ) {
396 $stash->{$key} = $new_stash->{$key};
b4b01a8a 397 }
398 }
0fc2d522 399
4090e3bb 400 return $stash;
401};
0fc2d522 402
b4b01a8a 403
b5ecfcf0 404=head2 $c->error
0ef52a96 405
b5ecfcf0 406=head2 $c->error($error, ...)
0ef52a96 407
b5ecfcf0 408=head2 $c->error($arrayref)
0ef52a96 409
83a8fcac 410Returns an arrayref containing error messages. If Catalyst encounters an
411error while processing a request, it stores the error in $c->error. This
e7ad3b81 412method should only be used to store fatal error messages.
0ef52a96 413
414 my @error = @{ $c->error };
415
416Add a new error.
417
418 $c->error('Something bad happened');
419
0ef52a96 420=cut
421
422sub error {
423 my $c = shift;
424 if ( $_[0] ) {
425 my $error = ref $_[0] eq 'ARRAY' ? $_[0] : [@_];
9ce44430 426 croak @$error unless ref $c;
0ef52a96 427 push @{ $c->{error} }, @$error;
428 }
429 elsif ( defined $_[0] ) { $c->{error} = undef }
430 return $c->{error} || [];
431}
432
b4b01a8a 433
434=head2 $c->state
435
436Contains the return value of the last executed action.
437
ca81eb67 438=head2 $c->clear_errors
439
440Clear errors. You probably don't want to clear the errors unless you are
441implementing a custom error screen.
442
443This is equivalent to running
444
445 $c->error(0);
446
447=cut
448
449sub clear_errors {
450 my $c = shift;
451 $c->error(0);
452}
453
2f381252 454# search components given a name and some prefixes
455sub _comp_search_prefixes {
456 my ( $c, $name, @prefixes ) = @_;
457 my $appclass = ref $c || $c;
458 my $filter = "^${appclass}::(" . join( '|', @prefixes ) . ')::';
0ef52a96 459
2f381252 460 # map the original component name to the sub part that we will search against
461 my %eligible = map { my $n = $_; $n =~ s{^$appclass\::[^:]+::}{}; $_ => $n; }
462 grep { /$filter/ } keys %{ $c->components };
0756fe3b 463
2f381252 464 # undef for a name will return all
465 return keys %eligible if !defined $name;
0756fe3b 466
2f381252 467 my $query = ref $name ? $name : qr/^$name$/i;
468 my @result = grep { $eligible{$_} =~ m{$query} } keys %eligible;
0756fe3b 469
2f381252 470 return map { $c->components->{ $_ } } @result if @result;
0756fe3b 471
2f381252 472 # if we were given a regexp to search against, we're done.
473 return if ref $name;
0756fe3b 474
2f381252 475 # regexp fallback
476 $query = qr/$name/i;
477 @result = map { $c->components->{ $_ } } grep { $eligible{ $_ } =~ m{$query} } keys %eligible;
0756fe3b 478
2f381252 479 # no results? try against full names
480 if( !@result ) {
481 @result = map { $c->components->{ $_ } } grep { m{$query} } keys %eligible;
482 }
0756fe3b 483
2f381252 484 # don't warn if we didn't find any results, it just might not exist
485 if( @result ) {
486 $c->log->warn( qq(Found results for "${name}" using regexp fallback.) );
487 $c->log->warn( 'Relying on the regexp fallback behavior for component resolution is unreliable and unsafe.' );
488 $c->log->warn( 'If you really want to search, pass in a regexp as the argument.' );
489 }
0756fe3b 490
2f381252 491 return @result;
0756fe3b 492}
493
ac5c933b 494# Find possible names for a prefix
3b88a455 495sub _comp_names {
496 my ( $c, @prefixes ) = @_;
3b88a455 497 my $appclass = ref $c || $c;
498
2f381252 499 my $filter = "^${appclass}::(" . join( '|', @prefixes ) . ')::';
3b88a455 500
2f381252 501 my @names = map { s{$filter}{}; $_; } $c->_comp_search_prefixes( undef, @prefixes );
3b88a455 502 return @names;
503}
504
197bd788 505# Filter a component before returning by calling ACCEPT_CONTEXT if available
506sub _filter_component {
507 my ( $c, $comp, @args ) = @_;
2f381252 508
df543cc2 509 if ( Scalar::Util::blessed($c) && eval { $comp->can('ACCEPT_CONTEXT'); } ) {
197bd788 510 return $comp->ACCEPT_CONTEXT( $c, @args );
511 }
2f381252 512
513 return $comp;
197bd788 514}
515
f7b672ef 516=head2 COMPONENT ACCESSORS
0ef52a96 517
b5ecfcf0 518=head2 $c->controller($name)
af3ff00e 519
0ef52a96 520Gets a L<Catalyst::Controller> instance by name.
af3ff00e 521
522 $c->controller('Foo')->do_stuff;
523
86418559 524If the name is omitted, will return the controller for the dispatched
525action.
649fd1fa 526
2f381252 527If you want to search for controllers, pass in a regexp as the argument.
528
529 # find all controllers that start with Foo
530 my @foo_controllers = $c->controller(qr{^Foo});
531
532
af3ff00e 533=cut
534
535sub controller {
197bd788 536 my ( $c, $name, @args ) = @_;
2f381252 537
538 if( $name ) {
539 my @result = $c->_comp_search_prefixes( $name, qw/Controller C/ );
540 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
541 return $c->_filter_component( $result[ 0 ], @args );
542 }
543
197bd788 544 return $c->component( $c->action->class );
af3ff00e 545}
546
b5ecfcf0 547=head2 $c->model($name)
fc7ec1d9 548
0ef52a96 549Gets a L<Catalyst::Model> instance by name.
550
551 $c->model('Foo')->do_stuff;
fc7ec1d9 552
72f87c4b 553Any extra arguments are directly passed to ACCEPT_CONTEXT.
554
ac5c933b 555If the name is omitted, it will look for
2f381252 556 - a model object in $c->stash->{current_model_instance}, then
a3b71f0f 557 - a model name in $c->stash->{current_model}, then
558 - a config setting 'default_model', or
559 - check if there is only one model, and return it if that's the case.
649fd1fa 560
2f381252 561If you want to search for models, pass in a regexp as the argument.
562
563 # find all models that start with Foo
564 my @foo_models = $c->model(qr{^Foo});
565
fc7ec1d9 566=cut
567
0ef52a96 568sub model {
197bd788 569 my ( $c, $name, @args ) = @_;
2f381252 570
571 if( $name ) {
572 my @result = $c->_comp_search_prefixes( $name, qw/Model M/ );
573 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
574 return $c->_filter_component( $result[ 0 ], @args );
575 }
576
a3b71f0f 577 if (ref $c) {
ac5c933b 578 return $c->stash->{current_model_instance}
a3b71f0f 579 if $c->stash->{current_model_instance};
580 return $c->model( $c->stash->{current_model} )
581 if $c->stash->{current_model};
a3b71f0f 582 }
72f87c4b 583 return $c->model( $c->config->{default_model} )
584 if $c->config->{default_model};
3b88a455 585
2f381252 586 my( $comp, $rest ) = $c->_comp_search_prefixes( undef, qw/Model M/);
3b88a455 587
2f381252 588 if( $rest ) {
589 $c->log->warn( 'Calling $c->model() will return a random model unless you specify one of:' );
590 $c->log->warn( '* $c->config->{default_model} # the name of the default model to use' );
591 $c->log->warn( '* $c->stash->{current_model} # the name of the model to use for this request' );
592 $c->log->warn( '* $c->stash->{current_model_instance} # the instance of the model to use for this request' );
593 $c->log->warn( 'NB: in version 5.80, the "random" behavior will not work at all.' );
594 }
3b88a455 595
2f381252 596 return $c->_filter_component( $comp );
3b88a455 597}
598
b4b01a8a 599
b5ecfcf0 600=head2 $c->view($name)
0ef52a96 601
602Gets a L<Catalyst::View> instance by name.
fc7ec1d9 603
0ef52a96 604 $c->view('Foo')->do_stuff;
fc7ec1d9 605
72f87c4b 606Any extra arguments are directly passed to ACCEPT_CONTEXT.
607
ac5c933b 608If the name is omitted, it will look for
2f381252 609 - a view object in $c->stash->{current_view_instance}, then
a3b71f0f 610 - a view name in $c->stash->{current_view}, then
611 - a config setting 'default_view', or
612 - check if there is only one view, and return it if that's the case.
649fd1fa 613
2f381252 614If you want to search for views, pass in a regexp as the argument.
615
616 # find all views that start with Foo
617 my @foo_views = $c->view(qr{^Foo});
618
fc7ec1d9 619=cut
620
0ef52a96 621sub view {
197bd788 622 my ( $c, $name, @args ) = @_;
2f381252 623
624 if( $name ) {
625 my @result = $c->_comp_search_prefixes( $name, qw/View V/ );
626 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
627 return $c->_filter_component( $result[ 0 ], @args );
628 }
629
a3b71f0f 630 if (ref $c) {
ac5c933b 631 return $c->stash->{current_view_instance}
a3b71f0f 632 if $c->stash->{current_view_instance};
633 return $c->view( $c->stash->{current_view} )
634 if $c->stash->{current_view};
a3b71f0f 635 }
72f87c4b 636 return $c->view( $c->config->{default_view} )
637 if $c->config->{default_view};
2f381252 638
639 my( $comp, $rest ) = $c->_comp_search_prefixes( undef, qw/View V/);
640
641 if( $rest ) {
642 $c->log->warn( 'Calling $c->view() will return a random view unless you specify one of:' );
643 $c->log->warn( '* $c->config->{default_view} # the name of the default view to use' );
644 $c->log->warn( '* $c->stash->{current_view} # the name of the view to use for this request' );
645 $c->log->warn( '* $c->stash->{current_view_instance} # the instance of the view to use for this request' );
646 $c->log->warn( 'NB: in version 5.80, the "random" behavior will not work at all.' );
647 }
648
649 return $c->_filter_component( $comp );
650}
651
652=head2 $c->controllers
653
654Returns the available names which can be passed to $c->controller
655
656=cut
657
658sub controllers {
659 my ( $c ) = @_;
660 return $c->_comp_names(qw/Controller C/);
0ef52a96 661}
fbcc39ad 662
b4b01a8a 663=head2 $c->models
664
665Returns the available names which can be passed to $c->model
666
667=cut
668
669sub models {
670 my ( $c ) = @_;
671 return $c->_comp_names(qw/Model M/);
672}
673
674
3b88a455 675=head2 $c->views
676
677Returns the available names which can be passed to $c->view
678
679=cut
680
681sub views {
682 my ( $c ) = @_;
683 return $c->_comp_names(qw/View V/);
684}
685
b4b01a8a 686=head2 $c->comp($name)
687
688=head2 $c->component($name)
689
cc95842f 690Gets a component object by name. This method is not recommended,
b4b01a8a 691unless you want to get a specific component by full
cc95842f 692class. C<< $c->controller >>, C<< $c->model >>, and C<< $c->view >>
b4b01a8a 693should be used instead.
694
2f381252 695If C<$name> is a regexp, a list of components matched against the full
696component name will be returned.
697
b4b01a8a 698=cut
699
700sub component {
2f381252 701 my ( $c, $name, @args ) = @_;
b4b01a8a 702
2f381252 703 if( $name ) {
704 my $comps = $c->components;
b4b01a8a 705
2f381252 706 if( !ref $name ) {
707 # is it the exact name?
708 return $c->_filter_component( $comps->{ $name }, @args )
709 if exists $comps->{ $name };
b4b01a8a 710
2f381252 711 # perhaps we just omitted "MyApp"?
712 my $composed = ( ref $c || $c ) . "::${name}";
713 return $c->_filter_component( $comps->{ $composed }, @args )
714 if exists $comps->{ $composed };
b4b01a8a 715
2f381252 716 # search all of the models, views and controllers
717 my( $comp ) = $c->_comp_search_prefixes( $name, qw/Model M Controller C View V/ );
718 return $c->_filter_component( $comp, @args ) if $comp;
719 }
720
721 # This is here so $c->comp( '::M::' ) works
722 my $query = ref $name ? $name : qr{$name}i;
b4b01a8a 723
2f381252 724 my @result = grep { m{$query} } keys %{ $c->components };
725 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
b4b01a8a 726
2f381252 727 if( $result[ 0 ] ) {
728 $c->log->warn( qq(Found results for "${name}" using regexp fallback.) );
729 $c->log->warn( 'Relying on the regexp fallback behavior for component resolution' );
730 $c->log->warn( 'is unreliable and unsafe. You have been warned' );
731 return $c->_filter_component( $result[ 0 ], @args );
732 }
733
734 # I would expect to return an empty list here, but that breaks back-compat
b4b01a8a 735 }
736
2f381252 737 # fallback
b4b01a8a 738 return sort keys %{ $c->components };
739}
740
b4b01a8a 741=head2 CLASS DATA AND HELPER CLASSES
fbcc39ad 742
b5ecfcf0 743=head2 $c->config
fbcc39ad 744
0ef52a96 745Returns or takes a hashref containing the application's configuration.
746
61b1d329 747 __PACKAGE__->config( { db => 'dsn:SQLite:foo.db' } );
81557adf 748
cc95842f 749You can also use a C<YAML>, C<XML> or C<Config::General> config file
750like myapp.yml in your applications home directory. See
751L<Catalyst::Plugin::ConfigLoader>.
a6ad13b6 752
753 ---
754 db: dsn:SQLite:foo.db
755
b4b01a8a 756
3643e890 757=cut
758
4090e3bb 759around config => sub {
760 my $orig = shift;
3643e890 761 my $c = shift;
762
763 $c->log->warn("Setting config after setup has been run is not a good idea.")
764 if ( @_ and $c->setup_finished );
765
4090e3bb 766 $c->$orig(@_);
767};
3643e890 768
b5ecfcf0 769=head2 $c->log
0ef52a96 770
86418559 771Returns the logging object instance. Unless it is already set, Catalyst
772sets this up with a L<Catalyst::Log> object. To use your own log class,
773set the logger with the C<< __PACKAGE__->log >> method prior to calling
9e7673af 774C<< __PACKAGE__->setup >>.
775
776 __PACKAGE__->log( MyLogger->new );
777 __PACKAGE__->setup;
778
779And later:
0ef52a96 780
ae1e6b59 781 $c->log->info( 'Now logging with my own logger!' );
0ef52a96 782
86418559 783Your log class should implement the methods described in
784L<Catalyst::Log>.
af3ff00e 785
b4b01a8a 786
787=head2 $c->debug
788
789Overload to enable debug messages (same as -Debug option).
790
e80e8542 791Note that this is a static method, not an accessor and should be overloaded
792by declaring "sub debug { 1 }" in your MyApp.pm, not by calling $c->debug(1).
793
af3ff00e 794=cut
795
b4b01a8a 796sub debug { 0 }
797
798=head2 $c->dispatcher
799
800Returns the dispatcher instance. Stringifies to class name. See
801L<Catalyst::Dispatcher>.
802
803=head2 $c->engine
804
805Returns the engine instance. Stringifies to the class name. See
806L<Catalyst::Engine>.
807
808
f7b672ef 809=head2 UTILITY METHODS
66e28e3f 810
b5ecfcf0 811=head2 $c->path_to(@path)
01033d73 812
cc95842f 813Merges C<@path> with C<< $c->config->{home} >> and returns a
afbb9aa3 814L<Path::Class::Dir> object.
01033d73 815
816For example:
817
818 $c->path_to( 'db', 'sqlite.db' );
819
820=cut
821
822sub path_to {
823 my ( $c, @path ) = @_;
a738ab68 824 my $path = Path::Class::Dir->new( $c->config->{home}, @path );
01033d73 825 if ( -d $path ) { return $path }
a738ab68 826 else { return Path::Class::File->new( $c->config->{home}, @path ) }
01033d73 827}
828
b5ecfcf0 829=head2 $c->plugin( $name, $class, @args )
0ef52a96 830
ae1e6b59 831Helper method for plugins. It creates a classdata accessor/mutator and
832loads and instantiates the given class.
0ef52a96 833
834 MyApp->plugin( 'prototype', 'HTML::Prototype' );
835
836 $c->prototype->define_javascript_functions;
837
838=cut
839
840sub plugin {
841 my ( $class, $name, $plugin, @args ) = @_;
97b58e17 842 $class->_register_plugin( $plugin, 1 );
0ef52a96 843
844 eval { $plugin->import };
845 $class->mk_classdata($name);
846 my $obj;
847 eval { $obj = $plugin->new(@args) };
848
849 if ($@) {
850 Catalyst::Exception->throw( message =>
851 qq/Couldn't instantiate instant plugin "$plugin", "$@"/ );
852 }
853
854 $class->$name($obj);
855 $class->log->debug(qq/Initialized instant plugin "$plugin" as "$name"/)
856 if $class->debug;
857}
858
b5ecfcf0 859=head2 MyApp->setup
fbcc39ad 860
e7f1cf73 861Initializes the dispatcher and engine, loads any plugins, and loads the
ae1e6b59 862model, view, and controller components. You may also specify an array
863of plugins to load here, if you choose to not load them in the C<use
864Catalyst> line.
fbcc39ad 865
0ef52a96 866 MyApp->setup;
867 MyApp->setup( qw/-Debug/ );
fbcc39ad 868
869=cut
870
871sub setup {
0319a12c 872 my ( $class, @arguments ) = @_;
5168a5fc 873 $class->log->warn("Running setup twice is not a good idea.")
874 if ( $class->setup_finished );
875
fbcc39ad 876 unless ( $class->isa('Catalyst') ) {
953b0e15 877
fbcc39ad 878 Catalyst::Exception->throw(
879 message => qq/'$class' does not inherit from Catalyst/ );
1c99e125 880 }
0319a12c 881
fbcc39ad 882 if ( $class->arguments ) {
883 @arguments = ( @arguments, @{ $class->arguments } );
884 }
885
886 # Process options
887 my $flags = {};
888
889 foreach (@arguments) {
890
891 if (/^-Debug$/) {
892 $flags->{log} =
893 ( $flags->{log} ) ? 'debug,' . $flags->{log} : 'debug';
894 }
895 elsif (/^-(\w+)=?(.*)$/) {
896 $flags->{ lc $1 } = $2;
897 }
898 else {
899 push @{ $flags->{plugins} }, $_;
900 }
901 }
902
99f187d6 903 $class->setup_home( delete $flags->{home} );
904
fbcc39ad 905 $class->setup_log( delete $flags->{log} );
906 $class->setup_plugins( delete $flags->{plugins} );
907 $class->setup_dispatcher( delete $flags->{dispatcher} );
908 $class->setup_engine( delete $flags->{engine} );
dc5f035e 909 $class->setup_stats( delete $flags->{stats} );
fbcc39ad 910
911 for my $flag ( sort keys %{$flags} ) {
912
913 if ( my $code = $class->can( 'setup_' . $flag ) ) {
914 &$code( $class, delete $flags->{$flag} );
915 }
916 else {
917 $class->log->warn(qq/Unknown flag "$flag"/);
918 }
919 }
920
0eb4af72 921 eval { require Catalyst::Devel; };
922 if( !$@ && $ENV{CATALYST_SCRIPT_GEN} && ( $ENV{CATALYST_SCRIPT_GEN} < $Catalyst::Devel::CATALYST_SCRIPT_GEN ) ) {
923 $class->log->warn(<<"EOF");
4ff0d824 924You are running an old script!
925
34a83d89 926 Please update by running (this will overwrite existing files):
927 catalyst.pl -force -scripts $class
928
929 or (this will not overwrite existing files):
930 catalyst.pl -scripts $class
1cf0345b 931
4ff0d824 932EOF
0eb4af72 933 }
ac5c933b 934
fbcc39ad 935 if ( $class->debug ) {
6601f2ad 936 my @plugins = map { "$_ " . ( $_->VERSION || '' ) } $class->registered_plugins;
fbcc39ad 937
938 if (@plugins) {
34d28dfd 939 my $t = Text::SimpleTable->new(74);
8c113188 940 $t->row($_) for @plugins;
1cf0345b 941 $class->log->debug( "Loaded plugins:\n" . $t->draw . "\n" );
fbcc39ad 942 }
943
944 my $dispatcher = $class->dispatcher;
945 my $engine = $class->engine;
946 my $home = $class->config->{home};
947
948 $class->log->debug(qq/Loaded dispatcher "$dispatcher"/);
949 $class->log->debug(qq/Loaded engine "$engine"/);
950
951 $home
952 ? ( -d $home )
953 ? $class->log->debug(qq/Found home "$home"/)
954 : $class->log->debug(qq/Home "$home" doesn't exist/)
955 : $class->log->debug(q/Couldn't find home/);
956 }
957
958 # Call plugins setup
959 {
960 no warnings qw/redefine/;
961 local *setup = sub { };
962 $class->setup;
963 }
964
965 # Initialize our data structure
966 $class->components( {} );
967
968 $class->setup_components;
969
970 if ( $class->debug ) {
34d28dfd 971 my $t = Text::SimpleTable->new( [ 63, 'Class' ], [ 8, 'Type' ] );
684d10ed 972 for my $comp ( sort keys %{ $class->components } ) {
973 my $type = ref $class->components->{$comp} ? 'instance' : 'class';
974 $t->row( $comp, $type );
975 }
1cf0345b 976 $class->log->debug( "Loaded components:\n" . $t->draw . "\n" )
8c113188 977 if ( keys %{ $class->components } );
fbcc39ad 978 }
979
980 # Add our self to components, since we are also a component
96d8d513 981 if( $class->isa('Catalyst::Controller') ){
982 $class->components->{$class} = $class;
983 }
fbcc39ad 984
985 $class->setup_actions;
986
987 if ( $class->debug ) {
988 my $name = $class->config->{name} || 'Application';
989 $class->log->info("$name powered by Catalyst $Catalyst::VERSION");
990 }
991 $class->log->_flush() if $class->log->can('_flush');
3643e890 992
993 $class->setup_finished(1);
fbcc39ad 994}
995
73664287 996=head2 $c->uri_for( $path, @args?, \%query_values? )
fbcc39ad 997
c50f595c 998Merges path with C<< $c->request->base >> for absolute URIs and with
999C<< $c->namespace >> for relative URIs, then returns a normalized L<URI>
86418559 1000object. If any args are passed, they are added at the end of the path.
1001If the last argument to C<uri_for> is a hash reference, it is assumed to
1002contain GET parameter key/value pairs, which will be appended to the URI
1003in standard fashion.
fbcc39ad 1004
8dc69021 1005Note that uri_for is destructive to the passed hashref. Subsequent calls
1006with the same hashref may have unintended results.
1007
86418559 1008Instead of C<$path>, you can also optionally pass a C<$action> object
1009which will be resolved to a path using
147869cd 1010C<< $c->dispatcher->uri_for_action >>; if the first element of
86418559 1011C<@args> is an arrayref it is treated as a list of captures to be passed
1012to C<uri_for_action>.
ea0e58d9 1013
fbcc39ad 1014=cut
1015
1016sub uri_for {
00e6a2b7 1017 my ( $c, $path, @args ) = @_;
00e6a2b7 1018
ea0e58d9 1019 if ( Scalar::Util::blessed($path) ) { # action object
1020 my $captures = ( scalar @args && ref $args[0] eq 'ARRAY'
1021 ? shift(@args)
1022 : [] );
1023 $path = $c->dispatcher->uri_for_action($path, $captures);
1024 return undef unless defined($path);
81e75875 1025 $path = '/' if $path eq '';
ea0e58d9 1026 }
1027
51674a63 1028 undef($path) if (defined $path && $path eq '');
00e6a2b7 1029
97b58e17 1030 my $params =
1031 ( scalar @args && ref $args[$#args] eq 'HASH' ? pop @args : {} );
8327e2e2 1032
cbb93105 1033 carp "uri_for called with undef argument" if grep { ! defined $_ } @args;
51674a63 1034 s/([^$URI::uric])/$URI::Escape::escapes{$1}/go for @args;
1035
1036 unshift(@args, $path);
1037
1038 unless (defined $path && $path =~ s!^/!!) { # in-place strip
1039 my $namespace = $c->namespace;
1040 if (defined $path) { # cheesy hack to handle path '../foo'
1041 $namespace =~ s{(?:^|/)[^/]+$}{} while $args[0] =~ s{^\.\./}{};
6601f2ad 1042 }
51674a63 1043 unshift(@args, $namespace || '');
1044 }
ac5c933b 1045
189e2a51 1046 # join args with '/', or a blank string
51674a63 1047 my $args = join('/', grep { defined($_) } @args);
1048 $args =~ s/\?/%3F/g; # STUPID STUPID SPECIAL CASE
1049 $args =~ s!^/!!;
1050 my $base = $c->req->base;
1051 my $class = ref($base);
1052 $base =~ s{(?<!/)$}{/};
1053
1054 my $query = '';
1055
1056 if (my @keys = keys %$params) {
1057 # somewhat lifted from URI::_query's query_form
1058 $query = '?'.join('&', map {
2f381252 1059 my $val = $params->{$_};
51674a63 1060 s/([;\/?:@&=+,\$\[\]%])/$URI::Escape::escapes{$1}/go;
1061 s/ /+/g;
1062 my $key = $_;
51674a63 1063 $val = '' unless defined $val;
1064 (map {
1065 $_ = "$_";
0ce485e9 1066 utf8::encode( $_ ) if utf8::is_utf8($_);
51674a63 1067 # using the URI::Escape pattern here so utf8 chars survive
1068 s/([^A-Za-z0-9\-_.!~*'() ])/$URI::Escape::escapes{$1}/go;
1069 s/ /+/g;
1070 "${key}=$_"; } ( ref $val eq 'ARRAY' ? @$val : $val ));
1071 } @keys);
1072 }
1073
1074 my $res = bless(\"${base}${args}${query}", $class);
d3e7a648 1075 $res;
fbcc39ad 1076}
1077
b5ecfcf0 1078=head2 $c->welcome_message
ab2374d3 1079
1080Returns the Catalyst welcome HTML page.
1081
1082=cut
1083
1084sub welcome_message {
bf1f2c60 1085 my $c = shift;
1086 my $name = $c->config->{name};
1087 my $logo = $c->uri_for('/static/images/catalyst_logo.png');
1088 my $prefix = Catalyst::Utils::appprefix( ref $c );
80cdbbff 1089 $c->response->content_type('text/html; charset=utf-8');
ab2374d3 1090 return <<"EOF";
80cdbbff 1091<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
1092 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1093<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
ab2374d3 1094 <head>
85d9fce6 1095 <meta http-equiv="Content-Language" content="en" />
1096 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
ab2374d3 1097 <title>$name on Catalyst $VERSION</title>
1098 <style type="text/css">
1099 body {
ab2374d3 1100 color: #000;
1101 background-color: #eee;
1102 }
1103 div#content {
1104 width: 640px;
80cdbbff 1105 margin-left: auto;
1106 margin-right: auto;
ab2374d3 1107 margin-top: 10px;
1108 margin-bottom: 10px;
1109 text-align: left;
1110 background-color: #ccc;
1111 border: 1px solid #aaa;
ab2374d3 1112 }
d84c4dab 1113 p, h1, h2 {
ab2374d3 1114 margin-left: 20px;
1115 margin-right: 20px;
16215972 1116 font-family: verdana, tahoma, sans-serif;
ab2374d3 1117 }
d84c4dab 1118 a {
1119 font-family: verdana, tahoma, sans-serif;
1120 }
d114e033 1121 :link, :visited {
1122 text-decoration: none;
1123 color: #b00;
1124 border-bottom: 1px dotted #bbb;
1125 }
1126 :link:hover, :visited:hover {
d114e033 1127 color: #555;
1128 }
ab2374d3 1129 div#topbar {
1130 margin: 0px;
1131 }
3e82a295 1132 pre {
3e82a295 1133 margin: 10px;
1134 padding: 8px;
1135 }
ab2374d3 1136 div#answers {
1137 padding: 8px;
1138 margin: 10px;
d114e033 1139 background-color: #fff;
ab2374d3 1140 border: 1px solid #aaa;
ab2374d3 1141 }
1142 h1 {
33108eaf 1143 font-size: 0.9em;
1144 font-weight: normal;
ab2374d3 1145 text-align: center;
1146 }
1147 h2 {
1148 font-size: 1.0em;
1149 }
1150 p {
1151 font-size: 0.9em;
1152 }
ae7c5252 1153 p img {
1154 float: right;
1155 margin-left: 10px;
1156 }
9619f23c 1157 span#appname {
1158 font-weight: bold;
33108eaf 1159 font-size: 1.6em;
ab2374d3 1160 }
1161 </style>
1162 </head>
1163 <body>
1164 <div id="content">
1165 <div id="topbar">
9619f23c 1166 <h1><span id="appname">$name</span> on <a href="http://catalyst.perl.org">Catalyst</a>
d84c4dab 1167 $VERSION</h1>
ab2374d3 1168 </div>
1169 <div id="answers">
ae7c5252 1170 <p>
80cdbbff 1171 <img src="$logo" alt="Catalyst Logo" />
ae7c5252 1172 </p>
596aaffe 1173 <p>Welcome to the world of Catalyst.
f92fd545 1174 This <a href="http://en.wikipedia.org/wiki/MVC">MVC</a>
1175 framework will make web development something you had
60dd6e1d 1176 never expected it to be: Fun, rewarding, and quick.</p>
ab2374d3 1177 <h2>What to do now?</h2>
4b8cb778 1178 <p>That really depends on what <b>you</b> want to do.
ab2374d3 1179 We do, however, provide you with a few starting points.</p>
1180 <p>If you want to jump right into web development with Catalyst
2f381252 1181 you might want to start with a tutorial.</p>
b607f8a0 1182<pre>perldoc <a href="http://cpansearch.perl.org/dist/Catalyst-Manual/lib/Catalyst/Manual/Tutorial.pod">Catalyst::Manual::Tutorial</a></code>
596aaffe 1183</pre>
1184<p>Afterwards you can go on to check out a more complete look at our features.</p>
1185<pre>
b607f8a0 1186<code>perldoc <a href="http://cpansearch.perl.org/dist/Catalyst-Manual/lib/Catalyst/Manual/Intro.pod">Catalyst::Manual::Intro</a>
1187<!-- Something else should go here, but the Catalyst::Manual link seems unhelpful -->
1188</code></pre>
ab2374d3 1189 <h2>What to do next?</h2>
f5681c92 1190 <p>Next it's time to write an actual application. Use the
80cdbbff 1191 helper scripts to generate <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AController%3A%3A&amp;mode=all">controllers</a>,
60dd6e1d 1192 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AModel%3A%3A&amp;mode=all">models</a>, and
1193 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AView%3A%3A&amp;mode=all">views</a>;
bf1f2c60 1194 they can save you a lot of work.</p>
1195 <pre><code>script/${prefix}_create.pl -help</code></pre>
1196 <p>Also, be sure to check out the vast and growing
60dd6e1d 1197 collection of <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3APlugin%3A%3A&amp;mode=all">plugins for Catalyst on CPAN</a>;
bf1f2c60 1198 you are likely to find what you need there.
f5681c92 1199 </p>
1200
82245cc4 1201 <h2>Need help?</h2>
f5681c92 1202 <p>Catalyst has a very active community. Here are the main places to
1203 get in touch with us.</p>
16215972 1204 <ul>
1205 <li>
2b9a7d76 1206 <a href="http://dev.catalyst.perl.org">Wiki</a>
16215972 1207 </li>
1208 <li>
1209 <a href="http://lists.rawmode.org/mailman/listinfo/catalyst">Mailing-List</a>
1210 </li>
1211 <li>
4eaf7c88 1212 <a href="irc://irc.perl.org/catalyst">IRC channel #catalyst on irc.perl.org</a>
16215972 1213 </li>
1214 </ul>
ab2374d3 1215 <h2>In conclusion</h2>
ac5c933b 1216 <p>The Catalyst team hopes you will enjoy using Catalyst as much
f5681c92 1217 as we enjoyed making it. Please contact us if you have ideas
1218 for improvement or other feedback.</p>
ab2374d3 1219 </div>
1220 </div>
1221 </body>
1222</html>
1223EOF
1224}
1225
fbcc39ad 1226=head1 INTERNAL METHODS
1227
ae1e6b59 1228These methods are not meant to be used by end users.
1229
b5ecfcf0 1230=head2 $c->components
fbcc39ad 1231
e7f1cf73 1232Returns a hash of components.
fbcc39ad 1233
b5ecfcf0 1234=head2 $c->context_class
1f9cb7c1 1235
e7f1cf73 1236Returns or sets the context class.
1f9cb7c1 1237
b5ecfcf0 1238=head2 $c->counter
fbcc39ad 1239
ae1e6b59 1240Returns a hashref containing coderefs and execution counts (needed for
1241deep recursion detection).
fbcc39ad 1242
b5ecfcf0 1243=head2 $c->depth
fbcc39ad 1244
e7f1cf73 1245Returns the number of actions on the current internal execution stack.
fbcc39ad 1246
b5ecfcf0 1247=head2 $c->dispatch
fbcc39ad 1248
e7f1cf73 1249Dispatches a request to actions.
fbcc39ad 1250
1251=cut
1252
1253sub dispatch { my $c = shift; $c->dispatcher->dispatch( $c, @_ ) }
1254
b5ecfcf0 1255=head2 $c->dispatcher_class
1f9cb7c1 1256
e7f1cf73 1257Returns or sets the dispatcher class.
1f9cb7c1 1258
b5ecfcf0 1259=head2 $c->dump_these
7f92deef 1260
ae1e6b59 1261Returns a list of 2-element array references (name, structure) pairs
1262that will be dumped on the error page in debug mode.
7f92deef 1263
1264=cut
1265
1266sub dump_these {
1267 my $c = shift;
ac5c933b 1268 [ Request => $c->req ],
1269 [ Response => $c->res ],
052a2d89 1270 [ Stash => $c->stash ],
1271 [ Config => $c->config ];
7f92deef 1272}
1273
b5ecfcf0 1274=head2 $c->engine_class
1f9cb7c1 1275
e7f1cf73 1276Returns or sets the engine class.
1f9cb7c1 1277
b5ecfcf0 1278=head2 $c->execute( $class, $coderef )
fbcc39ad 1279
0ef52a96 1280Execute a coderef in given class and catch exceptions. Errors are available
1281via $c->error.
fbcc39ad 1282
1283=cut
1284
1285sub execute {
1286 my ( $c, $class, $code ) = @_;
858828dd 1287 $class = $c->component($class) || $class;
fbcc39ad 1288 $c->state(0);
a0eca838 1289
197bd788 1290 if ( $c->depth >= $RECURSION ) {
f3414019 1291 my $action = $code->reverse();
91d08727 1292 $action = "/$action" unless $action =~ /->/;
f3414019 1293 my $error = qq/Deep recursion detected calling "${action}"/;
1627551a 1294 $c->log->error($error);
1295 $c->error($error);
1296 $c->state(0);
1297 return $c->state;
1298 }
1299
dc5f035e 1300 my $stats_info = $c->_stats_start_execute( $code ) if $c->use_stats;
22247e54 1301
8767c5a3 1302 push( @{ $c->stack }, $code );
ac5c933b 1303
f3414019 1304 eval { $c->state( $code->execute( $class, $c, @{ $c->req->args } ) || 0 ) };
22247e54 1305
dc5f035e 1306 $c->_stats_finish_execute( $stats_info ) if $c->use_stats and $stats_info;
ac5c933b 1307
a6724a82 1308 my $last = pop( @{ $c->stack } );
fbcc39ad 1309
1310 if ( my $error = $@ ) {
2f381252 1311 if ( !ref($error) and $error eq $DETACH ) {
1312 die $DETACH if($c->depth > 1);
1313 }
1314 elsif ( !ref($error) and $error eq $GO ) {
1315 die $GO if($c->depth > 0);
1316 }
fbcc39ad 1317 else {
1318 unless ( ref $error ) {
91d08727 1319 no warnings 'uninitialized';
fbcc39ad 1320 chomp $error;
f59def82 1321 my $class = $last->class;
1322 my $name = $last->name;
1323 $error = qq/Caught exception in $class->$name "$error"/;
fbcc39ad 1324 }
fbcc39ad 1325 $c->error($error);
1326 $c->state(0);
1327 }
1328 }
1329 return $c->state;
1330}
1331
7a7d7af5 1332sub _stats_start_execute {
1333 my ( $c, $code ) = @_;
1334
a6724a82 1335 return if ( ( $code->name =~ /^_.*/ )
1336 && ( !$c->config->{show_internal_actions} ) );
7a7d7af5 1337
f3414019 1338 my $action_name = $code->reverse();
1339 $c->counter->{$action_name}++;
7a7d7af5 1340
f3414019 1341 my $action = $action_name;
a6724a82 1342 $action = "/$action" unless $action =~ /->/;
1343
7a7d7af5 1344 # determine if the call was the result of a forward
1345 # this is done by walking up the call stack and looking for a calling
1346 # sub of Catalyst::forward before the eval
1347 my $callsub = q{};
1348 for my $index ( 2 .. 11 ) {
1349 last
1350 if ( ( caller($index) )[0] eq 'Catalyst'
1351 && ( caller($index) )[3] eq '(eval)' );
1352
1353 if ( ( caller($index) )[3] =~ /forward$/ ) {
1354 $callsub = ( caller($index) )[3];
1355 $action = "-> $action";
1356 last;
1357 }
1358 }
1359
f3414019 1360 my $uid = $action_name . $c->counter->{$action_name};
74efc144 1361
a6724a82 1362 # is this a root-level call or a forwarded call?
1363 if ( $callsub =~ /forward$/ ) {
1364
1365 # forward, locate the caller
1366 if ( my $parent = $c->stack->[-1] ) {
69d8f33c 1367 $c->stats->profile(
ac5c933b 1368 begin => $action,
69d8f33c 1369 parent => "$parent" . $c->counter->{"$parent"},
1370 uid => $uid,
1371 );
7a7d7af5 1372 }
1373 else {
1374
a6724a82 1375 # forward with no caller may come from a plugin
69d8f33c 1376 $c->stats->profile(
1377 begin => $action,
1378 uid => $uid,
1379 );
7a7d7af5 1380 }
1381 }
a6724a82 1382 else {
ac5c933b 1383
a6724a82 1384 # root-level call
69d8f33c 1385 $c->stats->profile(
1386 begin => $action,
1387 uid => $uid,
1388 );
a6724a82 1389 }
dc5f035e 1390 return $action;
7a7d7af5 1391
7a7d7af5 1392}
1393
1394sub _stats_finish_execute {
1395 my ( $c, $info ) = @_;
69d8f33c 1396 $c->stats->profile( end => $info );
7a7d7af5 1397}
1398
3d0d6d21 1399=head2 $c->_localize_fields( sub { }, \%keys );
1400
1401=cut
1402
e63bdf38 1403#Why does this exist? This is no longer safe and WILL NOT WORK.
1404# it doesnt seem to be used anywhere. can we remove it?
3d0d6d21 1405sub _localize_fields {
1406 my ( $c, $localized, $code ) = ( @_ );
1407
1408 my $request = delete $localized->{request} || {};
1409 my $response = delete $localized->{response} || {};
ac5c933b 1410
3d0d6d21 1411 local @{ $c }{ keys %$localized } = values %$localized;
1412 local @{ $c->request }{ keys %$request } = values %$request;
1413 local @{ $c->response }{ keys %$response } = values %$response;
1414
1415 $code->();
1416}
1417
b5ecfcf0 1418=head2 $c->finalize
fbcc39ad 1419
e7f1cf73 1420Finalizes the request.
fbcc39ad 1421
1422=cut
1423
1424sub finalize {
1425 my $c = shift;
1426
369c09bc 1427 for my $error ( @{ $c->error } ) {
1428 $c->log->error($error);
1429 }
1430
5050d7a7 1431 # Allow engine to handle finalize flow (for POE)
e63bdf38 1432 my $engine = $c->engine;
1433 if ( my $code = $engine->can('finalize') ) {
1434 $engine->$code($c);
fbcc39ad 1435 }
5050d7a7 1436 else {
fbcc39ad 1437
5050d7a7 1438 $c->finalize_uploads;
fbcc39ad 1439
5050d7a7 1440 # Error
1441 if ( $#{ $c->error } >= 0 ) {
1442 $c->finalize_error;
1443 }
1444
1445 $c->finalize_headers;
fbcc39ad 1446
5050d7a7 1447 # HEAD request
1448 if ( $c->request->method eq 'HEAD' ) {
1449 $c->response->body('');
1450 }
1451
1452 $c->finalize_body;
1453 }
ac5c933b 1454
1455 if ($c->use_stats) {
596677b6 1456 my $elapsed = sprintf '%f', $c->stats->elapsed;
12bf12c0 1457 my $av = $elapsed == 0 ? '??' : sprintf '%.3f', 1 / $elapsed;
908e3d9e 1458 $c->log->info(
ac5c933b 1459 "Request took ${elapsed}s ($av/s)\n" . $c->stats->report . "\n" );
908e3d9e 1460 }
fbcc39ad 1461
1462 return $c->response->status;
1463}
1464
b5ecfcf0 1465=head2 $c->finalize_body
fbcc39ad 1466
e7f1cf73 1467Finalizes body.
fbcc39ad 1468
1469=cut
1470
1471sub finalize_body { my $c = shift; $c->engine->finalize_body( $c, @_ ) }
1472
b5ecfcf0 1473=head2 $c->finalize_cookies
fbcc39ad 1474
e7f1cf73 1475Finalizes cookies.
fbcc39ad 1476
1477=cut
1478
147821ea 1479sub finalize_cookies { my $c = shift; $c->engine->finalize_cookies( $c, @_ ) }
fbcc39ad 1480
b5ecfcf0 1481=head2 $c->finalize_error
fbcc39ad 1482
e7f1cf73 1483Finalizes error.
fbcc39ad 1484
1485=cut
1486
1487sub finalize_error { my $c = shift; $c->engine->finalize_error( $c, @_ ) }
1488
b5ecfcf0 1489=head2 $c->finalize_headers
fbcc39ad 1490
e7f1cf73 1491Finalizes headers.
fbcc39ad 1492
1493=cut
1494
1495sub finalize_headers {
1496 my $c = shift;
1497
e63bdf38 1498 my $response = $c->response; #accessor calls can add up?
1499
fbcc39ad 1500 # Check if we already finalized headers
6680c772 1501 return if $response->finalized_headers;
fbcc39ad 1502
1503 # Handle redirects
e63bdf38 1504 if ( my $location = $response->redirect ) {
fbcc39ad 1505 $c->log->debug(qq/Redirecting to "$location"/) if $c->debug;
e63bdf38 1506 $response->header( Location => $location );
a7caa492 1507
e63bdf38 1508 #Moose TODO: we should probably be using a predicate method here ?
1509 if ( !$response->body ) {
39655cdc 1510 # Add a default body if none is already present
e63bdf38 1511 $response->body(
e422816e 1512 qq{<html><body><p>This item has moved <a href="$location">here</a>.</p></body></html>}
39655cdc 1513 );
1514 }
fbcc39ad 1515 }
1516
1517 # Content-Length
e63bdf38 1518 if ( $response->body && !$response->content_length ) {
775878ac 1519
8f62c91a 1520 # get the length from a filehandle
e63bdf38 1521 if ( blessed( $response->body ) && $response->body->can('read') )
197bd788 1522 {
e63bdf38 1523 my $stat = stat $response->body;
3b6a1db1 1524 if ( $stat && $stat->size > 0 ) {
e63bdf38 1525 $response->content_length( $stat->size );
8f62c91a 1526 }
1527 else {
775878ac 1528 $c->log->warn('Serving filehandle without a content-length');
8f62c91a 1529 }
1530 }
1531 else {
b5d7a61f 1532 # everything should be bytes at this point, but just in case
e63bdf38 1533 $response->content_length( bytes::length( $response->body ) );
8f62c91a 1534 }
fbcc39ad 1535 }
1536
1537 # Errors
e63bdf38 1538 if ( $response->status =~ /^(1\d\d|[23]04)$/ ) {
1539 $response->headers->remove_header("Content-Length");
1540 $response->body('');
fbcc39ad 1541 }
1542
1543 $c->finalize_cookies;
1544
1545 $c->engine->finalize_headers( $c, @_ );
1546
1547 # Done
6680c772 1548 $response->finalized_headers(1);
fbcc39ad 1549}
1550
b5ecfcf0 1551=head2 $c->finalize_output
fbcc39ad 1552
1553An alias for finalize_body.
1554
b5ecfcf0 1555=head2 $c->finalize_read
fbcc39ad 1556
e7f1cf73 1557Finalizes the input after reading is complete.
fbcc39ad 1558
1559=cut
1560
1561sub finalize_read { my $c = shift; $c->engine->finalize_read( $c, @_ ) }
1562
b5ecfcf0 1563=head2 $c->finalize_uploads
fbcc39ad 1564
ae1e6b59 1565Finalizes uploads. Cleans up any temporary files.
fbcc39ad 1566
1567=cut
1568
1569sub finalize_uploads { my $c = shift; $c->engine->finalize_uploads( $c, @_ ) }
1570
b5ecfcf0 1571=head2 $c->get_action( $action, $namespace )
fbcc39ad 1572
e7f1cf73 1573Gets an action in a given namespace.
fbcc39ad 1574
1575=cut
1576
684d10ed 1577sub get_action { my $c = shift; $c->dispatcher->get_action(@_) }
fbcc39ad 1578
b5ecfcf0 1579=head2 $c->get_actions( $action, $namespace )
a9dc674c 1580
ae1e6b59 1581Gets all actions of a given name in a namespace and all parent
1582namespaces.
a9dc674c 1583
1584=cut
1585
1586sub get_actions { my $c = shift; $c->dispatcher->get_actions( $c, @_ ) }
1587
f7b672ef 1588=head2 $c->handle_request( $class, @arguments )
fbcc39ad 1589
e7f1cf73 1590Called to handle each HTTP request.
fbcc39ad 1591
1592=cut
1593
1594sub handle_request {
1595 my ( $class, @arguments ) = @_;
1596
1597 # Always expect worst case!
1598 my $status = -1;
1599 eval {
dea1884f 1600 if ($class->debug) {
908e3d9e 1601 my $secs = time - $START || 1;
1602 my $av = sprintf '%.3f', $COUNT / $secs;
1603 my $time = localtime time;
1604 $class->log->info("*** Request $COUNT ($av/s) [$$] [$time] ***");
dea1884f 1605 }
908e3d9e 1606
1607 my $c = $class->prepare(@arguments);
1608 $c->dispatch;
ac5c933b 1609 $status = $c->finalize;
fbcc39ad 1610 };
1611
1612 if ( my $error = $@ ) {
1613 chomp $error;
1614 $class->log->error(qq/Caught exception in engine "$error"/);
1615 }
1616
1617 $COUNT++;
6680c772 1618
1619 if(my $coderef = $class->log->can('_flush')){
1620 $class->log->$coderef();
1621 }
fbcc39ad 1622 return $status;
1623}
1624
b5ecfcf0 1625=head2 $c->prepare( @arguments )
fbcc39ad 1626
ae1e6b59 1627Creates a Catalyst context from an engine-specific request (Apache, CGI,
1628etc.).
fbcc39ad 1629
1630=cut
1631
1632sub prepare {
1633 my ( $class, @arguments ) = @_;
1634
6680c772 1635 # XXX
1636 # After the app/ctxt split, this should become an attribute based on something passed
1637 # into the application.
3cec521a 1638 $class->context_class( ref $class || $class ) unless $class->context_class;
6680c772 1639
1640 my $c = $class->context_class->new({});
1641
1642 # For on-demand data
1643 $c->request->_context($c);
1644 $c->response->_context($c);
fbcc39ad 1645
b6d4ee6e 1646 #surely this is not the most efficient way to do things...
dc5f035e 1647 $c->stats($class->stats_class->new)->enable($c->use_stats);
908e3d9e 1648 if ( $c->debug ) {
ac5c933b 1649 $c->res->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
908e3d9e 1650 }
1651
e63bdf38 1652 #XXX reuse coderef from can
5050d7a7 1653 # Allow engine to direct the prepare flow (for POE)
1654 if ( $c->engine->can('prepare') ) {
1655 $c->engine->prepare( $c, @arguments );
1656 }
1657 else {
1658 $c->prepare_request(@arguments);
1659 $c->prepare_connection;
1660 $c->prepare_query_parameters;
1661 $c->prepare_headers;
1662 $c->prepare_cookies;
1663 $c->prepare_path;
1664
878b821c 1665 # Prepare the body for reading, either by prepare_body
1666 # or the user, if they are using $c->read
1667 $c->prepare_read;
ac5c933b 1668
878b821c 1669 # Parse the body unless the user wants it on-demand
1670 unless ( $c->config->{parse_on_demand} ) {
1671 $c->prepare_body;
1672 }
5050d7a7 1673 }
fbcc39ad 1674
fbcc39ad 1675 my $method = $c->req->method || '';
2f381252 1676 my $path = $c->req->path;
1677 $path = '/' unless length $path;
fbcc39ad 1678 my $address = $c->req->address || '';
1679
e3a13771 1680 $c->log->debug(qq/"$method" request for "$path" from "$address"/)
fbcc39ad 1681 if $c->debug;
1682
e3a13771 1683 $c->prepare_action;
1684
fbcc39ad 1685 return $c;
1686}
1687
b5ecfcf0 1688=head2 $c->prepare_action
fbcc39ad 1689
b4b01a8a 1690Prepares action. See L<Catalyst::Dispatcher>.
fbcc39ad 1691
1692=cut
1693
1694sub prepare_action { my $c = shift; $c->dispatcher->prepare_action( $c, @_ ) }
1695
b5ecfcf0 1696=head2 $c->prepare_body
fbcc39ad 1697
e7f1cf73 1698Prepares message body.
fbcc39ad 1699
1700=cut
1701
1702sub prepare_body {
1703 my $c = shift;
1704
e63bdf38 1705 #Moose TODO: what is _body ??
fbcc39ad 1706 # Do we run for the first time?
1707 return if defined $c->request->{_body};
1708
1709 # Initialize on-demand data
1710 $c->engine->prepare_body( $c, @_ );
1711 $c->prepare_parameters;
1712 $c->prepare_uploads;
1713
1714 if ( $c->debug && keys %{ $c->req->body_parameters } ) {
34d28dfd 1715 my $t = Text::SimpleTable->new( [ 35, 'Parameter' ], [ 36, 'Value' ] );
fbcc39ad 1716 for my $key ( sort keys %{ $c->req->body_parameters } ) {
1717 my $param = $c->req->body_parameters->{$key};
1718 my $value = defined($param) ? $param : '';
8c113188 1719 $t->row( $key,
fbcc39ad 1720 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1721 }
1722 $c->log->debug( "Body Parameters are:\n" . $t->draw );
1723 }
1724}
1725
b5ecfcf0 1726=head2 $c->prepare_body_chunk( $chunk )
4bd82c41 1727
e7f1cf73 1728Prepares a chunk of data before sending it to L<HTTP::Body>.
4bd82c41 1729
b4b01a8a 1730See L<Catalyst::Engine>.
1731
4bd82c41 1732=cut
1733
4f5ebacd 1734sub prepare_body_chunk {
1735 my $c = shift;
4bd82c41 1736 $c->engine->prepare_body_chunk( $c, @_ );
1737}
1738
b5ecfcf0 1739=head2 $c->prepare_body_parameters
fbcc39ad 1740
e7f1cf73 1741Prepares body parameters.
fbcc39ad 1742
1743=cut
1744
1745sub prepare_body_parameters {
1746 my $c = shift;
1747 $c->engine->prepare_body_parameters( $c, @_ );
1748}
1749
b5ecfcf0 1750=head2 $c->prepare_connection
fbcc39ad 1751
e7f1cf73 1752Prepares connection.
fbcc39ad 1753
1754=cut
1755
1756sub prepare_connection {
1757 my $c = shift;
1758 $c->engine->prepare_connection( $c, @_ );
1759}
1760
b5ecfcf0 1761=head2 $c->prepare_cookies
fbcc39ad 1762
e7f1cf73 1763Prepares cookies.
fbcc39ad 1764
1765=cut
1766
1767sub prepare_cookies { my $c = shift; $c->engine->prepare_cookies( $c, @_ ) }
1768
b5ecfcf0 1769=head2 $c->prepare_headers
fbcc39ad 1770
e7f1cf73 1771Prepares headers.
fbcc39ad 1772
1773=cut
1774
1775sub prepare_headers { my $c = shift; $c->engine->prepare_headers( $c, @_ ) }
1776
b5ecfcf0 1777=head2 $c->prepare_parameters
fbcc39ad 1778
e7f1cf73 1779Prepares parameters.
fbcc39ad 1780
1781=cut
1782
1783sub prepare_parameters {
1784 my $c = shift;
1785 $c->prepare_body_parameters;
1786 $c->engine->prepare_parameters( $c, @_ );
1787}
1788
b5ecfcf0 1789=head2 $c->prepare_path
fbcc39ad 1790
e7f1cf73 1791Prepares path and base.
fbcc39ad 1792
1793=cut
1794
1795sub prepare_path { my $c = shift; $c->engine->prepare_path( $c, @_ ) }
1796
b5ecfcf0 1797=head2 $c->prepare_query_parameters
fbcc39ad 1798
e7f1cf73 1799Prepares query parameters.
fbcc39ad 1800
1801=cut
1802
1803sub prepare_query_parameters {
1804 my $c = shift;
1805
1806 $c->engine->prepare_query_parameters( $c, @_ );
1807
1808 if ( $c->debug && keys %{ $c->request->query_parameters } ) {
34d28dfd 1809 my $t = Text::SimpleTable->new( [ 35, 'Parameter' ], [ 36, 'Value' ] );
fbcc39ad 1810 for my $key ( sort keys %{ $c->req->query_parameters } ) {
1811 my $param = $c->req->query_parameters->{$key};
1812 my $value = defined($param) ? $param : '';
8c113188 1813 $t->row( $key,
fbcc39ad 1814 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1815 }
1816 $c->log->debug( "Query Parameters are:\n" . $t->draw );
1817 }
1818}
1819
b5ecfcf0 1820=head2 $c->prepare_read
fbcc39ad 1821
e7f1cf73 1822Prepares the input for reading.
fbcc39ad 1823
1824=cut
1825
1826sub prepare_read { my $c = shift; $c->engine->prepare_read( $c, @_ ) }
1827
b5ecfcf0 1828=head2 $c->prepare_request
fbcc39ad 1829
e7f1cf73 1830Prepares the engine request.
fbcc39ad 1831
1832=cut
1833
1834sub prepare_request { my $c = shift; $c->engine->prepare_request( $c, @_ ) }
1835
b5ecfcf0 1836=head2 $c->prepare_uploads
fbcc39ad 1837
e7f1cf73 1838Prepares uploads.
fbcc39ad 1839
1840=cut
1841
1842sub prepare_uploads {
1843 my $c = shift;
1844
1845 $c->engine->prepare_uploads( $c, @_ );
1846
1847 if ( $c->debug && keys %{ $c->request->uploads } ) {
8c113188 1848 my $t = Text::SimpleTable->new(
34d28dfd 1849 [ 12, 'Parameter' ],
1850 [ 26, 'Filename' ],
8c113188 1851 [ 18, 'Type' ],
1852 [ 9, 'Size' ]
1853 );
fbcc39ad 1854 for my $key ( sort keys %{ $c->request->uploads } ) {
1855 my $upload = $c->request->uploads->{$key};
1856 for my $u ( ref $upload eq 'ARRAY' ? @{$upload} : ($upload) ) {
8c113188 1857 $t->row( $key, $u->filename, $u->type, $u->size );
fbcc39ad 1858 }
1859 }
1860 $c->log->debug( "File Uploads are:\n" . $t->draw );
1861 }
1862}
1863
b5ecfcf0 1864=head2 $c->prepare_write
fbcc39ad 1865
e7f1cf73 1866Prepares the output for writing.
fbcc39ad 1867
1868=cut
1869
1870sub prepare_write { my $c = shift; $c->engine->prepare_write( $c, @_ ) }
1871
b5ecfcf0 1872=head2 $c->request_class
1f9cb7c1 1873
e7f1cf73 1874Returns or sets the request class.
1f9cb7c1 1875
b5ecfcf0 1876=head2 $c->response_class
1f9cb7c1 1877
e7f1cf73 1878Returns or sets the response class.
1f9cb7c1 1879
b5ecfcf0 1880=head2 $c->read( [$maxlength] )
fbcc39ad 1881
ae1e6b59 1882Reads a chunk of data from the request body. This method is designed to
1883be used in a while loop, reading C<$maxlength> bytes on every call.
1884C<$maxlength> defaults to the size of the request if not specified.
fbcc39ad 1885
cc95842f 1886You have to set C<< MyApp->config->{parse_on_demand} >> to use this
ae1e6b59 1887directly.
fbcc39ad 1888
878b821c 1889Warning: If you use read(), Catalyst will not process the body,
1890so you will not be able to access POST parameters or file uploads via
1891$c->request. You must handle all body parsing yourself.
1892
fbcc39ad 1893=cut
1894
1895sub read { my $c = shift; return $c->engine->read( $c, @_ ) }
1896
b5ecfcf0 1897=head2 $c->run
fbcc39ad 1898
1899Starts the engine.
1900
1901=cut
1902
1903sub run { my $c = shift; return $c->engine->run( $c, @_ ) }
1904
b5ecfcf0 1905=head2 $c->set_action( $action, $code, $namespace, $attrs )
fbcc39ad 1906
e7f1cf73 1907Sets an action in a given namespace.
fbcc39ad 1908
1909=cut
1910
1911sub set_action { my $c = shift; $c->dispatcher->set_action( $c, @_ ) }
1912
b5ecfcf0 1913=head2 $c->setup_actions($component)
fbcc39ad 1914
e7f1cf73 1915Sets up actions for a component.
fbcc39ad 1916
1917=cut
1918
1919sub setup_actions { my $c = shift; $c->dispatcher->setup_actions( $c, @_ ) }
1920
b5ecfcf0 1921=head2 $c->setup_components
fbcc39ad 1922
86418559 1923Sets up components. Specify a C<setup_components> config option to pass
1924additional options directly to L<Module::Pluggable>. To add additional
1925search paths, specify a key named C<search_extra> as an array
1926reference. Items in the array beginning with C<::> will have the
18de900e 1927application class name prepended to them.
fbcc39ad 1928
2f381252 1929All components found will also have any
1930L<Devel::InnerPackage|inner packages> loaded and set up as components.
1931Note, that modules which are B<not> an I<inner package> of the main
1932file namespace loaded will not be instantiated as components.
1933
fbcc39ad 1934=cut
1935
1936sub setup_components {
1937 my $class = shift;
1938
18de900e 1939 my @paths = qw( ::Controller ::C ::Model ::M ::View ::V );
1940 my $config = $class->config->{ setup_components };
1941 my $extra = delete $config->{ search_extra } || [];
ac5c933b 1942
18de900e 1943 push @paths, @$extra;
ac5c933b 1944
364d7324 1945 my $locator = Module::Pluggable::Object->new(
18de900e 1946 search_path => [ map { s/^(?=::)/$class/; $_; } @paths ],
1947 %$config
364d7324 1948 );
b94b200c 1949
1950 my @comps = sort { length $a <=> length $b } $locator->plugins;
1951 my %comps = map { $_ => 1 } @comps;
ac5c933b 1952
b94b200c 1953 for my $component ( @comps ) {
dd91afb5 1954
1955 # We pass ignore_loaded here so that overlay files for (e.g.)
1956 # Model::DBI::Schema sub-classes are loaded - if it's in @comps
1957 # we know M::P::O found a file on disk so this is safe
1958
f5a4863c 1959 Catalyst::Utils::ensure_class_loaded( $component, { ignore_loaded => 1 } );
1960 #Class::MOP::load_class($component);
364d7324 1961
1962 my $module = $class->setup_component( $component );
1963 my %modules = (
1964 $component => $module,
1965 map {
1966 $_ => $class->setup_component( $_ )
ac5c933b 1967 } grep {
b94b200c 1968 not exists $comps{$_}
364d7324 1969 } Devel::InnerPackage::list_packages( $component )
1970 );
ac5c933b 1971
364d7324 1972 for my $key ( keys %modules ) {
1973 $class->components->{ $key } = $modules{ $key };
fbcc39ad 1974 }
364d7324 1975 }
1976}
fbcc39ad 1977
364d7324 1978=head2 $c->setup_component
fbcc39ad 1979
364d7324 1980=cut
fbcc39ad 1981
364d7324 1982sub setup_component {
1983 my( $class, $component ) = @_;
fbcc39ad 1984
364d7324 1985 unless ( $component->can( 'COMPONENT' ) ) {
1986 return $component;
1987 }
fbcc39ad 1988
364d7324 1989 my $suffix = Catalyst::Utils::class2classsuffix( $component );
1990 my $config = $class->config->{ $suffix } || {};
fbcc39ad 1991
364d7324 1992 my $instance = eval { $component->COMPONENT( $class, $config ); };
fbcc39ad 1993
1994 if ( my $error = $@ ) {
fbcc39ad 1995 chomp $error;
fbcc39ad 1996 Catalyst::Exception->throw(
364d7324 1997 message => qq/Couldn't instantiate component "$component", "$error"/
1998 );
fbcc39ad 1999 }
2000
364d7324 2001 Catalyst::Exception->throw(
2002 message =>
2003 qq/Couldn't instantiate component "$component", "COMPONENT() didn't return an object-like value"/
84ff88cf 2004 ) unless blessed($instance);
364d7324 2005
2006 return $instance;
fbcc39ad 2007}
2008
b5ecfcf0 2009=head2 $c->setup_dispatcher
fbcc39ad 2010
ae1e6b59 2011Sets up dispatcher.
2012
fbcc39ad 2013=cut
2014
2015sub setup_dispatcher {
2016 my ( $class, $dispatcher ) = @_;
2017
2018 if ($dispatcher) {
2019 $dispatcher = 'Catalyst::Dispatcher::' . $dispatcher;
2020 }
2021
cb69249e 2022 if ( my $env = Catalyst::Utils::env_value( $class, 'DISPATCHER' ) ) {
2023 $dispatcher = 'Catalyst::Dispatcher::' . $env;
fbcc39ad 2024 }
2025
2026 unless ($dispatcher) {
cb0354c6 2027 $dispatcher = $class->dispatcher_class;
fbcc39ad 2028 }
2029
e63bdf38 2030 Class::MOP::load_class($dispatcher);
fbcc39ad 2031
2032 # dispatcher instance
2033 $class->dispatcher( $dispatcher->new );
2034}
2035
b5ecfcf0 2036=head2 $c->setup_engine
fbcc39ad 2037
ae1e6b59 2038Sets up engine.
2039
fbcc39ad 2040=cut
2041
2042sub setup_engine {
2043 my ( $class, $engine ) = @_;
2044
2045 if ($engine) {
2046 $engine = 'Catalyst::Engine::' . $engine;
2047 }
2048
cb69249e 2049 if ( my $env = Catalyst::Utils::env_value( $class, 'ENGINE' ) ) {
2050 $engine = 'Catalyst::Engine::' . $env;
fbcc39ad 2051 }
2052
9b0a3e0f 2053 if ( $ENV{MOD_PERL} ) {
fbcc39ad 2054
2055 # create the apache method
84ff88cf 2056 $class->meta->add_method('apache' => sub { shift->engine->apache });
fbcc39ad 2057
2058 my ( $software, $version ) =
2059 $ENV{MOD_PERL} =~ /^(\S+)\/(\d+(?:[\.\_]\d+)+)/;
2060
2061 $version =~ s/_//g;
2062 $version =~ s/(\.[^.]+)\./$1/g;
2063
2064 if ( $software eq 'mod_perl' ) {
2065
9b0a3e0f 2066 if ( !$engine ) {
22247e54 2067
9b0a3e0f 2068 if ( $version >= 1.99922 ) {
2069 $engine = 'Catalyst::Engine::Apache2::MP20';
2070 }
22247e54 2071
9b0a3e0f 2072 elsif ( $version >= 1.9901 ) {
2073 $engine = 'Catalyst::Engine::Apache2::MP19';
2074 }
22247e54 2075
9b0a3e0f 2076 elsif ( $version >= 1.24 ) {
2077 $engine = 'Catalyst::Engine::Apache::MP13';
2078 }
22247e54 2079
9b0a3e0f 2080 else {
2081 Catalyst::Exception->throw( message =>
2082 qq/Unsupported mod_perl version: $ENV{MOD_PERL}/ );
2083 }
fbcc39ad 2084
fbcc39ad 2085 }
2086
2087 # install the correct mod_perl handler
2088 if ( $version >= 1.9901 ) {
2089 *handler = sub : method {
2090 shift->handle_request(@_);
2091 };
2092 }
2093 else {
2094 *handler = sub ($$) { shift->handle_request(@_) };
2095 }
2096
2097 }
2098
2099 elsif ( $software eq 'Zeus-Perl' ) {
2100 $engine = 'Catalyst::Engine::Zeus';
2101 }
2102
2103 else {
2104 Catalyst::Exception->throw(
2105 message => qq/Unsupported mod_perl: $ENV{MOD_PERL}/ );
2106 }
2107 }
2108
2109 unless ($engine) {
cb0354c6 2110 $engine = $class->engine_class;
fbcc39ad 2111 }
2112
e63bdf38 2113 Class::MOP::load_class($engine);
2114 #unless (Class::Inspector->loaded($engine)) {
2115 # require Class::Inspector->filename($engine);
2116 #}
0e7f5826 2117
d54484bf 2118 # check for old engines that are no longer compatible
2119 my $old_engine;
0e7f5826 2120 if ( $engine->isa('Catalyst::Engine::Apache')
2121 && !Catalyst::Engine::Apache->VERSION )
d54484bf 2122 {
2123 $old_engine = 1;
2124 }
0e7f5826 2125
d54484bf 2126 elsif ( $engine->isa('Catalyst::Engine::Server::Base')
0e7f5826 2127 && Catalyst::Engine::Server->VERSION le '0.02' )
d54484bf 2128 {
2129 $old_engine = 1;
2130 }
0e7f5826 2131
2132 elsif ($engine->isa('Catalyst::Engine::HTTP::POE')
2133 && $engine->VERSION eq '0.01' )
d54484bf 2134 {
2135 $old_engine = 1;
2136 }
0e7f5826 2137
2138 elsif ($engine->isa('Catalyst::Engine::Zeus')
2139 && $engine->VERSION eq '0.01' )
d54484bf 2140 {
2141 $old_engine = 1;
2142 }
fbcc39ad 2143
d54484bf 2144 if ($old_engine) {
2145 Catalyst::Exception->throw( message =>
0e7f5826 2146 qq/Engine "$engine" is not supported by this version of Catalyst/
d54484bf 2147 );
2148 }
0e7f5826 2149
fbcc39ad 2150 # engine instance
2151 $class->engine( $engine->new );
2152}
2153
b5ecfcf0 2154=head2 $c->setup_home
fbcc39ad 2155
ae1e6b59 2156Sets up the home directory.
2157
fbcc39ad 2158=cut
2159
2160sub setup_home {
2161 my ( $class, $home ) = @_;
2162
cb69249e 2163 if ( my $env = Catalyst::Utils::env_value( $class, 'HOME' ) ) {
2164 $home = $env;
fbcc39ad 2165 }
2166
b6d4ee6e 2167 $home ||= Catalyst::Utils::home($class);
fbcc39ad 2168
2169 if ($home) {
e63bdf38 2170 #I remember recently being scolded for assigning config values like this
fbcc39ad 2171 $class->config->{home} ||= $home;
a738ab68 2172 $class->config->{root} ||= Path::Class::Dir->new($home)->subdir('root');
fbcc39ad 2173 }
2174}
2175
b5ecfcf0 2176=head2 $c->setup_log
fbcc39ad 2177
ae1e6b59 2178Sets up log.
2179
fbcc39ad 2180=cut
2181
2182sub setup_log {
2183 my ( $class, $debug ) = @_;
2184
2185 unless ( $class->log ) {
2186 $class->log( Catalyst::Log->new );
2187 }
af3ff00e 2188
cb69249e 2189 my $env_debug = Catalyst::Utils::env_value( $class, 'DEBUG' );
2190 if ( defined($env_debug) ? $env_debug : $debug ) {
84ff88cf 2191 $class->meta->add_method('debug' => sub { 1 });
fbcc39ad 2192 $class->log->debug('Debug messages enabled');
2193 }
2194}
2195
b5ecfcf0 2196=head2 $c->setup_plugins
fbcc39ad 2197
ae1e6b59 2198Sets up plugins.
2199
fbcc39ad 2200=cut
2201
dc5f035e 2202=head2 $c->setup_stats
2203
2204Sets up timing statistics class.
2205
2206=cut
2207
2208sub setup_stats {
2209 my ( $class, $stats ) = @_;
2210
2211 Catalyst::Utils::ensure_class_loaded($class->stats_class);
2212
2213 my $env = Catalyst::Utils::env_value( $class, 'STATS' );
2214 if ( defined($env) ? $env : ($stats || $class->debug ) ) {
84ff88cf 2215 $class->meta->add_method('use_stats' => sub { 1 });
b01f0c69 2216 $class->log->debug('Statistics enabled');
dc5f035e 2217 }
2218}
2219
2220
ac5c933b 2221=head2 $c->registered_plugins
836e1134 2222
2223Returns a sorted list of the plugins which have either been stated in the
2224import list or which have been added via C<< MyApp->plugin(@args); >>.
2225
2226If passed a given plugin name, it will report a boolean value indicating
2227whether or not that plugin is loaded. A fully qualified name is required if
2228the plugin name does not begin with C<Catalyst::Plugin::>.
2229
2230 if ($c->registered_plugins('Some::Plugin')) {
2231 ...
2232 }
2233
2234=cut
fbcc39ad 2235
836e1134 2236{
97b58e17 2237
2238 sub registered_plugins {
836e1134 2239 my $proto = shift;
197bd788 2240 return sort keys %{ $proto->_plugins } unless @_;
836e1134 2241 my $plugin = shift;
d0d4d785 2242 return 1 if exists $proto->_plugins->{$plugin};
2243 return exists $proto->_plugins->{"Catalyst::Plugin::$plugin"};
836e1134 2244 }
fbcc39ad 2245
836e1134 2246 sub _register_plugin {
2247 my ( $proto, $plugin, $instant ) = @_;
2248 my $class = ref $proto || $proto;
fbcc39ad 2249
dd91afb5 2250 # no ignore_loaded here, the plugin may already have been
2251 # defined in memory and we don't want to error on "no file" if so
2252
b6d4ee6e 2253 Class::MOP::load_class( $plugin );
fbcc39ad 2254
197bd788 2255 $proto->_plugins->{$plugin} = 1;
836e1134 2256 unless ($instant) {
fbcc39ad 2257 no strict 'refs';
5fb67d52 2258 if( $class->can('meta') ){
2259 my @superclasses = ($plugin, $class->meta->superclasses );
2260 $class->meta->superclasses(@superclasses);
2261 } else {
2262 unshift @{"$class\::ISA"}, $plugin;
2263 }
fbcc39ad 2264 }
836e1134 2265 return $class;
2266 }
2267
2268 sub setup_plugins {
2269 my ( $class, $plugins ) = @_;
2270
d0d4d785 2271 $class->_plugins( {} ) unless $class->_plugins;
836e1134 2272 $plugins ||= [];
2273 for my $plugin ( reverse @$plugins ) {
2274
2275 unless ( $plugin =~ s/\A\+// ) {
2276 $plugin = "Catalyst::Plugin::$plugin";
2277 }
2278
2279 $class->_register_plugin($plugin);
2280 }
fbcc39ad 2281 }
2282}
2283
b5ecfcf0 2284=head2 $c->stack
8767c5a3 2285
86418559 2286Returns an arrayref of the internal execution stack (actions that are
2287currently executing).
8767c5a3 2288
dc5f035e 2289=head2 $c->stats_class
2290
2291Returns or sets the stats (timing statistics) class.
2292
2293=head2 $c->use_stats
2294
2295Returns 1 when stats collection is enabled. Stats collection is enabled
2296when the -Stats options is set, debug is on or when the <MYAPP>_STATS
2297environment variable is set.
2298
2299Note that this is a static method, not an accessor and should be overloaded
2300by declaring "sub use_stats { 1 }" in your MyApp.pm, not by calling $c->use_stats(1).
2301
2302=cut
2303
2304sub use_stats { 0 }
2305
2306
b5ecfcf0 2307=head2 $c->write( $data )
fbcc39ad 2308
ae1e6b59 2309Writes $data to the output stream. When using this method directly, you
2310will need to manually set the C<Content-Length> header to the length of
2311your output data, if known.
fbcc39ad 2312
2313=cut
2314
4f5ebacd 2315sub write {
2316 my $c = shift;
2317
2318 # Finalize headers if someone manually writes output
2319 $c->finalize_headers;
2320
2321 return $c->engine->write( $c, @_ );
2322}
fbcc39ad 2323
b5ecfcf0 2324=head2 version
bf88a181 2325
ae1e6b59 2326Returns the Catalyst version number. Mostly useful for "powered by"
2327messages in template systems.
bf88a181 2328
2329=cut
2330
2331sub version { return $Catalyst::VERSION }
2332
b0bb11ec 2333=head1 INTERNAL ACTIONS
2334
ae1e6b59 2335Catalyst uses internal actions like C<_DISPATCH>, C<_BEGIN>, C<_AUTO>,
2336C<_ACTION>, and C<_END>. These are by default not shown in the private
3e705254 2337action table, but you can make them visible with a config parameter.
b0bb11ec 2338
2339 MyApp->config->{show_internal_actions} = 1;
2340
d2ee9760 2341=head1 CASE SENSITIVITY
2342
3e705254 2343By default Catalyst is not case sensitive, so C<MyApp::C::FOO::Bar> is
ae1e6b59 2344mapped to C</foo/bar>. You can activate case sensitivity with a config
3e705254 2345parameter.
d2ee9760 2346
2347 MyApp->config->{case_sensitive} = 1;
2348
3e705254 2349This causes C<MyApp::C::Foo::Bar> to map to C</Foo/Bar>.
fbcc39ad 2350
2351=head1 ON-DEMAND PARSER
2352
2353The request body is usually parsed at the beginning of a request,
878b821c 2354but if you want to handle input yourself, you can enable on-demand
2355parsing with a config parameter.
fbcc39ad 2356
2357 MyApp->config->{parse_on_demand} = 1;
ac5c933b 2358
fbcc39ad 2359=head1 PROXY SUPPORT
2360
ae1e6b59 2361Many production servers operate using the common double-server approach,
2362with a lightweight frontend web server passing requests to a larger
2363backend server. An application running on the backend server must deal
2364with two problems: the remote user always appears to be C<127.0.0.1> and
2365the server's hostname will appear to be C<localhost> regardless of the
2366virtual host that the user connected through.
fbcc39ad 2367
ae1e6b59 2368Catalyst will automatically detect this situation when you are running
2369the frontend and backend servers on the same machine. The following
2370changes are made to the request.
fbcc39ad 2371
ac5c933b 2372 $c->req->address is set to the user's real IP address, as read from
ae1e6b59 2373 the HTTP X-Forwarded-For header.
ac5c933b 2374
ae1e6b59 2375 The host value for $c->req->base and $c->req->uri is set to the real
2376 host, as read from the HTTP X-Forwarded-Host header.
fbcc39ad 2377
3e705254 2378Obviously, your web server must support these headers for this to work.
fbcc39ad 2379
ae1e6b59 2380In a more complex server farm environment where you may have your
2381frontend proxy server(s) on different machines, you will need to set a
2382configuration option to tell Catalyst to read the proxied data from the
2383headers.
fbcc39ad 2384
2385 MyApp->config->{using_frontend_proxy} = 1;
ac5c933b 2386
fbcc39ad 2387If you do not wish to use the proxy support at all, you may set:
d1a31ac6 2388
fbcc39ad 2389 MyApp->config->{ignore_frontend_proxy} = 1;
2390
2391=head1 THREAD SAFETY
2392
86418559 2393Catalyst has been tested under Apache 2's threading C<mpm_worker>,
2394C<mpm_winnt>, and the standalone forking HTTP server on Windows. We
2395believe the Catalyst core to be thread-safe.
fbcc39ad 2396
2397If you plan to operate in a threaded environment, remember that all other
3e705254 2398modules you are using must also be thread-safe. Some modules, most notably
2399L<DBD::SQLite>, are not thread-safe.
d1a31ac6 2400
3cb1db8c 2401=head1 SUPPORT
2402
2403IRC:
2404
4eaf7c88 2405 Join #catalyst on irc.perl.org.
3cb1db8c 2406
3e705254 2407Mailing Lists:
3cb1db8c 2408
2409 http://lists.rawmode.org/mailman/listinfo/catalyst
2410 http://lists.rawmode.org/mailman/listinfo/catalyst-dev
1985c30b 2411
432d507d 2412Web:
2413
2414 http://catalyst.perl.org
2415
0ef52a96 2416Wiki:
2417
2418 http://dev.catalyst.perl.org
2419
fc7ec1d9 2420=head1 SEE ALSO
2421
829a28ca 2422=head2 L<Task::Catalyst> - All you need to start with Catalyst
2423
b5ecfcf0 2424=head2 L<Catalyst::Manual> - The Catalyst Manual
e7f1cf73 2425
b5ecfcf0 2426=head2 L<Catalyst::Component>, L<Catalyst::Base> - Base classes for components
61b1e958 2427
b5ecfcf0 2428=head2 L<Catalyst::Engine> - Core engine
61b1e958 2429
b5ecfcf0 2430=head2 L<Catalyst::Log> - Log class.
61b1e958 2431
b5ecfcf0 2432=head2 L<Catalyst::Request> - Request object
61b1e958 2433
b5ecfcf0 2434=head2 L<Catalyst::Response> - Response object
61b1e958 2435
b5ecfcf0 2436=head2 L<Catalyst::Test> - The test suite.
fc7ec1d9 2437
2f381252 2438=head1 PROJECT FOUNDER
2439
2440sri: Sebastian Riedel <sri@cpan.org>
fc7ec1d9 2441
2f381252 2442=head1 CONTRIBUTORS
15f0b5b7 2443
2f381252 2444abw: Andy Wardley
fbcc39ad 2445
2f381252 2446acme: Leon Brocard <leon@astray.com>
33108eaf 2447
f4a57de4 2448Andrew Bramble
2449
15f0b5b7 2450Andrew Ford
2451
2452Andrew Ruthven
2453
2f381252 2454andyg: Andy Grundman <andy@hybridized.org>
fbcc39ad 2455
2f381252 2456audreyt: Audrey Tang
15f0b5b7 2457
2f381252 2458bricas: Brian Cassidy <bricas@cpan.org>
0cf56dbc 2459
2f381252 2460chansen: Christian Hansen
6aaa1c60 2461
2f381252 2462chicks: Christopher Hicks
15f0b5b7 2463
2f381252 2464dkubb: Dan Kubb <dan.kubb-cpan@onautopilot.com>
15f0b5b7 2465
2f381252 2466Drew Taylor
15f0b5b7 2467
2f381252 2468esskar: Sascha Kiefer
0ef52a96 2469
2f381252 2470fireartist: Carl Franks <cfranks@cpan.org>
15f0b5b7 2471
2f381252 2472gabb: Danijel Milicevic
61bef238 2473
15f0b5b7 2474Gary Ashton Jones
2475
2476Geoff Richards
2477
e4cc83b2 2478ilmari: Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>
2479
2f381252 2480jcamacho: Juan Camacho
fbcc39ad 2481
15f0b5b7 2482Jody Belka
2483
2484Johan Lindstrom
2485
2f381252 2486jon: Jon Schutz <jjschutz@cpan.org>
15f0b5b7 2487
2f381252 2488marcus: Marcus Ramberg <mramberg@cpan.org>
15f0b5b7 2489
2f381252 2490miyagawa: Tatsuhiko Miyagawa <miyagawa@bulknews.net>
15f0b5b7 2491
2f381252 2492mst: Matt S. Trout <mst@shadowcatsystems.co.uk>
15f0b5b7 2493
2f381252 2494mugwump: Sam Vilain
71c3bcc3 2495
2f381252 2496naughton: David Naughton
a727119f 2497
2f381252 2498ningu: David Kamholz <dkamholz@cpan.org>
1cf1c56a 2499
2f381252 2500nothingmuch: Yuval Kogman <nothingmuch@woobling.org>
9c71d51d 2501
2f381252 2502numa: Dan Sully <daniel@cpan.org>
fc7ec1d9 2503
2f381252 2504obra: Jesse Vincent
2505
2506omega: Andreas Marienborg
51f0308d 2507
2f381252 2508phaylon: Robert Sedlacek <phaylon@dunkelheit.at>
bdcb95ef 2509
6dae3eef 2510rafl: Florian Ragwitz <rafl@debian.org>
2511
2f381252 2512sky: Arthur Bergman
2513
2514the_jester: Jesse Sheidlower
2515
2516Ulf Edvinsson
51f0308d 2517
2f381252 2518willert: Sebastian Willert <willert@cpan.org>
51f0308d 2519
fc7ec1d9 2520=head1 LICENSE
2521
9ce5ab63 2522This library is free software, you can redistribute it and/or modify it under
41ca9ba7 2523the same terms as Perl itself.
fc7ec1d9 2524
2525=cut
2526
4090e3bb 2527no Moose;
2528
46d0346d 2529__PACKAGE__->meta->make_immutable;
2530
fc7ec1d9 25311;