Revert incorrect fixes for parsing of attributes with empty parens
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Controller.pm
index 1594172..d0a8570 100644 (file)
@@ -9,7 +9,10 @@ use List::Util qw/first/;
 use List::MoreUtils qw/uniq/;
 use namespace::clean -except => 'meta';
 
-BEGIN { extends qw/Catalyst::Component MooseX::MethodAttributes::Inheritable/; }
+BEGIN {
+    extends qw/Catalyst::Component/;
+    with qw/MooseX::MethodAttributes::Role::AttrContainer::Inheritable/;
+}
 
 use MooseX::MethodAttributes;
 use Catalyst::Exception;
@@ -117,7 +120,7 @@ for more info about how Catalyst dispatches to actions.
 =cut
 
 #I think both of these could be attributes. doesn't really seem like they need
-#to ble class data. i think that attributes +default would work just fine
+#to be class data. i think that attributes +default would work just fine
 __PACKAGE__->mk_classdata($_) for qw/_dispatch_steps _action_class _action_role_prefix/;
 
 __PACKAGE__->_dispatch_steps( [qw/_BEGIN _AUTO _ACTION/] );
@@ -140,7 +143,12 @@ 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 {
@@ -150,7 +158,7 @@ sub _AUTO : Private {
         $auto->dispatch( $c );
         return 0 unless $c->state;
     }
-    return 1;
+    return $c->state || 1;
 }
 
 sub _ACTION : Private {
@@ -161,7 +169,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 {
@@ -317,7 +330,7 @@ sub action_class {
         ? $args{attributes}{ActionClass}[0]
         : $self->_action_class);
 
-    Class::MOP::load_class($class);
+    load_class($class);
     return $class;
 }
 
@@ -365,7 +378,16 @@ sub gather_default_action_roles {
   my @roles = ();
   push @roles, 'Catalyst::ActionRole::HTTPMethods'
     if $args{attributes}->{Method};
-  return @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;
 }
 
 sub _parse_attrs {
@@ -535,12 +557,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) = @_;
@@ -649,7 +672,7 @@ overridden from the "namespace" config key.
 
 =head2 $self->path_prefix($c)
 
-Returns the default path prefix for :PathPrefix, :Local, :LocalRegex and
+Returns the default path prefix for :PathPrefix, :Local and
 relative :Path actions in this component. Defaults to the action_namespace or
 can be overridden from the "path" config key.
 
@@ -705,7 +728,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
 
@@ -740,18 +763,20 @@ Handle various types of paths:
     ...
 
     sub myaction1 :Path { ... }  # -> /baz
-    sub myaction2 :Path('foo') { ... } # -> /baz/bar
+    sub myaction2 :Path('foo') { ... } # -> /baz/foo
     sub myaction2 :Path('/bar') { ... } # -> /bar
   }
 
-This is a general toolbox for attaching your action to a give path.
+This is a general toolbox for attaching your action to a given path.
 
 
 =head2 Regex
 
 =head2 Regexp
 
-Status: Deprecated.  Use Chained methods or other techniques
+B<Status: Deprecated.>  Use Chained methods or other techniques.
+If you really depend on this, install the standalone 
+L<Catalyst::DispatchType::Regex> distribution.
 
 A global way to match a give regular expression in the incoming request path.
 
@@ -759,6 +784,10 @@ A global way to match a give regular expression in the incoming request path.
 
 =head2 LocalRegexp
 
+B<Status: Deprecated.>  Use Chained methods or other techniques.
+If you really depend on this, install the standalone 
+L<Catalyst::DispatchType::Regex> distribution.
+
 Like L</Regex> but scoped under the namespace of the containing controller
 
 =head2 Chained 
@@ -771,7 +800,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
 
@@ -821,6 +872,141 @@ 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.
+
+=head2 Consumes('...')
+
+Matches the current action against the content-type of the request.  Typically
+this is used when the request is a POST or PUT and you want to restrict the
+submitted content type.  For example, you might have an HTML for that either
+returns classic url encoded form data, or JSON when Javascript is enabled.  In
+this case you may wish to match either incoming type to one of two different
+actions, for properly processing.
+
+Examples:
+
+    sub is_json       : Chained('start') Consumes('application/json') { ... }
+    sub is_urlencoded : Chained('start') Consumes('application/x-www-form-urlencoded') { ... }
+    sub is_multipart  : Chained('start') Consumes('multipart/form-data') { ... }
+
+To reduce boilerplate, we include the following content type shortcuts:
+
+Examples
+
+      sub is_json       : Chained('start') Consume(JSON) { ... }
+      sub is_urlencoded : Chained('start') Consumes(UrlEncoded) { ... }
+      sub is_multipart  : Chained('start') Consumes(Multipart) { ... }
+
+You may specify more than one match:
+
+      sub is_more_than_one
+        : Chained('start')
+        : Consumes('application/x-www-form-urlencoded')
+        : Consumes('multipart/form-data')
+
+      sub is_more_than_one
+        : Chained('start')
+        : Consumes(UrlEncoded)
+        : Consumes(Multipart)
+
+Since it is a common case the shortcut C<HTMLForm> matches both
+'application/x-www-form-urlencoded' and 'multipart/form-data'.  Here's the full
+list of available shortcuts:
+
+    JSON => 'application/json',
+    JS => 'application/javascript',
+    PERL => 'application/perl',
+    HTML => 'text/html',
+    XML => 'text/XML',
+    Plain => 'text/plain',
+    UrlEncoded => 'application/x-www-form-urlencoded',
+    Multipart => 'multipart/form-data',
+    HTMLForm => ['application/x-www-form-urlencoded','multipart/form-data'],
+
+Please keep in mind that when dispatching, L<Catalyst> will match the first most
+relevant case, so if you use the C<Consumes> attribute, you should place your
+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