stop using Moo as a test package
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Controller.pm
index 9c3cb2a..466d4d9 100644 (file)
@@ -143,17 +143,27 @@ sub _BEGIN : Private {
     my $begin = ( $c->get_actions( 'begin', $c->namespace ) )[-1];
     return 1 unless $begin;
     $begin->dispatch( $c );
-    return !@{ $c->error };
+    #If there is an error, all bets off
+    if( @{ $c->error }) {
+      return !@{ $c->error };
+    } else {
+      return $c->state || 1;
+    }
 }
 
 sub _AUTO : Private {
     my ( $self, $c ) = @_;
     my @auto = $c->get_actions( 'auto', $c->namespace );
     foreach my $auto (@auto) {
+        # We FORCE the auto action user to explicitly return
+        # true.  We need to do this since there's some auto
+        # users (Catalyst::Authentication::Credential::HTTP) that
+        # actually do a detach instead.  
+        $c->state(0);
         $auto->dispatch( $c );
         return 0 unless $c->state;
     }
-    return 1;
+    return $c->state || 1;
 }
 
 sub _ACTION : Private {
@@ -164,7 +174,12 @@ sub _ACTION : Private {
     {
         $c->action->dispatch( $c );
     }
-    return !@{ $c->error };
+    #If there is an error, all bets off
+    if( @{ $c->error }) {
+      return !@{ $c->error };
+    } else {
+      return $c->state || 1;
+    }
 }
 
 sub _END : Private {
@@ -372,6 +387,11 @@ sub gather_default_action_roles {
   push @roles, 'Catalyst::ActionRole::ConsumesContent'
     if $args{attributes}->{Consumes};
 
+  push @roles, 'Catalyst::ActionRole::Scheme'
+    if $args{attributes}->{Scheme};
+
+  push @roles, 'Catalyst::ActionRole::QueryMatching'
+    if $args{attributes}->{Query};
     return @roles;
 }
 
@@ -384,7 +404,7 @@ sub _parse_attrs {
 
         # Parse out :Foo(bar) into Foo => bar etc (and arrayify)
 
-        if ( my ( $key, $value ) = ( $attr =~ /^(.*?)(?:\(\s*(.+?)\s*\))?$/ ) )
+        if ( my ( $key, $value ) = ( $attr =~ /^(.*?)(?:\(\s*(.+?)?\s*\))?$/ ) )
         {
 
             if ( defined $value ) {
@@ -542,12 +562,13 @@ sub _parse_Does_attr {
     return Does => $self->_expand_role_shortname($value);
 }
 
-sub _parse_GET_attr    { Method => 'GET'    }
-sub _parse_POST_attr   { Method => 'POST'   }
-sub _parse_PUT_attr    { Method => 'PUT'    }
-sub _parse_DELETE_attr { Method => 'DELETE' }
-sub _parse_OPTION_attr { Method => 'OPTION' }
-sub _parse_HEAD_attr   { Method => 'HEAD'   }
+sub _parse_GET_attr     { Method => 'GET'     }
+sub _parse_POST_attr    { Method => 'POST'    }
+sub _parse_PUT_attr     { Method => 'PUT'     }
+sub _parse_DELETE_attr  { Method => 'DELETE'  }
+sub _parse_OPTIONS_attr { Method => 'OPTIONS' }
+sub _parse_HEAD_attr    { Method => 'HEAD'    }
+sub _parse_PATCH_attr  { Method => 'PATCH'  }
 
 sub _expand_role_shortname {
     my ($self, @shortnames) = @_;
@@ -641,10 +662,25 @@ arguments, when it is instantiated:
 From L<Catalyst::Component::ApplicationAttribute>, stashes the application
 instance as $self->_application.
 
-=head2 $self->action_for('name')
+=head2 $self->action_for($action_name)
+
+Returns the Catalyst::Action object (if any) for a given action in this
+controller or relative to it.  You may refer to actions in controllers
+nested under the current controllers namespace, or in controllers 'up'
+from the current controller namespace.  For example:
+
+    package MyApp::Controller::One::Two;
+    use base 'Catalyst::Controller';
 
-Returns the Catalyst::Action object (if any) for a given method name
-in this component.
+    sub foo :Local {
+      my ($self, $c) = @_;
+      $self->action_for('foo'); # action 'foo' in Controller 'One::Two'
+      $self->action_for('three/bar'); # action 'bar' in Controller 'One::Two::Three'
+      $self->action_for('../boo'); # action 'boo' in Controller 'One'
+    }
+
+This returns 'undef' if there is no action matching the requested action
+name (after any path normalization) so you should check for this as needed.
 
 =head2 $self->action_namespace($c)
 
@@ -712,7 +748,7 @@ similar to how annotations work in other languages you might have heard of.
 Generally L<Catalyst> uses these to influence how the dispatcher sees your
 action and when it will run it in response to an incoming request.  They can
 also be used for other things.  Here's a summary, but you should refer to the
-liked manual page for additional help.
+linked manual page for additional help.
 
 =head2 Global
 
@@ -784,7 +820,29 @@ Like L</Regex> but scoped under the namespace of the containing controller
 
 =head2 CaptureArgs
 
-Please see L<Catalyst::DispatchType::Chained>
+Allowed values for CaptureArgs is a single integer (CaptureArgs(2), meaning two
+allowed) or you can declare a L<Moose>, L<MooseX::Types> or L<Type::Tiny>
+named constraint such as CaptureArgs(Int,Str) would require two args with
+the first being a Integer and the second a string.  You may declare your own
+custom type constraints and import them into the controller namespace:
+
+    package MyApp::Controller::Root;
+
+    use Moose;
+    use MooseX::MethodAttributes;
+    use MyApp::Types qw/Int/;
+
+    extends 'Catalyst::Controller';
+
+    sub chain_base :Chained(/) CaptureArgs(1) { }
+
+      sub any_priority_chain :Chained(chain_base) PathPart('') Args(1) { }
+
+      sub int_priority_chain :Chained(chain_base) PathPart('') Args(Int) { }
+
+See L<Catalyst::RouteMatching> for more.
+
+Please see L<Catalyst::DispatchType::Chained> for more.
 
 =head2 ActionClass
 
@@ -804,9 +862,9 @@ The following is exactly the same:
 
     package MyApp::Controller::Zoo;
 
-    sub foo  : Local Does('Moo')  { ... } # Catalyst::ActionRole::
-    sub bar  : Local Does('~Moo') { ... } # MyApp::ActionRole::Moo
-    sub baz  : Local Does('+MyApp::ActionRole::Moo') { ... }
+    sub foo  : Local Does('Buzz')  { ... } # Catalyst::ActionRole::
+    sub bar  : Local Does('~Buzz') { ... } # MyApp::ActionRole::Buzz
+    sub baz  : Local Does('+MyApp::ActionRole::Buzz') { ... }
 
 =head2 GET
 
@@ -834,6 +892,57 @@ When used with L</Path> indicates the number of arguments expected in
 the path.  However if no Args value is set, assumed to 'slurp' all
 remaining path pars under this namespace.
 
+Allowed values for Args is a single integer (Args(2), meaning two allowed) or you
+can declare a L<Moose>, L<MooseX::Types> or L<Type::Tiny> named constraint such
+as Args(Int,Str) would require two args with the first being a Integer and the
+second a string.  You may declare your own custom type constraints and import
+them into the controller namespace:
+
+    package MyApp::Controller::Root;
+
+    use Moose;
+    use MooseX::MethodAttributes;
+    use MyApp::Types qw/Tuple Int Str StrMatch UserId/;
+
+    extends 'Catalyst::Controller';
+
+    sub user :Local Args(UserId) {
+      my ($self, $c, $int) = @_;
+    }
+
+    sub an_int :Local Args(Int) {
+      my ($self, $c, $int) = @_;
+    }
+
+    sub many_ints :Local Args(ArrayRef[Int]) {
+      my ($self, $c, @ints) = @_;
+    }
+
+    sub match :Local Args(StrMatch[qr{\d\d-\d\d-\d\d}]) {
+      my ($self, $c, $int) = @_;
+    }
+
+If you choose not to use imported type constraints (like L<Type::Tiny>, or <MooseX::Types>
+you may use L<Moose> 'stringy' types however just like when you use these types in your
+declared attributes you must quote them:
+
+    sub my_moose_type :Local Args('Int') { ... }
+
+If you use 'reference' type constraints (such as ArrayRef[Int]) that have an unknown
+number of allowed matches, we set this the same way "Args" is.  Please keep in mind
+that actions with an undetermined number of args match at lower precedence than those
+with a fixed number.  You may use reference types such as Tuple from L<Types::Standard>
+that allows you to fix the number of allowed args.  For example Args(Tuple[Int,Int])
+would be determined to be two args (or really the same as Args(Int,Int).)  You may
+find this useful for creating custom subtypes with complex matching rules that you 
+wish to reuse over many actions.
+
+See L<Catalyst::RouteMatching> for more.
+
+B<Note>: It is highly recommended to use L<Type::Tiny> for your type constraints over
+other options.  L<Type::Tiny> exposed a better meta data interface which allows us to
+do more and better types of introspection driving tests and debugging.
+
 =head2 Consumes('...')
 
 Matches the current action against the content-type of the request.  Typically
@@ -889,6 +998,39 @@ most accurate matches early in the Chain, and your 'catchall' actions last.
 
 See L<Catalyst::ActionRole::ConsumesContent> for more.
 
+=head2 Scheme(...)
+
+Allows you to specify a URI scheme for the action or action chain.  For example
+you can required that a given path be C<https> or that it is a websocket endpoint
+C<ws> or C<wss>.  For an action chain you may currently only have one defined
+Scheme.
+
+    package MyApp::Controller::Root;
+
+    use base 'Catalyst::Controller';
+
+    sub is_http :Path(scheme) Scheme(http) Args(0) {
+      my ($self, $c) = @_;
+      $c->response->body("is_http");
+    }
+
+    sub is_https :Path(scheme) Scheme(https) Args(0)  {
+      my ($self, $c) = @_;
+      $c->response->body("is_https");
+    }
+
+In the above example http://localhost/root/scheme would match the first
+action (is_http) but https://localhost/root/scheme would match the second.
+
+As an added benefit, if an action or action chain defines a Scheme, when using
+$c->uri_for the scheme of the generated URL will use what you define in the action
+or action chain (the current behavior is to set the scheme based on the current
+incoming request).  This makes it easier to use uri_for on websites where some
+paths are secure and others are not.  You may also use this to other schemes
+like websockets.
+
+See L<Catalyst::ActionRole::Scheme> for more.
+
 =head1 OPTIONAL METHODS
 
 =head2 _parse_[$name]_attr