Merge remote branch 'origin/no_state_in_engine'
Tomas Doran [Sun, 22 Jan 2012 09:50:54 +0000 (09:50 +0000)]
* origin/no_state_in_engine: (22 commits)
  silent warnings from Data::Dumper about dummy CODE refs
  silence warning from Engine::HTTP when $ENV{HARNESS_ACTIVE} is true
  Spelling skips
  Work when not aggregated
  Pod spelling
  Fix removed methods that plugins are likely to be hooking
  Fix docs in Response, fix Pod tests
  Sort out the Request docs
  Start re-arranging and fixing docs. remove docs for deprecated stuff
  Stop the request needing the context, just pass in the logger instead
  The response no longer needs the context
  Move write and finalize_headers into response object
  Put prepare_connection back as Engine::PSGI uses it
  Do moar, moving headers and cookies. This breaks engine::psgi, fix later..
  Move prepare_connection, and it's lies documentation. Bet this breaks mad engines (stomp?)
  Move prepare_parametrs to be the builder.
  Move preparing the body into the request, almost works.
  Move actual reading into request
  Move read_chunk to the request
  Similarly, we don't need finalize_read
  ...

Changes
lib/Catalyst.pm
lib/Catalyst/Action.pm
lib/Catalyst/DispatchType/Chained.pm
lib/Catalyst/Engine.pm
lib/Catalyst/Runtime.pm
t/aggregate/live_component_controller_action_chained.t
t/lib/TestApp/Action/TestMatchCaptures.pm [new file with mode: 0644]
t/lib/TestApp/Controller/Action/Chained.pm

diff --git a/Changes b/Changes
index 40c4df8..2de89be 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,27 @@
 # This file documents the revision history for Perl extension Catalyst.
 
+ Documentation:
+  - Fix the display of PROJECT FOUNDER and CONTRIBUTORS sections in the
+    documentation. These were erroneously being emitted when the Pod
+    was converted to HTML for search.cpan.org
+
+5.90007 - 2011-11-22 20:35:00
+
+  New features:
+   - Implement a match_captures hook which, if it exists on an action,
+     is called with the $ctx and \@captures and is expected to return
+     true to continue the chain matching and false to stop matching.
+     This can be used to implement action classes or roles which match
+     conditionally (for example only matching captures which are integers).
+
+  Bug fixes:
+   - Lighttpd script name fix is only applied for lighttpd versions
+     < 1.4.23. This should fix non-root installs of lighttpd in versions
+     over that.
+   - Prepare_action is now inside a try {} block, so that requests containing
+     bad unicode can be appropriately trapped by
+     Catalyst::Plugin::Unicode::Encoding
+
 5.90006 - 2011-10-25 09:18:00
 
   New features:
index d458962..ebfcf8c 100644 (file)
@@ -100,7 +100,7 @@ __PACKAGE__->stats_class('Catalyst::Stats');
 
 # Remember to update this in Catalyst::Runtime as well!
 
-our $VERSION = '5.90006';
+our $VERSION = '5.90007';
 
 sub import {
     my ( $class, @arguments ) = @_;
@@ -372,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 ] )" >>,
@@ -402,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<go> and
@@ -2043,6 +2051,7 @@ sub prepare {
                 $c->prepare_body;
             }
         }
+        $c->prepare_action;
     }
     # VERY ugly and probably shouldn't rely on ->finalize actually working
     catch {
@@ -2050,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;
 }
 
@@ -2765,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
@@ -3247,8 +3265,6 @@ Wiki:
 
 =head2 L<Catalyst::Test> - The test suite.
 
-=begin stopwords
-
 =head1 PROJECT FOUNDER
 
 sri: Sebastian Riedel <sri@cpan.org>
@@ -3391,8 +3407,6 @@ rainboxx: Matthias Dietrich, C<perl@rainboxx.de>
 
 dd070: Dhaval Dhanani <dhaval070@gmail.com>
 
-=end stopwords
-
 =head1 COPYRIGHT
 
 Copyright (c) 2005, the above named PROJECT FOUNDER and CONTRIBUTORS.
index 09f81a8..af60527 100644 (file)
@@ -172,6 +172,17 @@ Returns the number of captures this action expects for L<Chained|Catalyst::Dispa
 
 Provided by Moose.
 
+=head1 OPTIONAL METHODS
+
+=head2 match_captures
+
+Can be implemented by action class and action role authors. If the method
+exists, then it will be called with the request context and an array reference
+of the captures for this action.
+
+Returning true from this method causes the chain match to continue, returning
+makes the chain not match (and alternate, less preferred chains will be attempted).
+
 =head1 AUTHORS
 
 Catalyst Contributors, see Catalyst.pm
index 2437698..ede2b69 100644 (file)
@@ -211,6 +211,9 @@ sub recurse_match {
                 # strip CaptureArgs into list
                 push(@captures, splice(@parts, 0, $capture_attr->[0]));
 
+                # check if the action may fit, depending on a given test by the app
+                if ($action->can('match_captures')) { next TRY_ACTION unless $action->match_captures($c, \@captures) }
+
                 # try the remaining parts against children of this action
                 my ($actions, $captures, $action_parts, $n_pathparts) = $self->recurse_match(
                                              $c, '/'.$action->reverse, \@parts
@@ -674,6 +677,13 @@ The C<forward>ing to other actions does just what you would expect. But if
 you C<detach> out of a chain, the rest of the chain will not get called
 after the C<detach>.
 
+=head2 match_captures
+
+A method which can optionally be implemented by actions to
+stop chain matching.
+
+See L<Catalyst::Action> for further details.
+
 =head1 AUTHORS
 
 Catalyst Contributors, see Catalyst.pm
index fac70cd..48126e7 100644 (file)
@@ -535,7 +535,7 @@ sub prepare_read {
 
 =head2 $self->prepare_request(@arguments)
 
-Populate the context object from the request object.
+Sets up the PSGI environment in the Engine.
 
 =cut
 
@@ -670,8 +670,7 @@ sub run {
 
 =head2 build_psgi_app ($app, @args)
 
-Builds and returns a PSGI application closure, wrapping it in the reverse proxy
-middleware if the using_frontend_proxy config setting is set.
+Builds and returns a PSGI application closure. (Raw, not wrapped in middleware)
 
 =cut
 
index 7ac1375..34e3edc 100644 (file)
@@ -7,7 +7,7 @@ BEGIN { require 5.008004; }
 
 # Remember to update this in Catalyst as well!
 
-our $VERSION = '5.90006';
+our $VERSION = '5.90007';
 
 =head1 NAME
 
index efea301..6f01812 100644 (file)
@@ -1113,6 +1113,19 @@ sub run_tests {
         ok( index($content, $path) > 1, 'uri can round trip through uri_for' )
             or diag("Expected $path, got $content");
     }
+
+    #
+    #   match_captures
+    #
+    {
+
+        ok( my $response = request('http://localhost/chained/match_captures/foo/bar'), 'match_captures: falling through' );
+        is($response->header('X-TestAppActionTestMatchCaptures'), 'fallthrough', 'match_captures: fell through');
+
+        ok($response = request('http://localhost/chained/match_captures/force/bar'), 'match_captures: *not* falling through' );
+        is($response->header('X-TestAppActionTestMatchCaptures'), 'forcing', 'match_captures: forced');
+        is($response->header('X-TestAppActionTestMatchCapturesHasRan'), 'yes', 'match_captures: actually ran');
+    }
 }
 
 done_testing;
diff --git a/t/lib/TestApp/Action/TestMatchCaptures.pm b/t/lib/TestApp/Action/TestMatchCaptures.pm
new file mode 100644 (file)
index 0000000..2d9d167
--- /dev/null
@@ -0,0 +1,18 @@
+package TestApp::Action::TestMatchCaptures;
+
+use Moose;
+
+extends 'Catalyst::Action';
+
+sub match_captures {
+    my ($self, $c, $cap) = @_;
+    if ($cap->[0] eq 'force') {
+        $c->res->header( 'X-TestAppActionTestMatchCaptures', 'forcing' );
+        return 1;
+    } else {
+        $c->res->header( 'X-TestAppActionTestMatchCaptures', 'fallthrough' );
+        return 0;
+    }
+}
+
+1;
\ No newline at end of file
index a393e77..732a35b 100644 (file)
@@ -220,6 +220,13 @@ sub roundtrip_urifor_end : Chained('roundtrip_urifor') PathPart('') Args(1) {
     $c->stash->{no_end} = 1;
 }
 
+sub match_captures : Chained('/') PathPart('chained/match_captures') CaptureArgs(1) ActionClass('+TestApp::Action::TestMatchCaptures') {
+    my ($self, $c) = @_;
+    $c->res->header( 'X-TestAppActionTestMatchCapturesHasRan', 'yes');
+}
+
+sub match_captures_end : Chained('match_captures') PathPart('bar') Args(0) { }
+
 sub end :Private {
   my ($self, $c) = @_;
   return if $c->stash->{no_end};