use actionrole instead of core for the new http method support
[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        push @roles, $self->gather_default_action_roles(%args);
337
338        $class = $self->_apply_action_class_roles($class, @roles) if @roles;
339     }
340
341     my $action_args = (
342         ref($self)
343             ? $self->action_args
344             : $self->config->{action_args}
345     );
346
347     my %extra_args = (
348         %{ $action_args->{'*'}           || {} },
349         %{ $action_args->{ $args{name} } || {} },
350     );
351
352     return $class->new({ %extra_args, %args });
353 }
354
355 sub gather_action_roles {
356    my ($self, %args) = @_;
357    return (
358       (blessed $self ? $self->_action_roles : ()),
359       @{ $args{attributes}->{Does} || [] },
360    );
361 }
362
363 sub gather_default_action_roles {
364   my ($self, %args) = @_;
365   my @roles = ();
366   push @roles, 'Catalyst::ActionRole::HTTPMethods'
367     if $args{attributes}->{Method};
368   return @roles;
369 }
370
371 sub _parse_attrs {
372     my ( $self, $c, $name, @attrs ) = @_;
373
374     my %raw_attributes;
375
376     foreach my $attr (@attrs) {
377
378         # Parse out :Foo(bar) into Foo => bar etc (and arrayify)
379
380         if ( my ( $key, $value ) = ( $attr =~ /^(.*?)(?:\(\s*(.+?)\s*\))?$/ ) )
381         {
382
383             if ( defined $value ) {
384                 ( $value =~ s/^'(.*)'$/$1/ ) || ( $value =~ s/^"(.*)"/$1/ );
385             }
386             push( @{ $raw_attributes{$key} }, $value );
387         }
388     }
389
390     my ($actions_config, $all_actions_config);
391     if( ref($self) ) {
392         $actions_config = $self->_controller_actions;
393         # No, you're not getting actions => { '*' => ... } with actions in MyApp.
394         $all_actions_config = $self->_all_actions_attributes;
395     } else {
396         my $cfg = $self->config;
397         $actions_config = $self->merge_config_hashes($cfg->{actions}, $cfg->{action});
398         $all_actions_config = {};
399     }
400
401     %raw_attributes = (
402         %raw_attributes,
403         # Note we deep copy array refs here to stop crapping on config
404         # when attributes are parsed. RT#65463
405         exists $actions_config->{$name} ? map { ref($_) eq 'ARRAY' ? [ @$_ ] : $_ } %{ $actions_config->{$name } } : (),
406     );
407
408     # Private actions with additional attributes will raise a warning and then
409     # be ignored. Adding '*' arguments to the default _DISPATCH / etc. methods,
410     # which are Private, will prevent those from being registered. They should
411     # probably be turned into :Actions instead, or we might want to otherwise
412     # disambiguate between those built-in internal actions and user-level
413     # Private ones.
414     %raw_attributes = (%{ $all_actions_config }, %raw_attributes)
415         unless $raw_attributes{Private};
416
417     my %final_attributes;
418
419     while (my ($key, $value) = each %raw_attributes){
420         my $new_attrs = $self->_parse_attr($c, $name, $key => $value );
421         push @{ $final_attributes{$_} }, @{ $new_attrs->{$_} } for keys %$new_attrs;
422     }
423
424     return \%final_attributes;
425 }
426
427 sub _parse_attr {
428     my ($self, $c, $name, $key, $values) = @_;
429
430     my %final_attributes;
431     foreach my $value (ref($values) eq 'ARRAY' ? @$values : $values) {
432         my $meth = "_parse_${key}_attr";
433         if ( my $code = $self->can($meth) ) {
434             my %new_attrs = $self->$code( $c, $name, $value );
435             while (my ($new_key, $value) = each %new_attrs){
436                 my $new_attrs = $key eq $new_key ?
437                     { $new_key => [$value] } :
438                     $self->_parse_attr($c, $name, $new_key => $value );
439                 push @{ $final_attributes{$_} }, @{ $new_attrs->{$_} } for keys %$new_attrs;
440             }
441         }
442         else {
443             push( @{ $final_attributes{$key} }, $value );
444         }
445     }
446
447     return \%final_attributes;
448 }
449
450 sub _parse_Global_attr {
451     my ( $self, $c, $name, $value ) = @_;
452     # _parse_attr will call _parse_Path_attr for us
453     return Path => "/$name";
454 }
455
456 sub _parse_Absolute_attr { shift->_parse_Global_attr(@_); }
457
458 sub _parse_Local_attr {
459     my ( $self, $c, $name, $value ) = @_;
460     # _parse_attr will call _parse_Path_attr for us
461     return Path => $name;
462 }
463
464 sub _parse_Relative_attr { shift->_parse_Local_attr(@_); }
465
466 sub _parse_Path_attr {
467     my ( $self, $c, $name, $value ) = @_;
468     $value = '' if !defined $value;
469     if ( $value =~ m!^/! ) {
470         return ( 'Path', $value );
471     }
472     elsif ( length $value ) {
473         return ( 'Path', join( '/', $self->path_prefix($c), $value ) );
474     }
475     else {
476         return ( 'Path', $self->path_prefix($c) );
477     }
478 }
479
480 sub _parse_Regex_attr {
481     my ( $self, $c, $name, $value ) = @_;
482     return ( 'Regex', $value );
483 }
484
485 sub _parse_Regexp_attr { shift->_parse_Regex_attr(@_); }
486
487 sub _parse_LocalRegex_attr {
488     my ( $self, $c, $name, $value ) = @_;
489     unless ( $value =~ s/^\^// ) { $value = "(?:.*?)$value"; }
490
491     my $prefix = $self->path_prefix( $c );
492     $prefix .= '/' if length( $prefix );
493
494     return ( 'Regex', "^${prefix}${value}" );
495 }
496
497 sub _parse_LocalRegexp_attr { shift->_parse_LocalRegex_attr(@_); }
498
499 sub _parse_Chained_attr {
500     my ($self, $c, $name, $value) = @_;
501
502     if (defined($value) && length($value)) {
503         if ($value eq '.') {
504             $value = '/'.$self->action_namespace($c);
505         } elsif (my ($rel, $rest) = $value =~ /^((?:\.{2}\/)+)(.*)$/) {
506             my @parts = split '/', $self->action_namespace($c);
507             my @levels = split '/', $rel;
508
509             $value = '/'.join('/', @parts[0 .. $#parts - @levels], $rest);
510         } elsif ($value !~ m/^\//) {
511             my $action_ns = $self->action_namespace($c);
512
513             if ($action_ns) {
514                 $value = '/'.join('/', $action_ns, $value);
515             } else {
516                 $value = '/'.$value; # special case namespace '' (root)
517             }
518         }
519     } else {
520         $value = '/'
521     }
522
523     return Chained => $value;
524 }
525
526 sub _parse_ChainedParent_attr {
527     my ($self, $c, $name, $value) = @_;
528     return $self->_parse_Chained_attr($c, $name, '../'.$name);
529 }
530
531 sub _parse_PathPrefix_attr {
532     my ( $self, $c ) = @_;
533     return PathPart => $self->path_prefix($c);
534 }
535
536 sub _parse_ActionClass_attr {
537     my ( $self, $c, $name, $value ) = @_;
538     my $appname = $self->_application;
539     $value = Catalyst::Utils::resolve_namespace($appname . '::Action', $self->_action_class, $value);
540     return ( 'ActionClass', $value );
541 }
542
543 sub _parse_MyAction_attr {
544     my ( $self, $c, $name, $value ) = @_;
545
546     my $appclass = Catalyst::Utils::class2appclass($self);
547     $value = "+${appclass}::Action::${value}";
548
549     return ( 'ActionClass', $value );
550 }
551
552 sub _parse_Does_attr {
553     my ($self, $app, $name, $value) = @_;
554     return Does => $self->_expand_role_shortname($value);
555 }
556
557 sub _parse_GET_attr { Method => 'GET' }
558 sub _parse_POST_attr { Method => 'POST' }
559 sub _parse_PUT_attr { Method => 'PUT' }
560 sub _parse_DELETE_attr { Method => 'DELETE' }
561 sub _parse_OPTION_attr { Method => 'OPTION' }
562 sub _parse_HEAD_attr { Method => 'HEAD' }
563
564 sub _expand_role_shortname {
565     my ($self, @shortnames) = @_;
566     my $app = $self->_application;
567
568     my $prefix = $self->can('_action_role_prefix') ? $self->_action_role_prefix : ['Catalyst::ActionRole::'];
569     my @prefixes = (qq{${app}::ActionRole::}, @$prefix);
570
571     return String::RewritePrefix->rewrite(
572         { ''  => sub {
573             my $loaded = load_first_existing_class(
574                 map { "$_$_[0]" } @prefixes
575             );
576             return first { $loaded =~ /^$_/ }
577               sort { length $b <=> length $a } @prefixes;
578           },
579           '~' => $prefixes[0],
580           '+' => '' },
581         @shortnames,
582     );
583 }
584
585 __PACKAGE__->meta->make_immutable;
586
587 1;
588
589 __END__
590
591 =head1 CONFIGURATION
592
593 Like any other L<Catalyst::Component>, controllers have a config hash,
594 accessible through $self->config from the controller actions.  Some
595 settings are in use by the Catalyst framework:
596
597 =head2 namespace
598
599 This specifies the internal namespace the controller should be bound
600 to. By default the controller is bound to the URI version of the
601 controller name. For instance controller 'MyApp::Controller::Foo::Bar'
602 will be bound to 'foo/bar'. The default Root controller is an example
603 of setting namespace to '' (the null string).
604
605 =head2 path
606
607 Sets 'path_prefix', as described below.
608
609 =head2 action
610
611 Allows you to set the attributes that the dispatcher creates actions out of.
612 This allows you to do 'rails style routes', or override some of the
613 attribute definitions of actions composed from Roles.
614 You can set arguments globally (for all actions of the controller) and
615 specifically (for a single action).
616
617     __PACKAGE__->config(
618         action => {
619             '*' => { Chained => 'base', Args => 0  },
620             base => { Chained => '/', PathPart => '', CaptureArgs => 0 },
621         },
622      );
623
624 In the case above every sub in the package would be made into a Chain
625 endpoint with a URI the same as the sub name for each sub, chained
626 to the sub named C<base>. Ergo dispatch to C</example> would call the
627 C<base> method, then the C<example> method.
628
629 =head2 action_args
630
631 Allows you to set constructor arguments on your actions. You can set arguments
632 globally and specifically (as above).
633 This is particularly useful when using C<ActionRole>s
634 (L<Catalyst::Controller::ActionRole>) and custom C<ActionClass>es.
635
636     __PACKAGE__->config(
637         action_args => {
638             '*' => { globalarg1 => 'hello', globalarg2 => 'goodbye' },
639             'specific_action' => { customarg => 'arg1' },
640         },
641      );
642
643 In the case above the action class associated with C<specific_action> would get
644 passed the following arguments, in addition to the normal action constructor
645 arguments, when it is instantiated:
646
647   (globalarg1 => 'hello', globalarg2 => 'goodbye', customarg => 'arg1')
648
649 =head1 METHODS
650
651 =head2 BUILDARGS ($app, @args)
652
653 From L<Catalyst::Component::ApplicationAttribute>, stashes the application
654 instance as $self->_application.
655
656 =head2 $self->action_for('name')
657
658 Returns the Catalyst::Action object (if any) for a given method name
659 in this component.
660
661 =head2 $self->action_namespace($c)
662
663 Returns the private namespace for actions in this component. Defaults
664 to a value from the controller name (for
665 e.g. MyApp::Controller::Foo::Bar becomes "foo/bar") or can be
666 overridden from the "namespace" config key.
667
668
669 =head2 $self->path_prefix($c)
670
671 Returns the default path prefix for :PathPrefix, :Local, :LocalRegex and
672 relative :Path actions in this component. Defaults to the action_namespace or
673 can be overridden from the "path" config key.
674
675 =head2 $self->register_actions($c)
676
677 Finds all applicable actions for this component, creates
678 Catalyst::Action objects (using $self->create_action) for them and
679 registers them with $c->dispatcher.
680
681 =head2 $self->get_action_methods()
682
683 Returns a list of L<Moose::Meta::Method> objects, doing the
684 L<MooseX::MethodAttributes::Role::Meta::Method> role, which are the set of
685 action methods for this package.
686
687 =head2 $self->register_action_methods($c, @methods)
688
689 Creates action objects for a set of action methods using C< create_action >,
690 and registers them with the dispatcher.
691
692 =head2 $self->action_class(%args)
693
694 Used when a controller is creating an action to determine the correct base
695 action class to use.
696
697 =head2 $self->create_action(%args)
698
699 Called with a hash of data to be use for construction of a new
700 Catalyst::Action (or appropriate sub/alternative class) object.
701
702 =head2 $self->gather_action_roles(\%action_args)
703
704 Gathers the list of roles to apply to an action with the given %action_args.
705
706 =head2 $self->gather_default_action_roles(\%action_args)
707
708 returns a list of action roles to be applied based on core, builtin rules.
709 Currently only the L<Catalyst::ActionRole::HTTPMethods> role is applied
710 this way.
711
712 =head2 $self->_application
713
714 =head2 $self->_app
715
716 Returns the application instance stored by C<new()>
717
718 =head1 ACTION SUBROUTINE ATTRIBUTES
719
720 Please see L<Catalyst::Manual::Intro> for more details
721
722 Think of action attributes as a sort of way to record metadata about an action,
723 similar to how annotations work in other languages you might have heard of.
724 Generally L<Catalyst> uses these to influence how the dispatcher sees your
725 action and when it will run it in response to an incoming request.  They can
726 also be used for other things.  Here's a summary, but you should refer to the
727 liked manual page for additional help.
728
729 =head2 Global
730
731   sub homepage :Global { ... }
732
733 A global action defined in any controller always runs relative to your root.
734 So the above is the same as:
735
736   sub myaction :Path("/homepage") { ... }
737
738 =head2 Absolute
739
740 Status: Deprecated alias to L</Global>.
741
742 =head2 Local
743
744 Alias to "Path("$action_name").  The following two actions are the same:
745
746   sub myaction :Local { ... }
747   sub myaction :Path('myaction') { ... }
748
749 =head2 Relative
750
751 Status: Deprecated alias to L</Local>
752
753 =head2 Path
754
755 Handle various types of paths:
756
757   package MyApp::Controller::Baz {
758
759     ...
760
761     sub myaction1 :Path { ... }  # -> /baz
762     sub myaction2 :Path('foo') { ... } # -> /baz/bar
763     sub myaction2 :Path('/bar') { ... } # -> /bar
764   }
765
766 This is a general toolbox for attaching your action to a give path.
767
768
769 =head2 Regex
770
771 =head2 Regexp
772
773 Status: Deprecated.  Use Chained methods or other techniques
774
775 A global way to match a give regular expression in the incoming request path.
776
777 =head2 LocalRegex
778
779 =head2 LocalRegexp
780
781 Like L</Regex> but scoped under the namespace of the containing controller
782
783 =head2 Chained 
784
785 =head2 ChainedParent
786
787 =head2 PathPrefix
788
789 =head2 PathPart
790
791 =head2 CaptureArgs
792
793 Please see L<Catalyst::DispatchType::Chained>
794
795 =head2 ActionClass
796
797 Set the base class for the action, defaults to L</Catalyst::Action>.  It is now
798 preferred to use L</Does>.
799
800 =head2 MyAction
801
802 Set the ActionClass using a custom Action in your project namespace.
803
804 The following is exactly the same:
805
806     sub foo_action1 : Local ActionClass('+MyApp::Action::Bar') { ... }
807     sub foo_action2 : Local MyAction('Bar') { ... }
808
809 =head2 Does
810
811     package MyApp::Controller::Zoo;
812
813     sub foo  : Local Does('Moo')  { ... } # Catalyst::ActionRole::
814     sub bar  : Local Does('~Moo') { ... } # MyApp::ActionRole::Moo
815     sub baz  : Local Does('+MyApp::ActionRole::Moo') { ... }
816
817 =head2 GET
818
819 =head2 POST
820
821 =head2 PUT
822
823 =head2 DELETE
824
825 =head2 OPTION
826
827 =head2 HEAD
828
829 =head2 PATCH
830
831 =head2 Method('...')
832
833 Sets the give action path to match the specified HTTP method, or via one of the
834 broadly accepted methods of overriding the 'true' method (see
835 L<Catalyst::ActionRole::HTTPMethods>).
836
837 =head2 Args
838
839 When used with L</Path> indicates the number of arguments expected in
840 the path.  However if no Args value is set, assumed to 'slurp' all
841 remaining path pars under this namespace.
842
843 =head1 OPTIONAL METHODS
844
845 =head2 _parse_[$name]_attr
846
847 Allows you to customize parsing of subroutine attributes.
848
849     sub myaction1 :Path TwoArgs { ... }
850
851     sub _parse_TwoArgs_attr {
852       my ( $self, $c, $name, $value ) = @_;
853       # $self -> controller instance
854       #
855       return(Args => 2);
856     }
857
858 Please note that this feature does not let you actually assign new functions
859 to actions via subroutine attributes, but is really more for creating useful
860 aliases to existing core and extended attributes, and transforms based on 
861 existing information (like from configuration).  Code for actually doing
862 something meaningful with the subroutine attributes will be located in the
863 L<Catalyst::Action> classes (or your subclasses), L<Catalyst::Dispatcher> and
864 in subclasses of L<Catalyst::DispatchType>.  Remember these methods only get
865 called basically once when the application is starting, not per request!
866
867 =head1 AUTHORS
868
869 Catalyst Contributors, see Catalyst.pm
870
871 =head1 COPYRIGHT
872
873 This library is free software. You can redistribute it and/or modify
874 it under the same terms as Perl itself.
875
876 =cut