move all core use of "debug" to use "trace" instead (or almost all of them)
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Controller.pm
1 package Catalyst::Controller;
2
3 use Moose;
4 use Class::MOP;
5 use Class::Load ':all';
6 use String::RewritePrefix;
7 use Moose::Util qw/find_meta/;
8 use List::Util qw/first/;
9 use List::MoreUtils qw/uniq/;
10 use namespace::clean -except => 'meta';
11
12 BEGIN {
13     extends qw/Catalyst::Component/;
14     with qw/MooseX::MethodAttributes::Role::AttrContainer::Inheritable/;
15 }
16
17 use MooseX::MethodAttributes;
18 use Catalyst::Exception;
19 use Catalyst::Utils;
20
21 with 'Catalyst::Component::ApplicationAttribute';
22
23 has path_prefix => (
24     is        => 'rw',
25     isa       => 'Str',
26     init_arg  => 'path',
27     predicate => 'has_path_prefix',
28 );
29
30 has action_namespace => (
31     is        => 'rw',
32     isa       => 'Str',
33     init_arg  => 'namespace',
34     predicate => 'has_action_namespace',
35 );
36
37 has actions => (
38     accessor => '_controller_actions',
39     isa      => 'HashRef',
40     init_arg => undef,
41 );
42
43 has _action_role_args => (
44     traits     => [qw(Array)],
45     isa        => 'ArrayRef[Str]',
46     init_arg   => 'action_roles',
47     default    => sub { [] },
48     handles    => {
49         _action_role_args => 'elements',
50     },
51 );
52
53 has _action_roles => (
54     traits     => [qw(Array)],
55     isa        => 'ArrayRef[RoleName]',
56     init_arg   => undef,
57     lazy       => 1,
58     builder    => '_build__action_roles',
59     handles    => {
60         _action_roles => 'elements',
61     },
62 );
63
64 has action_args => (is => 'ro');
65
66 # ->config(actions => { '*' => ...
67 has _all_actions_attributes => (
68     is       => 'ro',
69     isa      => 'HashRef',
70     init_arg => undef,
71     lazy     => 1,
72     builder  => '_build__all_actions_attributes',
73 );
74
75 sub BUILD {
76     my ($self, $args) = @_;
77     my $action  = delete $args->{action}  || {};
78     my $actions = delete $args->{actions} || {};
79     my $attr_value = $self->merge_config_hashes($actions, $action);
80     $self->_controller_actions($attr_value);
81
82     # trigger lazy builder
83     $self->_all_actions_attributes;
84     $self->_action_roles;
85 }
86
87 sub _build__action_roles {
88     my $self = shift;
89     my @roles = $self->_expand_role_shortname($self->_action_role_args);
90     load_class($_) for @roles;
91     return \@roles;
92 }
93
94 sub _build__all_actions_attributes {
95     my ($self) = @_;
96     delete $self->_controller_actions->{'*'} || {};
97 }
98
99 =head1 NAME
100
101 Catalyst::Controller - Catalyst Controller base class
102
103 =head1 SYNOPSIS
104
105   package MyApp::Controller::Search
106   use base qw/Catalyst::Controller/;
107
108   sub foo : Local {
109     my ($self,$c,@args) = @_;
110     ...
111   } # Dispatches to /search/foo
112
113 =head1 DESCRIPTION
114
115 Controllers are where the actions in the Catalyst framework
116 reside. Each action is represented by a function with an attribute to
117 identify what kind of action it is. See the L<Catalyst::Dispatcher>
118 for more info about how Catalyst dispatches to actions.
119
120 =cut
121
122 #I think both of these could be attributes. doesn't really seem like they need
123 #to be class data. i think that attributes +default would work just fine
124 __PACKAGE__->mk_classdata($_) for qw/_dispatch_steps _action_class _action_role_prefix/;
125
126 __PACKAGE__->_dispatch_steps( [qw/_BEGIN _AUTO _ACTION/] );
127 __PACKAGE__->_action_class('Catalyst::Action');
128 __PACKAGE__->_action_role_prefix([ 'Catalyst::ActionRole::' ]);
129
130
131 sub _DISPATCH : Private {
132     my ( $self, $c ) = @_;
133
134     foreach my $disp ( @{ $self->_dispatch_steps } ) {
135         last unless $c->forward($disp);
136     }
137
138     $c->forward('_END');
139 }
140
141 sub _BEGIN : Private {
142     my ( $self, $c ) = @_;
143     my $begin = ( $c->get_actions( 'begin', $c->namespace ) )[-1];
144     return 1 unless $begin;
145     $begin->dispatch( $c );
146     return !@{ $c->error };
147 }
148
149 sub _AUTO : Private {
150     my ( $self, $c ) = @_;
151     my @auto = $c->get_actions( 'auto', $c->namespace );
152     foreach my $auto (@auto) {
153         $auto->dispatch( $c );
154         return 0 unless $c->state;
155     }
156     return 1;
157 }
158
159 sub _ACTION : Private {
160     my ( $self, $c ) = @_;
161     if (   ref $c->action
162         && $c->action->can('execute')
163         && defined $c->req->action )
164     {
165         $c->action->dispatch( $c );
166     }
167     return !@{ $c->error };
168 }
169
170 sub _END : Private {
171     my ( $self, $c ) = @_;
172     my $end = ( $c->get_actions( 'end', $c->namespace ) )[-1];
173     return 1 unless $end;
174     $end->dispatch( $c );
175     return !@{ $c->error };
176 }
177
178 sub action_for {
179     my ( $self, $name ) = @_;
180     my $app = ($self->isa('Catalyst') ? $self : $self->_application);
181     return $app->dispatcher->get_action($name, $self->action_namespace);
182 }
183
184 #my opinion is that this whole sub really should be a builder method, not
185 #something that happens on every call. Anyone else disagree?? -- groditi
186 ## -- apparently this is all just waiting for app/ctx split
187 around action_namespace => sub {
188     my $orig = shift;
189     my ( $self, $c ) = @_;
190
191     my $class = ref($self) || $self;
192     my $appclass = ref($c) || $c;
193     if( ref($self) ){
194         return $self->$orig if $self->has_action_namespace;
195     } else {
196         return $class->config->{namespace} if exists $class->config->{namespace};
197     }
198
199     my $case_s;
200     if( $c ){
201         $case_s = $appclass->config->{case_sensitive};
202     } else {
203         if ($self->isa('Catalyst')) {
204             $case_s = $class->config->{case_sensitive};
205         } else {
206             if (ref $self) {
207                 $case_s = ref($self->_application)->config->{case_sensitive};
208             } else {
209                 confess("Can't figure out case_sensitive setting");
210             }
211         }
212     }
213
214     my $namespace = Catalyst::Utils::class2prefix($self->catalyst_component_name, $case_s) || '';
215     $self->$orig($namespace) if ref($self);
216     return $namespace;
217 };
218
219 #Once again, this is probably better written as a builder method
220 around path_prefix => sub {
221     my $orig = shift;
222     my $self = shift;
223     if( ref($self) ){
224       return $self->$orig if $self->has_path_prefix;
225     } else {
226       return $self->config->{path} if exists $self->config->{path};
227     }
228     my $namespace = $self->action_namespace(@_);
229     $self->$orig($namespace) if ref($self);
230     return $namespace;
231 };
232
233 sub get_action_methods {
234     my $self = shift;
235     my $meta = find_meta($self) || confess("No metaclass setup for $self");
236     confess(
237         sprintf "Metaclass %s for %s cannot support register_actions.",
238             ref $meta, $meta->name,
239     ) unless $meta->can('get_nearest_methods_with_attributes');
240     my @methods = $meta->get_nearest_methods_with_attributes;
241
242     # actions specified via config are also action_methods
243     push(
244         @methods,
245         map {
246             $meta->find_method_by_name($_)
247                 || confess( sprintf 'Action "%s" is not available from controller %s',
248                             $_, ref $self )
249         } keys %{ $self->_controller_actions }
250     ) if ( ref $self );
251     return uniq @methods;
252 }
253
254
255 sub register_actions {
256     my ( $self, $c ) = @_;
257     $self->register_action_methods( $c, $self->get_action_methods );
258 }
259
260 sub register_action_methods {
261     my ( $self, $c, @methods ) = @_;
262     my $class = $self->catalyst_component_name;
263     #this is still not correct for some reason.
264     my $namespace = $self->action_namespace($c);
265
266     # FIXME - fugly
267     if (!blessed($self) && $self eq $c && scalar(@methods)) {
268         my @really_bad_methods = grep { ! /^_(DISPATCH|BEGIN|AUTO|ACTION|END)$/ } map { $_->name } @methods;
269         if (scalar(@really_bad_methods)) {
270             $c->log->warn("Action methods (" . join(', ', @really_bad_methods) . ") found defined in your application class, $self. This is deprecated, please move them into a Root controller.");
271         }
272     }
273
274     foreach my $method (@methods) {
275         my $name = $method->name;
276         # Horrible hack! All method metaclasses should have an attributes
277         # method, core Moose bug - see r13354.
278         my $attributes = $method->can('attributes') ? $method->attributes : [];
279         my $attrs = $self->_parse_attrs( $c, $name, @{ $attributes } );
280         if ( $attrs->{Private} && ( keys %$attrs > 1 ) ) {
281             $c->trace(1, 'Bad action definition "'
282                   . join( ' ', @{ $attributes } )
283                   . qq/" for "$class->$name"/ );
284             next;
285         }
286         my $reverse = $namespace ? "${namespace}/${name}" : $name;
287         my $action = $self->create_action(
288             name       => $name,
289             code       => $method->body,
290             reverse    => $reverse,
291             namespace  => $namespace,
292             class      => $class,
293             attributes => $attrs,
294         );
295
296         $c->dispatcher->register( $c, $action );
297     }
298 }
299
300 sub _apply_action_class_roles {
301     my ($self, $class, @roles) = @_;
302
303     load_class($_) for @roles;
304     my $meta = Moose::Meta::Class->initialize($class)->create_anon_class(
305         superclasses => [$class],
306         roles        => \@roles,
307         cache        => 1,
308     );
309     $meta->add_method(meta => sub { $meta });
310
311     return $meta->name;
312 }
313
314 sub action_class {
315     my $self = shift;
316     my %args = @_;
317
318     my $class = (exists $args{attributes}{ActionClass}
319         ? $args{attributes}{ActionClass}[0]
320         : $self->_action_class);
321
322     load_class($class);
323     return $class;
324 }
325
326 sub create_action {
327     my $self = shift;
328     my %args = @_;
329
330     my $class = $self->action_class(%args);
331
332     load_class($class);
333     Moose->init_meta(for_class => $class)
334         unless Class::MOP::does_metaclass_exist($class);
335
336     unless ($args{name} =~ /^_(DISPATCH|BEGIN|AUTO|ACTION|END)$/) {
337        my @roles = $self->gather_action_roles(%args);
338        push @roles, $self->gather_default_action_roles(%args);
339
340        $class = $self->_apply_action_class_roles($class, @roles) if @roles;
341     }
342
343     my $action_args = (
344         ref($self)
345             ? $self->action_args
346             : $self->config->{action_args}
347     );
348
349     my %extra_args = (
350         %{ $action_args->{'*'}           || {} },
351         %{ $action_args->{ $args{name} } || {} },
352     );
353
354     return $class->new({ %extra_args, %args });
355 }
356
357 sub gather_action_roles {
358    my ($self, %args) = @_;
359    return (
360       (blessed $self ? $self->_action_roles : ()),
361       @{ $args{attributes}->{Does} || [] },
362    );
363 }
364
365 sub gather_default_action_roles {
366   my ($self, %args) = @_;
367   my @roles = ();
368   push @roles, 'Catalyst::ActionRole::HTTPMethods'
369     if $args{attributes}->{Method};
370
371   push @roles, 'Catalyst::ActionRole::ConsumesContent'
372     if $args{attributes}->{Consumes};
373
374     return @roles;
375 }
376
377 sub _parse_attrs {
378     my ( $self, $c, $name, @attrs ) = @_;
379
380     my %raw_attributes;
381
382     foreach my $attr (@attrs) {
383
384         # Parse out :Foo(bar) into Foo => bar etc (and arrayify)
385
386         if ( my ( $key, $value ) = ( $attr =~ /^(.*?)(?:\(\s*(.+?)\s*\))?$/ ) )
387         {
388
389             if ( defined $value ) {
390                 ( $value =~ s/^'(.*)'$/$1/ ) || ( $value =~ s/^"(.*)"/$1/ );
391             }
392             push( @{ $raw_attributes{$key} }, $value );
393         }
394     }
395
396     my ($actions_config, $all_actions_config);
397     if( ref($self) ) {
398         $actions_config = $self->_controller_actions;
399         # No, you're not getting actions => { '*' => ... } with actions in MyApp.
400         $all_actions_config = $self->_all_actions_attributes;
401     } else {
402         my $cfg = $self->config;
403         $actions_config = $self->merge_config_hashes($cfg->{actions}, $cfg->{action});
404         $all_actions_config = {};
405     }
406
407     %raw_attributes = (
408         %raw_attributes,
409         # Note we deep copy array refs here to stop crapping on config
410         # when attributes are parsed. RT#65463
411         exists $actions_config->{$name} ? map { ref($_) eq 'ARRAY' ? [ @$_ ] : $_ } %{ $actions_config->{$name } } : (),
412     );
413
414     # Private actions with additional attributes will raise a warning and then
415     # be ignored. Adding '*' arguments to the default _DISPATCH / etc. methods,
416     # which are Private, will prevent those from being registered. They should
417     # probably be turned into :Actions instead, or we might want to otherwise
418     # disambiguate between those built-in internal actions and user-level
419     # Private ones.
420     %raw_attributes = (%{ $all_actions_config }, %raw_attributes)
421         unless $raw_attributes{Private};
422
423     my %final_attributes;
424
425     while (my ($key, $value) = each %raw_attributes){
426         my $new_attrs = $self->_parse_attr($c, $name, $key => $value );
427         push @{ $final_attributes{$_} }, @{ $new_attrs->{$_} } for keys %$new_attrs;
428     }
429
430     return \%final_attributes;
431 }
432
433 sub _parse_attr {
434     my ($self, $c, $name, $key, $values) = @_;
435
436     my %final_attributes;
437     foreach my $value (ref($values) eq 'ARRAY' ? @$values : $values) {
438         my $meth = "_parse_${key}_attr";
439         if ( my $code = $self->can($meth) ) {
440             my %new_attrs = $self->$code( $c, $name, $value );
441             while (my ($new_key, $value) = each %new_attrs){
442                 my $new_attrs = $key eq $new_key ?
443                     { $new_key => [$value] } :
444                     $self->_parse_attr($c, $name, $new_key => $value );
445                 push @{ $final_attributes{$_} }, @{ $new_attrs->{$_} } for keys %$new_attrs;
446             }
447         }
448         else {
449             push( @{ $final_attributes{$key} }, $value );
450         }
451     }
452
453     return \%final_attributes;
454 }
455
456 sub _parse_Global_attr {
457     my ( $self, $c, $name, $value ) = @_;
458     # _parse_attr will call _parse_Path_attr for us
459     return Path => "/$name";
460 }
461
462 sub _parse_Absolute_attr { shift->_parse_Global_attr(@_); }
463
464 sub _parse_Local_attr {
465     my ( $self, $c, $name, $value ) = @_;
466     # _parse_attr will call _parse_Path_attr for us
467     return Path => $name;
468 }
469
470 sub _parse_Relative_attr { shift->_parse_Local_attr(@_); }
471
472 sub _parse_Path_attr {
473     my ( $self, $c, $name, $value ) = @_;
474     $value = '' if !defined $value;
475     if ( $value =~ m!^/! ) {
476         return ( 'Path', $value );
477     }
478     elsif ( length $value ) {
479         return ( 'Path', join( '/', $self->path_prefix($c), $value ) );
480     }
481     else {
482         return ( 'Path', $self->path_prefix($c) );
483     }
484 }
485
486 sub _parse_Chained_attr {
487     my ($self, $c, $name, $value) = @_;
488
489     if (defined($value) && length($value)) {
490         if ($value eq '.') {
491             $value = '/'.$self->action_namespace($c);
492         } elsif (my ($rel, $rest) = $value =~ /^((?:\.{2}\/)+)(.*)$/) {
493             my @parts = split '/', $self->action_namespace($c);
494             my @levels = split '/', $rel;
495
496             $value = '/'.join('/', @parts[0 .. $#parts - @levels], $rest);
497         } elsif ($value !~ m/^\//) {
498             my $action_ns = $self->action_namespace($c);
499
500             if ($action_ns) {
501                 $value = '/'.join('/', $action_ns, $value);
502             } else {
503                 $value = '/'.$value; # special case namespace '' (root)
504             }
505         }
506     } else {
507         $value = '/'
508     }
509
510     return Chained => $value;
511 }
512
513 sub _parse_ChainedParent_attr {
514     my ($self, $c, $name, $value) = @_;
515     return $self->_parse_Chained_attr($c, $name, '../'.$name);
516 }
517
518 sub _parse_PathPrefix_attr {
519     my ( $self, $c ) = @_;
520     return PathPart => $self->path_prefix($c);
521 }
522
523 sub _parse_ActionClass_attr {
524     my ( $self, $c, $name, $value ) = @_;
525     my $appname = $self->_application;
526     $value = Catalyst::Utils::resolve_namespace($appname . '::Action', $self->_action_class, $value);
527     return ( 'ActionClass', $value );
528 }
529
530 sub _parse_MyAction_attr {
531     my ( $self, $c, $name, $value ) = @_;
532
533     my $appclass = Catalyst::Utils::class2appclass($self);
534     $value = "+${appclass}::Action::${value}";
535
536     return ( 'ActionClass', $value );
537 }
538
539 sub _parse_Does_attr {
540     my ($self, $app, $name, $value) = @_;
541     return Does => $self->_expand_role_shortname($value);
542 }
543
544 sub _parse_GET_attr    { Method => 'GET'    }
545 sub _parse_POST_attr   { Method => 'POST'   }
546 sub _parse_PUT_attr    { Method => 'PUT'    }
547 sub _parse_DELETE_attr { Method => 'DELETE' }
548 sub _parse_OPTION_attr { Method => 'OPTION' }
549 sub _parse_HEAD_attr   { Method => 'HEAD'   }
550
551 sub _expand_role_shortname {
552     my ($self, @shortnames) = @_;
553     my $app = $self->_application;
554
555     my $prefix = $self->can('_action_role_prefix') ? $self->_action_role_prefix : ['Catalyst::ActionRole::'];
556     my @prefixes = (qq{${app}::ActionRole::}, @$prefix);
557
558     return String::RewritePrefix->rewrite(
559         { ''  => sub {
560             my $loaded = load_first_existing_class(
561                 map { "$_$_[0]" } @prefixes
562             );
563             return first { $loaded =~ /^$_/ }
564               sort { length $b <=> length $a } @prefixes;
565           },
566           '~' => $prefixes[0],
567           '+' => '' },
568         @shortnames,
569     );
570 }
571
572 __PACKAGE__->meta->make_immutable;
573
574 1;
575
576 __END__
577
578 =head1 CONFIGURATION
579
580 Like any other L<Catalyst::Component>, controllers have a config hash,
581 accessible through $self->config from the controller actions.  Some
582 settings are in use by the Catalyst framework:
583
584 =head2 namespace
585
586 This specifies the internal namespace the controller should be bound
587 to. By default the controller is bound to the URI version of the
588 controller name. For instance controller 'MyApp::Controller::Foo::Bar'
589 will be bound to 'foo/bar'. The default Root controller is an example
590 of setting namespace to '' (the null string).
591
592 =head2 path
593
594 Sets 'path_prefix', as described below.
595
596 =head2 action
597
598 Allows you to set the attributes that the dispatcher creates actions out of.
599 This allows you to do 'rails style routes', or override some of the
600 attribute definitions of actions composed from Roles.
601 You can set arguments globally (for all actions of the controller) and
602 specifically (for a single action).
603
604     __PACKAGE__->config(
605         action => {
606             '*' => { Chained => 'base', Args => 0  },
607             base => { Chained => '/', PathPart => '', CaptureArgs => 0 },
608         },
609      );
610
611 In the case above every sub in the package would be made into a Chain
612 endpoint with a URI the same as the sub name for each sub, chained
613 to the sub named C<base>. Ergo dispatch to C</example> would call the
614 C<base> method, then the C<example> method.
615
616 =head2 action_args
617
618 Allows you to set constructor arguments on your actions. You can set arguments
619 globally and specifically (as above).
620 This is particularly useful when using C<ActionRole>s
621 (L<Catalyst::Controller::ActionRole>) and custom C<ActionClass>es.
622
623     __PACKAGE__->config(
624         action_args => {
625             '*' => { globalarg1 => 'hello', globalarg2 => 'goodbye' },
626             'specific_action' => { customarg => 'arg1' },
627         },
628      );
629
630 In the case above the action class associated with C<specific_action> would get
631 passed the following arguments, in addition to the normal action constructor
632 arguments, when it is instantiated:
633
634   (globalarg1 => 'hello', globalarg2 => 'goodbye', customarg => 'arg1')
635
636 =head1 METHODS
637
638 =head2 BUILDARGS ($app, @args)
639
640 From L<Catalyst::Component::ApplicationAttribute>, stashes the application
641 instance as $self->_application.
642
643 =head2 $self->action_for('name')
644
645 Returns the Catalyst::Action object (if any) for a given method name
646 in this component.
647
648 =head2 $self->action_namespace($c)
649
650 Returns the private namespace for actions in this component. Defaults
651 to a value from the controller name (for
652 e.g. MyApp::Controller::Foo::Bar becomes "foo/bar") or can be
653 overridden from the "namespace" config key.
654
655
656 =head2 $self->path_prefix($c)
657
658 Returns the default path prefix for :PathPrefix, :Local and
659 relative :Path actions in this component. Defaults to the action_namespace or
660 can be overridden from the "path" config key.
661
662 =head2 $self->register_actions($c)
663
664 Finds all applicable actions for this component, creates
665 Catalyst::Action objects (using $self->create_action) for them and
666 registers them with $c->dispatcher.
667
668 =head2 $self->get_action_methods()
669
670 Returns a list of L<Moose::Meta::Method> objects, doing the
671 L<MooseX::MethodAttributes::Role::Meta::Method> role, which are the set of
672 action methods for this package.
673
674 =head2 $self->register_action_methods($c, @methods)
675
676 Creates action objects for a set of action methods using C< create_action >,
677 and registers them with the dispatcher.
678
679 =head2 $self->action_class(%args)
680
681 Used when a controller is creating an action to determine the correct base
682 action class to use.
683
684 =head2 $self->create_action(%args)
685
686 Called with a hash of data to be use for construction of a new
687 Catalyst::Action (or appropriate sub/alternative class) object.
688
689 =head2 $self->gather_action_roles(\%action_args)
690
691 Gathers the list of roles to apply to an action with the given %action_args.
692
693 =head2 $self->gather_default_action_roles(\%action_args)
694
695 returns a list of action roles to be applied based on core, builtin rules.
696 Currently only the L<Catalyst::ActionRole::HTTPMethods> role is applied
697 this way.
698
699 =head2 $self->_application
700
701 =head2 $self->_app
702
703 Returns the application instance stored by C<new()>
704
705 =head1 ACTION SUBROUTINE ATTRIBUTES
706
707 Please see L<Catalyst::Manual::Intro> for more details
708
709 Think of action attributes as a sort of way to record metadata about an action,
710 similar to how annotations work in other languages you might have heard of.
711 Generally L<Catalyst> uses these to influence how the dispatcher sees your
712 action and when it will run it in response to an incoming request.  They can
713 also be used for other things.  Here's a summary, but you should refer to the
714 linked manual page for additional help.
715
716 =head2 Global
717
718   sub homepage :Global { ... }
719
720 A global action defined in any controller always runs relative to your root.
721 So the above is the same as:
722
723   sub myaction :Path("/homepage") { ... }
724
725 =head2 Absolute
726
727 Status: Deprecated alias to L</Global>.
728
729 =head2 Local
730
731 Alias to "Path("$action_name").  The following two actions are the same:
732
733   sub myaction :Local { ... }
734   sub myaction :Path('myaction') { ... }
735
736 =head2 Relative
737
738 Status: Deprecated alias to L</Local>
739
740 =head2 Path
741
742 Handle various types of paths:
743
744   package MyApp::Controller::Baz {
745
746     ...
747
748     sub myaction1 :Path { ... }  # -> /baz
749     sub myaction2 :Path('foo') { ... } # -> /baz/foo
750     sub myaction2 :Path('/bar') { ... } # -> /bar
751   }
752
753 This is a general toolbox for attaching your action to a given path.
754
755
756 =head2 Regex
757
758 =head2 Regexp
759
760 B<Status: Deprecated.>  Use Chained methods or other techniques.
761 If you really depend on this, install the standalone 
762 L<Catalyst::DispatchType::Regex> distribution.
763
764 A global way to match a give regular expression in the incoming request path.
765
766 =head2 LocalRegex
767
768 =head2 LocalRegexp
769
770 B<Status: Deprecated.>  Use Chained methods or other techniques.
771 If you really depend on this, install the standalone 
772 L<Catalyst::DispatchType::Regex> distribution.
773
774 Like L</Regex> but scoped under the namespace of the containing controller
775
776 =head2 Chained 
777
778 =head2 ChainedParent
779
780 =head2 PathPrefix
781
782 =head2 PathPart
783
784 =head2 CaptureArgs
785
786 Please see L<Catalyst::DispatchType::Chained>
787
788 =head2 ActionClass
789
790 Set the base class for the action, defaults to L</Catalyst::Action>.  It is now
791 preferred to use L</Does>.
792
793 =head2 MyAction
794
795 Set the ActionClass using a custom Action in your project namespace.
796
797 The following is exactly the same:
798
799     sub foo_action1 : Local ActionClass('+MyApp::Action::Bar') { ... }
800     sub foo_action2 : Local MyAction('Bar') { ... }
801
802 =head2 Does
803
804     package MyApp::Controller::Zoo;
805
806     sub foo  : Local Does('Moo')  { ... } # Catalyst::ActionRole::
807     sub bar  : Local Does('~Moo') { ... } # MyApp::ActionRole::Moo
808     sub baz  : Local Does('+MyApp::ActionRole::Moo') { ... }
809
810 =head2 GET
811
812 =head2 POST
813
814 =head2 PUT
815
816 =head2 DELETE
817
818 =head2 OPTION
819
820 =head2 HEAD
821
822 =head2 PATCH
823
824 =head2 Method('...')
825
826 Sets the give action path to match the specified HTTP method, or via one of the
827 broadly accepted methods of overriding the 'true' method (see
828 L<Catalyst::ActionRole::HTTPMethods>).
829
830 =head2 Args
831
832 When used with L</Path> indicates the number of arguments expected in
833 the path.  However if no Args value is set, assumed to 'slurp' all
834 remaining path pars under this namespace.
835
836 =head2 Consumes('...')
837
838 Matches the current action against the content-type of the request.  Typically
839 this is used when the request is a POST or PUT and you want to restrict the
840 submitted content type.  For example, you might have an HTML for that either
841 returns classic url encoded form data, or JSON when Javascript is enabled.  In
842 this case you may wish to match either incoming type to one of two different
843 actions, for properly processing.
844
845 Examples:
846
847     sub is_json       : Chained('start') Consumes('application/json') { ... }
848     sub is_urlencoded : Chained('start') Consumes('application/x-www-form-urlencoded') { ... }
849     sub is_multipart  : Chained('start') Consumes('multipart/form-data') { ... }
850
851 To reduce boilerplate, we include the following content type shortcuts:
852
853 Examples
854
855       sub is_json       : Chained('start') Consume(JSON) { ... }
856       sub is_urlencoded : Chained('start') Consumes(UrlEncoded) { ... }
857       sub is_multipart  : Chained('start') Consumes(Multipart) { ... }
858
859 You may specify more than one match:
860
861       sub is_more_than_one
862         : Chained('start')
863         : Consumes('application/x-www-form-urlencoded')
864         : Consumes('multipart/form-data')
865
866       sub is_more_than_one
867         : Chained('start')
868         : Consumes(UrlEncoded)
869         : Consumes(Multipart)
870
871 Since it is a common case the shortcut C<HTMLForm> matches both
872 'application/x-www-form-urlencoded' and 'multipart/form-data'.  Here's the full
873 list of available shortcuts:
874
875     JSON => 'application/json',
876     JS => 'application/javascript',
877     PERL => 'application/perl',
878     HTML => 'text/html',
879     XML => 'text/XML',
880     Plain => 'text/plain',
881     UrlEncoded => 'application/x-www-form-urlencoded',
882     Multipart => 'multipart/form-data',
883     HTMLForm => ['application/x-www-form-urlencoded','multipart/form-data'],
884
885 Please keep in mind that when dispatching, L<Catalyst> will match the first most
886 relevant case, so if you use the C<Consumes> attribute, you should place your
887 most accurate matches early in the Chain, and your 'catchall' actions last.
888
889 See L<Catalyst::ActionRole::ConsumesContent> for more.
890
891 =head1 OPTIONAL METHODS
892
893 =head2 _parse_[$name]_attr
894
895 Allows you to customize parsing of subroutine attributes.
896
897     sub myaction1 :Path TwoArgs { ... }
898
899     sub _parse_TwoArgs_attr {
900       my ( $self, $c, $name, $value ) = @_;
901       # $self -> controller instance
902       #
903       return(Args => 2);
904     }
905
906 Please note that this feature does not let you actually assign new functions
907 to actions via subroutine attributes, but is really more for creating useful
908 aliases to existing core and extended attributes, and transforms based on 
909 existing information (like from configuration).  Code for actually doing
910 something meaningful with the subroutine attributes will be located in the
911 L<Catalyst::Action> classes (or your subclasses), L<Catalyst::Dispatcher> and
912 in subclasses of L<Catalyst::DispatchType>.  Remember these methods only get
913 called basically once when the application is starting, not per request!
914
915 =head1 AUTHORS
916
917 Catalyst Contributors, see Catalyst.pm
918
919 =head1 COPYRIGHT
920
921 This library is free software. You can redistribute it and/or modify
922 it under the same terms as Perl itself.
923
924 =cut