X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Runtime.git;a=blobdiff_plain;f=lib%2FCatalyst.pm;h=a2cfa74346a369a1b19fbcaebf25a8c93051f179;hp=6ba42eb8a84dd47fc44ed457a1cbcf91fa27a879;hb=3a526ce8805d85f0214f134af2e0a4bb107dd2d4;hpb=4dcdaae144e5787f9efd4c72dce35cd97cc69288 diff --git a/lib/Catalyst.pm b/lib/Catalyst.pm index 6ba42eb..a2cfa74 100644 --- a/lib/Catalyst.pm +++ b/lib/Catalyst.pm @@ -38,7 +38,7 @@ use Plack::Middleware::ReverseProxy; use Plack::Middleware::IIS6ScriptNameFix; use Plack::Middleware::LighttpdScriptNameFix; -BEGIN { require 5.008004; } +BEGIN { require 5.008003; } has stack => (is => 'ro', default => sub { [] }); has stash => (is => 'rw', default => sub { {} }); @@ -46,8 +46,24 @@ has state => (is => 'rw', default => 0); has stats => (is => 'rw'); has action => (is => 'rw'); has counter => (is => 'rw', default => sub { {} }); -has request => (is => 'rw', default => sub { $_[0]->request_class->new({}) }, required => 1, lazy => 1); -has response => (is => 'rw', default => sub { $_[0]->response_class->new({}) }, required => 1, lazy => 1); +has request => ( + is => 'rw', + default => sub { + my $self = shift; + my %p = ( _log => $self->log ); + $p{_uploadtmp} = $self->_uploadtmp if $self->_has_uploadtmp; + $self->request_class->new(\%p); + }, + lazy => 1, +); +has response => ( + is => 'rw', + default => sub { + my $self = shift; + $self->response_class->new({ _log => $self->log }); + }, + lazy => 1, +); has namespace => (is => 'rw'); sub depth { scalar @{ shift->stack || [] }; } @@ -75,7 +91,7 @@ our $GO = Catalyst::Exception::Go->new; __PACKAGE__->mk_classdata($_) for qw/components arguments dispatcher engine log dispatcher_class engine_loader context_class request_class response_class stats_class - setup_finished _psgi_app loading_psgi_file/; + setup_finished _psgi_app loading_psgi_file run_options/; __PACKAGE__->dispatcher_class('Catalyst::Dispatcher'); __PACKAGE__->request_class('Catalyst::Request'); @@ -84,7 +100,7 @@ __PACKAGE__->stats_class('Catalyst::Stats'); # Remember to update this in Catalyst::Runtime as well! -our $VERSION = '5.90004'; +our $VERSION = '5.90011'; sub import { my ( $class, @arguments ) = @_; @@ -356,8 +372,12 @@ When called with no arguments it escapes the processing chain entirely. sub detach { my $c = shift; $c->dispatcher->detach( $c, @_ ) } +=head2 $c->visit( $action [, \@arguments ] ) + =head2 $c->visit( $action [, \@captures, \@arguments ] ) +=head2 $c->visit( $class, $method, [, \@arguments ] ) + =head2 $c->visit( $class, $method, [, \@captures, \@arguments ] ) Almost the same as L<< forward|/"$c->forward( $action [, \@arguments ] )" >>, @@ -386,8 +406,12 @@ transfer control to another action as if it had been reached directly from a URL sub visit { my $c = shift; $c->dispatcher->visit( $c, @_ ) } +=head2 $c->go( $action [, \@arguments ] ) + =head2 $c->go( $action [, \@captures, \@arguments ] ) +=head2 $c->go( $class, $method, [, \@arguments ] ) + =head2 $c->go( $class, $method, [, \@captures, \@arguments ] ) The relationship between C and @@ -1295,7 +1319,15 @@ sub uri_for { } my $action = $path; - $path = $c->dispatcher->uri_for_action($action, $captures); + # ->uri_for( $action, \@captures_and_args, \%query_values? ) + if( !@args && $action->number_of_args ) { + my $expanded_action = $c->dispatcher->expand_action( $action ); + + my $num_captures = $expanded_action->number_of_captures; + unshift @args, splice @$captures, $num_captures; + } + + $path = $c->dispatcher->uri_for_action($action, $captures); if (not defined $path) { $c->log->debug(qq/Can't find uri_for action '$action' @$captures/) if $c->debug; @@ -1346,9 +1378,9 @@ sub uri_for { $res; } -=head2 $c->uri_for_action( $path, \@captures?, @args?, \%query_values? ) +=head2 $c->uri_for_action( $path, \@captures_and_args?, @args?, \%query_values? ) -=head2 $c->uri_for_action( $action, \@captures?, @args?, \%query_values? ) +=head2 $c->uri_for_action( $action, \@captures_and_args?, @args?, \%query_values? ) =over @@ -1377,6 +1409,31 @@ You can use: and it will create the URI /users/the-list. +=item \@captures_and_args? + +Optional array reference of Captures (i.e. C<req->captures>) +and arguments to the request. Usually used with L +to interpolate all the parameters in the URI. + +=item @args? + +Optional list of extra arguments - can be supplied in the +C<< \@captures_and_args? >> array ref, or here - whichever is easier for your +code. + +Your action can have zero, a fixed or a variable number of args (e.g. +C<< Args(1) >> for a fixed number or C<< Args() >> for a variable number).. + +=item \%query_values? + +Optional array reference of query parameters to append. E.g. + + { foo => 'bar' } + +will generate + + /rest/of/your/uri?foo=bar + =back =cut @@ -1496,18 +1553,18 @@ sub welcome_message { We do, however, provide you with a few starting points.

If you want to jump right into web development with Catalyst you might want to start with a tutorial.

-
perldoc Catalyst::Manual::Tutorial
+
perldoc Catalyst::Manual::Tutorial
 

Afterwards you can go on to check out a more complete look at our features.

-perldoc Catalyst::Manual::Intro
+perldoc Catalyst::Manual::Intro
 
 

What to do next?

Next it's time to write an actual application. Use the - helper scripts to generate controllers, - models, and - views; + helper scripts to generate controllers, + models, and + views; they can save you a lot of work.

script/${prefix}_create.pl --help

Also, be sure to check out the vast and growing @@ -1540,6 +1597,16 @@ sub welcome_message { EOF } +=head2 run_options + +Contains a hash of options passed from the application script, including +the original ARGV the script received, the processed values from that +ARGV and any extra arguments to the script which were not processed. + +This can be used to add custom options to your application's scripts +and setup your application differently depending on the values of these +options. + =head1 INTERNAL METHODS These methods are not meant to be used by end users. @@ -1940,6 +2007,11 @@ etc.). =cut +has _uploadtmp => ( + is => 'ro', + predicate => '_has_uploadtmp', +); + sub prepare { my ( $class, @arguments ) = @_; @@ -1948,11 +2020,8 @@ sub prepare { # into the application. $class->context_class( ref $class || $class ) unless $class->context_class; - my $c = $class->context_class->new({}); - - # For on-demand data - $c->request->_context($c); - $c->response->_context($c); + my $uploadtmp = $class->config->{uploadtmp}; + my $c = $class->context_class->new({ $uploadtmp ? (_uploadtmp => $uploadtmp) : ()}); #surely this is not the most efficient way to do things... $c->stats($class->stats_class->new)->enable($c->use_stats); @@ -1969,8 +2038,8 @@ sub prepare { $c->prepare_request(@arguments); $c->prepare_connection; $c->prepare_query_parameters; - $c->prepare_headers; - $c->prepare_cookies; + $c->prepare_headers; # Just hooks, no longer needed - they just + $c->prepare_cookies; # cause the lazy attribute on req to build $c->prepare_path; # Prepare the body for reading, either by prepare_body @@ -1982,6 +2051,7 @@ sub prepare { $c->prepare_body; } } + $c->prepare_action; } # VERY ugly and probably shouldn't rely on ->finalize actually working catch { @@ -1989,19 +2059,19 @@ sub prepare { $c->response->status(400); $c->response->content_type('text/plain'); $c->response->body('Bad Request'); + # Note we call finalize and then die here, which escapes + # finalize being called in the enclosing block.. + # It in fact couldn't be called, as we don't return $c.. + # This is a mess - but I'm unsure you can fix this without + # breaking compat for people doing crazy things (we should set + # the 400 and just return the ctx here IMO, letting finalize get called + # above... $c->finalize; die $_; }; - my $method = $c->req->method || ''; - my $path = $c->req->path; - $path = '/' unless length $path; - my $address = $c->req->address || ''; - $c->log_request; - $c->prepare_action; - return $c; } @@ -2062,24 +2132,28 @@ Prepares connection. sub prepare_connection { my $c = shift; - $c->engine->prepare_connection( $c, @_ ); + # XXX - This is called on the engine (not the request) to maintain + # Engine::PSGI back compat. + $c->engine->prepare_connection($c); } =head2 $c->prepare_cookies -Prepares cookies. +Prepares cookies by ensuring that the attribute on the request +object has been built. =cut -sub prepare_cookies { my $c = shift; $c->engine->prepare_cookies( $c, @_ ) } +sub prepare_cookies { my $c = shift; $c->request->cookies } =head2 $c->prepare_headers -Prepares headers. +Prepares request headers by ensuring that the attribute on the request +object has been built. =cut -sub prepare_headers { my $c = shift; $c->engine->prepare_headers( $c, @_ ) } +sub prepare_headers { my $c = shift; $c->request->headers } =head2 $c->prepare_parameters @@ -2362,7 +2436,7 @@ $c->request. You must handle all body parsing yourself. =cut -sub read { my $c = shift; return $c->engine->read( $c, @_ ) } +sub read { my $c = shift; return $c->request->read( @_ ) } =head2 $c->run @@ -2609,7 +2683,7 @@ sub setup_engine { $meta->add_method(handler => sub { my $r = shift; - my $psgi_app = $class->psgi_app; + my $psgi_app = $class->_finalized_psgi_app; $apache->call_app($r, $psgi_app); }); @@ -2700,7 +2774,16 @@ sub apply_default_middlewares { # If we're running under Lighttpd, swap PATH_INFO and SCRIPT_NAME # http://lists.scsys.co.uk/pipermail/catalyst/2006-June/008361.html - $psgi_app = Plack::Middleware::LighttpdScriptNameFix->wrap($psgi_app); + $psgi_app = Plack::Middleware::Conditional->wrap( + $psgi_app, + builder => sub { Plack::Middleware::LighttpdScriptNameFix->wrap($_[0]) }, + condition => sub { + my ($env) = @_; + return unless $env->{SERVER_SOFTWARE} && $env->{SERVER_SOFTWARE} =~ m!lighttpd[-/]1\.(\d+\.\d+)!; + return unless $1 < 4.23; + 1; + }, + ); # we're applying this unconditionally as the middleware itself already makes # sure it doesn't fuck things up if it's not running under one of the right @@ -2845,11 +2928,11 @@ the plugin name does not begin with C. Class::MOP::load_class( $plugin ); $class->log->warn( "$plugin inherits from 'Catalyst::Component' - this is deprecated and will not work in 5.81" ) if $plugin->isa( 'Catalyst::Component' ); - $proto->_plugins->{$plugin} = 1; - unless ($instant) { + if (!$instant && !$proto->_plugins->{$plugin}) { my $meta = Class::MOP::get_metaclass_by_name($class); $meta->superclasses($plugin, $meta->superclasses); } + $proto->_plugins->{$plugin} = 1; return $class; } @@ -2931,10 +3014,10 @@ your output data, if known. sub write { my $c = shift; - # Finalize headers if someone manually writes output + # Finalize headers if someone manually writes output (for compat) $c->finalize_headers; - return $c->engine->write( $c, @_ ); + return $c->response->write( @_ ); } =head2 version @@ -3114,7 +3197,26 @@ headers. If you do not wish to use the proxy support at all, you may set: - MyApp->config(ignore_frontend_proxy => 1); + MyApp->config(ignore_frontend_proxy => 0); + +=head2 Note about psgi files + +Note that if you supply your own .psgi file, calling +C<< MyApp->psgi_app(@_); >>, then B. + +You either need to apply L yourself +in your psgi, for example: + + builder { + enable "Plack::Middleware::ReverseProxy"; + MyApp->psgi_app + }; + +This will unconditionally add the ReverseProxy support, or you need to call +C<< $app = MyApp->apply_default_middlewares($app) >> (to conditionally +apply the support depending upon your config). + +See L for more information. =head1 THREAD SAFETY @@ -3163,8 +3265,6 @@ Wiki: =head2 L - The test suite. -=begin stopwords - =head1 PROJECT FOUNDER sri: Sebastian Riedel @@ -3307,8 +3407,6 @@ rainboxx: Matthias Dietrich, C dd070: Dhaval Dhanani -=end stopwords - =head1 COPYRIGHT Copyright (c) 2005, the above named PROJECT FOUNDER and CONTRIBUTORS.