bump version
[catagits/Web-Simple.git] / lib / Web / Dispatch.pm
index 01ebb3e..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;
@@ -37,32 +40,39 @@ sub _dispatch {
     } elsif (ref($try) eq 'ARRAY') {
       return $try;
     }
-    my @result = $self->_to_try($try)->($env, @match);
+    my @result = $self->_to_try($try, \@match)->($env, @match);
     next unless @result and defined($result[0]);
     if (ref($result[0]) eq 'ARRAY') {
+      if (@{$result[0]} == 1 and ref($result[0][0]) eq 'CODE') {
+        return $result[0][0];
+      }
       return $result[0];
-    } elsif (blessed($result[0]) && $result[0]->can('wrap')) {
-      return $result[0]->wrap(sub {
-        $self->_dispatch($_[0], @match)
-      })->($env);
+    } 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')) {
       return $result[0];
     } 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;
 }
 
 sub _to_try {
-  my ($self, $try) = @_;
+  my ($self, $try, $more) = @_;
   if (ref($try) eq 'CODE') {
     if (defined(my $proto = prototype($try))) {
       $self->_construct_node(
@@ -71,6 +81,10 @@ sub _to_try {
     } else {
       $try
     }
+  } elsif (!ref($try) and ref($more->[0]) eq 'CODE') {
+    $self->_construct_node(
+      match => $self->_parser->parse($try), run => shift(@$more)
+    )->to_app;
   } elsif (blessed($try) && $try->can('to_app')) {
     $try->to_app;
   } else {
@@ -80,8 +94,7 @@ sub _to_try {
 
 sub _construct_node {
   my ($self, %args) = @_;
-  @args{keys %$_} = values %$_ for $self->node_args;
-  $self->node_class->new(\%args);
+  $self->node_class->new({ %{$self->node_args}, %args });
 }
 
 1;