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