first pass at constraints on uri_for
John Napiorkowski [Thu, 26 Mar 2015 19:36:55 +0000 (14:36 -0500)]
lib/Catalyst.pm
lib/Catalyst/ActionChain.pm
t/arg_constraints.t

index f013027..576f0c4 100644 (file)
@@ -1491,18 +1491,18 @@ sub uri_for {
                          : ()) ];
 
         my $action = $path;
+        my $expanded_action = $c->dispatcher->expand_action( $action );
+         my $num_captures = $expanded_action->number_of_captures;
+
         # ->uri_for( $action, \@captures_and_args, \%query_values? )
         if( !@encoded_args && $action->number_of_args ) {
-            my $expanded_action = $c->dispatcher->expand_action( $action );
-            my $num_captures = $expanded_action->number_of_captures;
-            unshift @encoded_args, splice @$captures, $num_captures;
+          unshift @encoded_args, splice @$captures, $num_captures;
         }
 
-        # use Devel::Dwarn;Dwarn $captures;
-
-        if($action->has_captures_constraints) {
-          unless($action->match_captures($c, $captures)) {
-            carp "@{$captures} do not match the type constraints in $action";
+        if($num_captures) {
+          unless($expanded_action->match_captures($c, $captures)) {
+            carp "captures [@{$captures}] do not match the type constraints in action '$action'";
+            return;
           }
         }
 
@@ -1515,9 +1515,10 @@ sub uri_for {
         $path = '/' if $path eq '';
 
         # At this point @encoded_args is the remaining Args (all captures removed).
-        if($action->has_args_constraints) {
-          unless($action->match_args($c,\@encoded_args)) {
-            carp "@encoded_args do not match the type constraints in $action";
+        if($expanded_action->has_args_constraints) {
+          unless($expanded_action->match_args($c,\@encoded_args)) {
+             carp "args [@encoded_args] do not match the type constraints in action '$expanded_action'";
+             return;
           }
         }
     }
@@ -1582,8 +1583,8 @@ sub uri_for {
       } @keys);
     }
 
-    warn $base;
-    warn $args;
+    #warn $base;
+    #warn $args;
     
     my $res = bless(\"${base}${args}${query}", $class);
     $res;
index 5e222c2..873e3a8 100644 (file)
@@ -61,6 +61,17 @@ sub number_of_captures {
     return $captures;
 }
 
+sub match_captures {
+  my ($self, $c, $captures) = @_;
+  my @captures = @{$captures||[]};
+
+  foreach my $link(@{$self->chain}) {
+    my @local_captures = splice @captures,0,$link->number_of_captures;
+    return unless $link->match_captures($c, \@local_captures);
+  }
+  return 1;
+}
+
 # the scheme defined at the end of the chain is the one we use
 # but warn if too many.
 
@@ -103,6 +114,10 @@ Catalyst::ActionChain object representing a chain of these actions
 
 Returns the total number of captures for the entire chain of actions.
 
+=head2 match_captures
+
+Match all the captures that this chain encloses, if any.
+
 =head2 scheme
 
 Any defined scheme for the actionchain
index 80b53f6..e948dee 100644 (file)
@@ -367,22 +367,54 @@ SKIP: {
 {
   # URI testing
   my ($res, $c) = ctx_request '/';
-  ok my $url1 = $c->uri_for($c->controller('Root')->action_for('finally'), [1,2,3,4,5],6);
-  warn $url1;
 
-  ok my $url2 = $c->uri_for($c->controller('Root')->action_for('finally'), [1,2,3,4,5,6]);
-  warn $url2;
+  {
+    ok my $url = eval { $c->uri_for($c->controller('Root')->action_for('user'), 2) };
+    is $url, 'http://localhost/user/2';
+  }
 
-  ok my $url3 = $c->uri_for($c->controller('Root')->action_for('user'), 2);
-  warn $url3;
+  {
+    ok my $url = eval { $c->uri_for($c->controller('Root')->action_for('user'), [2]) };
+    is $url, 'http://localhost/user/2';
+  }
 
-  ok my $url4 = $c->uri_for($c->controller('Root')->action_for('user'), [2]);
-  warn $url4;
+  {
+    ok my $url = ! eval { $c->uri_for($c->controller('Root')->action_for('user'), [20]) };
+  }
+
+  {
+    ok my $url = eval { $c->uri_for($c->controller('Root')->action_for('finally'), [1,2,3,4,4],6) };
+    is $url, 'http://localhost/chain_base/1/2/3/4/4/6';
+  }
+
+  {
+    ok my $url = eval { $c->uri_for($c->controller('Root')->action_for('finally'), [1,2,3,4,4,6]) };
+    is $url, 'http://localhost/chain_base/1/2/3/4/4/6';
+  }
+
+  {
+    ok my $url = ! eval { $c->uri_for($c->controller('Root')->action_for('finally'), [1,2,3,4,5,6]) };
+  }
+
+  {
+    ok my $url = eval { $c->uri_for($c->controller('Root')->action_for('finally'), ['a',2,3,4,4,6]) };
+    is $url, 'http://localhost/chain_base/a/2/3/4/4/6';
+  }
+
+  {
+    ok my $url = ! eval { $c->uri_for($c->controller('Root')->action_for('finally'), ['a','1',3,4,4,'a']) };
+  }
+
+  {
+    ok my $url = ! eval { $c->uri_for($c->controller('Root')->action_for('finally'), ['a','a',3,4,4,'6']) };
+  }
 
 }
 
 done_testing;
 
+
 __END__
 
 
+