fix environment changes within subdispatch and arrange for middleware to uplevel...
Matt S Trout [Fri, 11 Feb 2011 06:32:12 +0000 (06:32 +0000)]
lib/Web/Dispatch.pm
lib/Web/Dispatch/Node.pm
t/response-filter.t
t/sub-dispatch-env.t [new file with mode: 0644]

index d9e76ca..184cada 100644 (file)
@@ -2,6 +2,9 @@ package Web::Dispatch;
 
 use Sub::Quote;
 use Scalar::Util qw(blessed);
+
+sub MAGIC_MIDDLEWARE_KEY { __PACKAGE__.'.middleware' }
+
 use Moo;
 use Web::Dispatch::Parser;
 use Web::Dispatch::Node;
@@ -47,7 +50,14 @@ sub _dispatch {
     } elsif (blessed($result[0]) && $result[0]->isa('Plack::Middleware')) {
       die "Multiple results but first one is a middleware ($result[0])"
         if @result > 1;
+      # middleware needs to uplevel exactly once to wrap the rest of the
+      # level it was created for - next elsif unwraps it
+      return { MAGIC_MIDDLEWARE_KEY, $result[0] };
       my $mw = $result[0];
+    } elsif (
+      ref($result[0]) eq 'HASH'
+      and my $mw = $result[0]->{+MAGIC_MIDDLEWARE_KEY}
+    ) {
       $mw->app(sub { $self->_dispatch($_[0], @match) });
       return $mw->to_app->($env);
     } elsif (blessed($result[0]) && !$result[0]->can('to_app')) {
@@ -55,12 +65,7 @@ sub _dispatch {
     } else {
       # make a copy so we don't screw with it assigning further up
       my $env = $env;
-      # try not to end up quite so bloody deep in the call stack
-      if (@match) {
-        unshift @match, sub { $self->_dispatch($env, @result) };
-      } else {
-        @match = @result;
-      }
+      unshift @match, sub { $self->_dispatch($env, @result) };
     }
   }
   return;
index 4fbc46d..bd83a7c 100644 (file)
@@ -11,7 +11,7 @@ for (qw(match run)) {
 sub call {
   my ($self, $env) = @_;
   if (my ($env_delta, @match) = $self->_match->($env)) {
-    $self->_curry(@match)->({ %$env, %$env_delta });
+    ($env_delta, $self->_curry(@match));
   } else {
     ()
   }
index 645e4e6..1cac671 100644 (file)
@@ -15,7 +15,7 @@ use HTTP::Request::Common qw(GET POST);
           [ 'Content-Type' => 'text/html' ], 
           [ shift->{name} ],
         ];
-      };
+      }
     },
     sub (GET + /index) {
       bless {name=>'john'}, 'CrazyHotWildWet';
diff --git a/t/sub-dispatch-env.t b/t/sub-dispatch-env.t
new file mode 100644 (file)
index 0000000..14a7a31
--- /dev/null
@@ -0,0 +1,26 @@
+use strictures 1;
+use Test::More;
+
+{
+  package TestApp;
+
+  use Web::Simple;
+
+  sub dispatch_request {
+    sub (/foo/...) {
+      sub (GET) { [ 200, [], [ $_[PSGI_ENV]->{PATH_INFO} ] ] }
+    },
+    sub (POST) { [ 200, [], [ $_[PSGI_ENV]->{PATH_INFO} ] ] }
+  }
+}
+
+my $app = TestApp->new->to_psgi_app;
+
+my $call = sub { $app->({
+  SCRIPT_NAME => '/base', PATH_INFO => '/foo/bar', REQUEST_METHOD => shift
+})->[2]->[0] };
+
+is($call->('GET'), '/bar', 'recursive strip ok');
+is($call->('POST'), '/foo/bar', 'later dispatchers unaffected');
+
+done_testing;