X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCatalyst.pm;h=fc8f49e4ead14681ca2198f041774e9eccdada05;hb=a3b71f0f7e3a6debf22ce742c206f2c3d249c199;hp=5d3bfc767523201378189511bc68500cdc885c0e;hpb=a6724a82c19cdfa49866c6063634c77fd8ed2379;p=catagits%2FCatalyst-Runtime.git diff --git a/lib/Catalyst.pm b/lib/Catalyst.pm index 5d3bfc7..fc8f49e 100644 --- a/lib/Catalyst.pm +++ b/lib/Catalyst.pm @@ -12,13 +12,13 @@ use Catalyst::Utils; use Catalyst::Controller; use Devel::InnerPackage (); use File::stat; -use Module::Pluggable::Object; +use Module::Pluggable::Object (); use NEXT; -use Text::SimpleTable; -use Path::Class::Dir; -use Path::Class::File; +use Text::SimpleTable (); +use Path::Class::Dir (); +use Path::Class::File (); use Time::HiRes qw/gettimeofday tv_interval/; -use URI; +use URI (); use Scalar::Util qw/weaken blessed/; use Tree::Simple qw/use_weak_refs/; use Tree::Simple::Visitor::FindByUID; @@ -61,7 +61,7 @@ __PACKAGE__->response_class('Catalyst::Response'); # Remember to update this in Catalyst::Runtime as well! -our $VERSION = '5.70_03'; +our $VERSION = '5.7003'; sub import { my ( $class, @arguments ) = @_; @@ -87,6 +87,7 @@ Catalyst - The Elegant MVC Web Application Framework =head1 SYNOPSIS + # Install Catalyst::Devel for helpers and other development tools # use the helper to create a new application catalyst.pl MyApp @@ -171,7 +172,10 @@ See L for additional information. =head1 DESCRIPTION -Catalyst is a modern framework for making web applications without the pain usually associated with this process. This document is a reference to the main Catalyst application. If you are a new user, we suggest you start with L or L +Catalyst is a modern framework for making web applications without the +pain usually associated with this process. This document is a reference +to the main Catalyst application. If you are a new user, we suggest you +start with L or L. See L for more documentation. @@ -196,15 +200,16 @@ arguments when Catalyst is loaded: use Catalyst qw/-Debug My::Module/; The position of plugins and flags in the chain is important, because -they are loaded in exactly the order in which they appear. +they are loaded in the order in which they appear. The following flags are supported: =head2 -Debug Enables debug output. You can also force this setting from the system -environment with CATALYST_DEBUG or _DEBUG. The environment settings -override the app, with _DEBUG having highest priority. +environment with CATALYST_DEBUG or _DEBUG. The environment +settings override the application, with _DEBUG having the highest +priority. =head2 -Engine @@ -217,7 +222,7 @@ C prefix of the engine name, i.e.: Forces Catalyst to use a specific home directory, e.g.: - use Catalyst qw[-Home=/usr/sri]; + use Catalyst qw[-Home=/usr/mst]; =head2 -Log @@ -234,7 +239,7 @@ stringifies to the action name. See L. =head2 $c->namespace -Returns the namespace of the current action, i.e., the uri prefix +Returns the namespace of the current action, i.e., the URI prefix corresponding to the controller of the current action. For example: # in Controller::Foo::Bar @@ -244,8 +249,9 @@ corresponding to the controller of the current action. For example: =head2 $c->req -Returns the current L object. See -L. +Returns the current L object, giving access to +information about the current client request (including parameters, +cookies, HTTP headers, etc.). See L. =head2 REQUEST FLOW HANDLING @@ -253,7 +259,7 @@ L. =head2 $c->forward( $class, $method, [, \@arguments ] ) -Forwards processing to another action, by it's private name. If you give a +Forwards processing to another action, by its private name. If you give a class name but no method, C is called. You may also optionally pass arguments in an arrayref. The action will receive the arguments in C<@_> and C<$c-Ereq-Eargs>. Upon returning from the function, @@ -267,15 +273,15 @@ call to forward. $c->forward(qw/MyApp::Model::DBIC::Foo do_stuff/); $c->forward('MyApp::View::TT'); -Note that forward implies an C<> around the call (well, actually -C does), thus de-fatalizing all 'dies' within the called action. If -you want C to propagate you need to do something like: +Note that forward implies an C<> around the call (actually +C does), thus de-fatalizing all 'dies' within the called +action. If you want C to propagate you need to do something like: $c->forward('foo'); die $c->error if $c->error; -Or make sure to always return true values from your actions and write your code -like this: +Or make sure to always return true values from your actions and write +your code like this: $c->forward('foo') || return; @@ -287,9 +293,13 @@ sub forward { my $c = shift; $c->dispatcher->forward( $c, @_ ) } =head2 $c->detach( $class, $method, [, \@arguments ] ) +=head2 $c->detach() + The same as C, but doesn't return to the previous action when processing is finished. +When called with no arguments it escapes the processing chain entirely. + =cut sub detach { my $c = shift; $c->dispatcher->detach( $c, @_ ) } @@ -298,7 +308,7 @@ sub detach { my $c = shift; $c->dispatcher->detach( $c, @_ ) } =head2 $c->res -Returns the current L object. +Returns the current L object, q.v. =head2 $c->stash @@ -306,7 +316,9 @@ Returns a hashref to the stash, which may be used to store data and pass it between components during a request. You can also set hash keys by passing arguments. The stash is automatically sent to the view. The stash is cleared at the end of a request; it cannot be used for -persistent storage. +persistent storage (for this you must use a session; see +L for a complete system integrated with +Catalyst). $c->stash->{foo} = $bar; $c->stash( { moose => 'majestic', qux => 0 } ); @@ -380,8 +392,6 @@ sub clear_errors { } - - # search via regex sub _comp_search { my ( $c, @names ) = @_; @@ -472,7 +482,8 @@ Gets a L instance by name. $c->controller('Foo')->do_stuff; -If name is omitted, will return the controller for the dispatched action. +If the name is omitted, will return the controller for the dispatched +action. =cut @@ -490,8 +501,11 @@ Gets a L instance by name. $c->model('Foo')->do_stuff; -If the name is omitted, it will look for a config setting 'default_model', -or check if there is only one view, and return it if that's the case. +If the name is omitted, it will look for + - a model object in $c->stash{current_model_instance}, then + - a model name in $c->stash->{current_model}, then + - a config setting 'default_model', or + - check if there is only one model, and return it if that's the case. =cut @@ -500,8 +514,14 @@ sub model { return $c->_filter_component( $c->_comp_prefixes( $name, qw/Model M/ ), @args ) if $name; - return $c->component( $c->config->{default_model} ) - if $c->config->{default_model}; + if (ref $c) { + return $c->stash->{current_model_instance} + if $c->stash->{current_model_instance}; + return $c->model( $c->stash->{current_model} ) + if $c->stash->{current_model}; + return $c->model( $c->config->{default_model} ) + if $c->config->{default_model}; + } return $c->_filter_component( $c->_comp_singular(qw/Model M/), @args ); } @@ -524,8 +544,11 @@ Gets a L instance by name. $c->view('Foo')->do_stuff; -If the name is omitted, it will look for a config setting 'default_view', -or check if there is only one view, and forward to it if that's the case. +If the name is omitted, it will look for + - a view object in $c->stash{current_view_instance}, then + - a view name in $c->stash->{current_view}, then + - a config setting 'default_view', or + - check if there is only one view, and return it if that's the case. =cut @@ -534,8 +557,14 @@ sub view { return $c->_filter_component( $c->_comp_prefixes( $name, qw/View V/ ), @args ) if $name; - return $c->component( $c->config->{default_view} ) - if $c->config->{default_view}; + if (ref $c) { + return $c->stash->{current_view_instance} + if $c->stash->{current_view_instance}; + return $c->view( $c->stash->{current_view} ) + if $c->stash->{current_view}; + return $c->view( $c->config->{default_view} ) + if $c->config->{default_view}; + } return $c->_filter_component( $c->_comp_singular(qw/View V/) ); } @@ -628,9 +657,9 @@ sub config { =head2 $c->log -Returns the logging object instance. Unless it is already set, Catalyst sets -this up with a L object. To use your own log class, set the -logger with the C<< __PACKAGE__->log >> method prior to calling +Returns the logging object instance. Unless it is already set, Catalyst +sets this up with a L object. To use your own log class, +set the logger with the C<< __PACKAGE__->log >> method prior to calling C<< __PACKAGE__->setup >>. __PACKAGE__->log( MyLogger->new ); @@ -640,8 +669,8 @@ And later: $c->log->info( 'Now logging with my own logger!' ); -Your log class should implement the methods described in the -L man page. +Your log class should implement the methods described in +L. =head2 $c->debug @@ -852,17 +881,18 @@ EOF =head2 $c->uri_for( $path, @args?, \%query_values? ) -Merges path with C<$c-Erequest-Ebase> for absolute uri's and -with C<$c-Enamespace> for relative uri's, then returns a -normalized L object. If any args are passed, they are added at the -end of the path. If the last argument to uri_for is a hash reference, -it is assumed to contain GET parameter key/value pairs, which will be -appended to the URI in standard fashion. +Merges path with C<< $c->request->base >> for absolute URIs and with +C<< $c->namespace >> for relative URIs, then returns a normalized L +object. If any args are passed, they are added at the end of the path. +If the last argument to C is a hash reference, it is assumed to +contain GET parameter key/value pairs, which will be appended to the URI +in standard fashion. -Instead of $path, you can also optionally pass a $action object which will -be resolved to a path using $c->dispatcher->uri_for_action; if the first -element of @args is an arrayref it is treated as a list of captures to be -passed to uri_for_action. +Instead of C<$path>, you can also optionally pass a C<$action> object +which will be resolved to a path using +C<< $c->dispatcher->uri_for_action >>; if the first element of +C<@args> is an arrayref it is treated as a list of captures to be passed +to C. =cut @@ -880,6 +910,7 @@ sub uri_for { : [] ); $path = $c->dispatcher->uri_for_action($path, $captures); return undef unless defined($path); + $path = '/' if $path eq ''; } # massage namespace, empty if absolute path @@ -893,11 +924,10 @@ sub uri_for { ( scalar @args && ref $args[$#args] eq 'HASH' ? pop @args : {} ); for my $value ( values %$params ) { - my $isa_ref = ref $value; - if( $isa_ref and $isa_ref ne 'ARRAY' ) { - croak( "Non-array reference ($isa_ref) passed to uri_for()" ); + for ( ref $value eq 'ARRAY' ? @$value : $value ) { + $_ = "$_"; + utf8::encode( $_ ); } - utf8::encode( $_ ) for grep { defined } $isa_ref ? @$value : $value; }; # join args with '/', or a blank string @@ -1120,7 +1150,7 @@ sub execute { if ( $c->depth >= $RECURSION ) { my $action = "$code"; - $action = "/$action" unless $action =~ /\-\>/; + $action = "/$action" unless $action =~ /->/; my $error = qq/Deep recursion detected calling "$action"/; $c->log->error($error); $c->error($error); @@ -1139,9 +1169,10 @@ sub execute { my $last = pop( @{ $c->stack } ); if ( my $error = $@ ) { - if ( $error eq $DETACH ) { die $DETACH if $c->depth > 1 } + if ( !ref($error) and $error eq $DETACH ) { die $DETACH if $c->depth > 1 } else { unless ( ref $error ) { + no warnings 'uninitialized'; chomp $error; my $class = $last->class; my $name = $last->name; @@ -1223,10 +1254,8 @@ sub _stats_start_execute { sub _stats_finish_execute { my ( $c, $info ) = @_; - my ( $start, $node ) = @{ $info }{qw/start node/}; - - my $elapsed = tv_interval $start; - my $value = $node->getNodeValue; + my $elapsed = tv_interval $info->{start}; + my $value = $info->{node}->getNodeValue; $value->{elapsed} = sprintf( '%fs', $elapsed ); } @@ -1409,25 +1438,20 @@ sub handle_request { # Always expect worst case! my $status = -1; eval { - my $stats = ( $class->debug ) ? Tree::Simple->new: q{}; - - my $handler = sub { + if ($class->debug) { + my $start = [gettimeofday]; my $c = $class->prepare(@arguments); - $c->stats($stats); + $c->stats(Tree::Simple->new); $c->dispatch; - return $c->finalize; - }; + $status = $c->finalize; - if ( $class->debug ) { - my $start = [gettimeofday]; - $status = &$handler; my $elapsed = tv_interval $start; $elapsed = sprintf '%f', $elapsed; my $av = sprintf '%.3f', ( $elapsed == 0 ? '??' : ( 1 / $elapsed ) ); my $t = Text::SimpleTable->new( [ 62, 'Action' ], [ 9, 'Time' ] ); - $stats->traverse( + $c->stats->traverse( sub { my $action = shift; my $stat = $action->getNodeValue; @@ -1439,8 +1463,11 @@ sub handle_request { $class->log->info( "Request took ${elapsed}s ($av/s)\n" . $t->draw ); } - else { $status = &$handler } - + else { + my $c = $class->prepare(@arguments); + $c->dispatch; + $status = $c->finalize; + } }; if ( my $error = $@ ) { @@ -1766,9 +1793,10 @@ sub setup_actions { my $c = shift; $c->dispatcher->setup_actions( $c, @_ ) } =head2 $c->setup_components -Sets up components. Specify a C config option to pass additional options -directly to L. To add additional search paths, specify a key named -C as an array reference. Items in the array beginning with C<::> will have the +Sets up components. Specify a C config option to pass +additional options directly to L. To add additional +search paths, specify a key named C as an array +reference. Items in the array beginning with C<::> will have the application class name prepended to them. =cut @@ -1788,7 +1816,7 @@ sub setup_components { ); for my $component ( sort { length $a <=> length $b } $locator->plugins ) { - Catalyst::Utils::ensure_class_loaded( $component ); + Catalyst::Utils::ensure_class_loaded( $component, { ignore_loaded => 1 } ); my $module = $class->setup_component( $component ); my %modules = ( @@ -2112,8 +2140,8 @@ the plugin name does not begin with C. =head2 $c->stack -Returns an arrayref of the internal execution stack (actions that are currently -executing). +Returns an arrayref of the internal execution stack (actions that are +currently executing). =head2 $c->write( $data ) @@ -2201,9 +2229,9 @@ If you do not wish to use the proxy support at all, you may set: =head1 THREAD SAFETY -Catalyst has been tested under Apache 2's threading mpm_worker, mpm_winnt, -and the standalone forking HTTP server on Windows. We believe the Catalyst -core to be thread-safe. +Catalyst has been tested under Apache 2's threading C, +C, and the standalone forking HTTP server on Windows. We +believe the Catalyst core to be thread-safe. If you plan to operate in a threaded environment, remember that all other modules you are using must also be thread-safe. Some modules, most notably