refactor dispatch some more
Matt S Trout [Wed, 15 Dec 2010 12:07:09 +0000 (12:07 +0000)]
lib/Web/Dispatch.pm
lib/Web/Dispatch/Parser.pm
lib/Web/Dispatch/Predicates.pm
lib/Web/Dispatch/Wrapper.pm
t/dispatch_parser.t

index 581cc04..1b2dda0 100644 (file)
@@ -41,10 +41,12 @@ sub _dispatch {
     next unless @result and defined($result[0]);
     if (ref($result[0]) eq 'ARRAY') {
       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;
+      my $mw = $result[0];
+      $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 {
index 9d02af1..69c510b 100644 (file)
@@ -109,7 +109,7 @@ sub _parse_spec_section {
       return do {
         my $match = $self->_parse_spec_section($_);
         return sub {
-          return {} unless $match->(@_);
+          return {} unless my @discard = $match->(@_);
           return;
         };
       };
@@ -179,23 +179,7 @@ sub _url_path_segment_match {
 
 sub _url_extension_match {
   my ($self, $str, $extension) = @_;
-  if ($extension eq '*') {
-    sub {
-      if ((my $tmp = shift->{PATH_INFO}) =~ s/\.(\w+)$//) {
-        ({ PATH_INFO => $tmp }, $1);
-      } else {
-        ();
-      }
-    };
-  } else {
-    sub {
-      if ((my $tmp = shift->{PATH_INFO}) =~ s/\.\Q${extension}\E$//) {
-        ({ PATH_INFO => $tmp });
-      } else {
-        ();
-      }
-    };
-  }
+  match_extension($extension);
 }
 
 sub _parse_param_handler {
index 7008efe..bfc5f2f 100644 (file)
@@ -3,7 +3,10 @@ package Web::Dispatch::Predicates;
 use strictures 1;
 use base qw(Exporter);
 
-our @EXPORT = qw(match_and match_or match_method match_path match_path_strip);
+our @EXPORT = qw(
+  match_and match_or match_method match_path match_path_strip
+  match_extension
+);
 
 sub match_and {
   my @match = @_;
@@ -72,4 +75,19 @@ sub match_path_strip {
   }
 }
 
+sub match_extension {
+  my ($extension) = @_;
+  my $wild = (!$extension or $extension eq '*');
+  my $re = $wild
+             ? qr/\.(\w+)$/
+             : qr/\.(\Q${extension}\E)$/;
+  sub {
+    if ($_[0]->{PATH_INFO} =~ $re) {
+      ($wild ? ({}, $1) : {});
+    } else {
+      ();
+    }
+  };
+}
+
 1;
index 80e6356..65739fd 100644 (file)
@@ -1,10 +1,15 @@
 package Web::Dispatch::Wrapper;
 
 use strictures 1;
+use Moo;
 use Exporter 'import';
 
 our @EXPORT = qw(dispatch_wrapper redispatch_to response_filter);
 
+extends 'Plack::Middleware';
+
+has 'wrapper' => (is => 'ro', required => 1);
+
 sub dispatch_wrapper (&) {
   my ($code) = @_;
   __PACKAGE__->from_code($code);
@@ -12,7 +17,7 @@ sub dispatch_wrapper (&) {
 
 sub from_code {
   my ($class, $code) = @_;
-  bless(\$code, $class);
+  $class->new(wrapper => $code);
 }
 
 sub redispatch_to {
@@ -34,8 +39,8 @@ sub response_filter (&) {
   });
 }
 
-sub wrap {
-  my $code = ${$_[0]};
+sub to_app {
+  my $code = $_[0]->wrapper;
   my $app = $_[1];
   sub { $code->($_[0], $app) }
 }
index 8405d7d..503a570 100644 (file)
@@ -23,17 +23,12 @@ my $dp = Web::Dispatch::Parser->new;
    );
 }
 
-ok(
-  !eval { $dp->parse('GET POST'); 1; },
-  "Don't yet allow two methods"
-);
-
 {
    my $html = $dp->parse('.html');
 
    is_deeply(
      [ $html->({ PATH_INFO => '/foo/bar.html' }) ],
-     [ { PATH_INFO => '/foo/bar' } ],
+     [ { } ],
      '.html matches'
    );
 
@@ -49,7 +44,7 @@ ok(
 
    is_deeply(
      [ $any_ext->({ PATH_INFO => '/foo/bar.html' }) ],
-     [ { PATH_INFO => '/foo/bar' }, 'html' ],
+     [ { }, 'html' ],
      '.html matches .* and extension returned'
    );
 
@@ -90,6 +85,12 @@ ok(
      [],
      '/post/one/ does not match'
    );
+
+   is_deeply(
+     [ $post->({ PATH_INFO => '/post/one.html' }) ],
+     [ {}, 'one' ],
+     '/post/one.html still parses out one'
+   );
 }
 
 {
@@ -219,7 +220,7 @@ ok(
 
    is_deeply(
      [ $not->({ PATH_INFO => '/foo.xml' }) ],
-     [ { PATH_INFO => '/foo' }, 'xml' ],
+     [ {}, 'xml' ],
      '!.html+.* matches /foo.xml'
    );