display http methods debug information before the action name
[catagits/Catalyst-Runtime.git] / lib / Catalyst / DispatchType / Chained.pm
index 3654a11..1a3fd56 100644 (file)
@@ -96,16 +96,17 @@ sub list {
                   sort { $a->reverse cmp $b->reverse }
                            @{ $self->_endpoints }
                   ) {
-        my $args = $endpoint->attributes->{Args}->[0];
+        my $args = $endpoint->list_extra_info->{Args};
         my @parts = (defined($args) ? (("*") x $args) : '...');
         my @parents = ();
         my $parent = "DUMMY";
+        my $extra  = $self->_list_extra_http_methods($endpoint);
         my $curr = $endpoint;
         while ($curr) {
-            if (my $cap = $curr->attributes->{CaptureArgs}) {
-                unshift(@parts, (("*") x $cap->[0]));
+            if (my $cap = $curr->list_extra_info->{CaptureArgs}) {
+                unshift(@parts, (("*") x $cap));
             }
-            if (my $pp = $curr->attributes->{PartPath}) {
+            if (my $pp = $curr->attributes->{PathPart}) {
                 unshift(@parts, $pp->[0])
                     if (defined $pp->[0] && length $pp->[0]);
             }
@@ -121,15 +122,19 @@ sub list {
         my @rows;
         foreach my $p (@parents) {
             my $name = "/${p}";
-            if (my $cap = $p->attributes->{CaptureArgs}) {
-                $name .= ' ('.$cap->[0].')';
+
+            if (defined(my $extra = $self->_list_extra_http_methods($p))) {
+                $name = "${extra} ${name}";
+            }
+            if (defined(my $cap = $p->list_extra_info->{CaptureArgs})) {
+                $name .= ' ('.$cap.')';
             }
             unless ($p eq $parents[0]) {
                 $name = "-> ${name}";
             }
             push(@rows, [ '', $name ]);
         }
-        push(@rows, [ '', (@rows ? "=> " : '')."/${endpoint}" ]);
+        push(@rows, [ '', (@rows ? "=> " : '').($extra ? "$extra " : '')."/${endpoint}" ]);
         $rows[0][0] = join('/', '', @parts) || '/';
         $paths->row(@$_) for @rows;
     }
@@ -139,6 +144,12 @@ sub list {
         if $has_unattached_actions;
 }
 
+sub _list_extra_http_methods {
+    my ( $self, $action ) = @_;
+    return unless defined $action->list_extra_info->{HTTP_METHODS};
+    return join(', ', @{$action->list_extra_info->{HTTP_METHODS}});
+}
+
 =head2 $self->match( $c, $path )
 
 Calls C<recurse_match> to see if a chain matches the C<$path>.
@@ -201,6 +212,7 @@ sub recurse_match {
         my @try_actions = @{$children->{$try_part}};
         TRY_ACTION: foreach my $action (@try_actions) {
             if (my $capture_attr = $action->attributes->{CaptureArgs}) {
+                $capture_attr ||= 0;
 
                 # Short-circuit if not enough remaining parts
                 next TRY_ACTION unless @parts >= $capture_attr->[0];
@@ -211,8 +223,11 @@ 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) = $self->recurse_match(
+                my ($actions, $captures, $action_parts, $n_pathparts) = $self->recurse_match(
                                              $c, '/'.$action->reverse, \@parts
                                            );
                 #    No best action currently
@@ -222,12 +237,15 @@ sub recurse_match {
                     (!$best_action                                 ||
                      $#$action_parts < $#{$best_action->{parts}}   ||
                      ($#$action_parts == $#{$best_action->{parts}} &&
-                      $#$captures < $#{$best_action->{captures}}))){
+                      $#$captures < $#{$best_action->{captures}} &&
+                      $n_pathparts > $best_action->{n_pathparts}))) {
+                    my @pathparts = split /\//, $action->attributes->{PathPart}->[0];
                     $best_action = {
                         actions => [ $action, @$actions ],
                         captures=> [ @captures, @$captures ],
-                        parts   => $action_parts
-                        };
+                        parts   => $action_parts,
+                        n_pathparts => scalar(@pathparts) + $n_pathparts,
+                    };
                 }
             }
             else {
@@ -236,7 +254,7 @@ sub recurse_match {
                     next TRY_ACTION unless $action->match($c);
                 }
                 my $args_attr = $action->attributes->{Args}->[0];
-
+                my @pathparts = split /\//, $action->attributes->{PathPart}->[0];
                 #    No best action currently
                 # OR This one matches with fewer parts left than the current best action,
                 #    And therefore is a better match
@@ -246,17 +264,18 @@ sub recurse_match {
 
                 if (!$best_action                       ||
                     @parts < @{$best_action->{parts}}   ||
-                    (!@parts && $args_attr eq 0)){
+                    (!@parts && defined($args_attr) && $args_attr eq "0")){
                     $best_action = {
                         actions => [ $action ],
                         captures=> [],
-                        parts   => \@parts
-                    }
+                        parts   => \@parts,
+                        n_pathparts => scalar(@pathparts),
+                    };
                 }
             }
         }
     }
-    return @$best_action{qw/actions captures parts/} if $best_action;
+    return @$best_action{qw/actions captures parts n_pathparts/} if $best_action;
     return ();
 }
 
@@ -304,7 +323,7 @@ sub register {
         );
     }
 
-    $action->attributes->{PartPath} = [ $part ];
+    $action->attributes->{PathPart} = [ $part ];
 
     unshift(@{ $children->{$part} ||= [] }, $action);
 
@@ -353,12 +372,12 @@ sub uri_for_action {
     my $curr = $action;
     while ($curr) {
         if (my $cap = $curr->attributes->{CaptureArgs}) {
-            return undef unless @captures >= $cap->[0]; # not enough captures
+            return undef unless @captures >= ($cap->[0]||0); # not enough captures
             if ($cap->[0]) {
                 unshift(@parts, splice(@captures, -$cap->[0]));
             }
         }
-        if (my $pp = $curr->attributes->{PartPath}) {
+        if (my $pp = $curr->attributes->{PathPart}) {
             unshift(@parts, $pp->[0])
                 if (defined($pp->[0]) && length($pp->[0]));
         }
@@ -400,6 +419,7 @@ sub expand_action {
 }
 
 __PACKAGE__->meta->make_immutable;
+1;
 
 =head1 USAGE
 
@@ -669,6 +689,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