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