Change Catalsyt _parse_attrs so that when sub attr handlers:
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Controller.pm
CommitLineData
5ee249f2 1package Catalyst::Controller;
2
ae29b412 3use Moose;
eff60019 4use Class::MOP;
c6392ad5 5use Class::Load ':all';
eff60019 6use String::RewritePrefix;
a58af53d 7use Moose::Util qw/find_meta/;
eff60019 8use List::Util qw/first/;
4f4ab5b4 9use List::MoreUtils qw/uniq/;
ae29b412 10use namespace::clean -except => 'meta';
11
ba545c13 12BEGIN { extends qw/Catalyst::Component MooseX::MethodAttributes::Inheritable/; }
234763d4 13
cf37d21a 14use MooseX::MethodAttributes;
234763d4 15use Catalyst::Exception;
16use Catalyst::Utils;
ae29b412 17
18with 'Catalyst::Component::ApplicationAttribute';
19
aea897b2 20has path_prefix => (
21 is => 'rw',
22 isa => 'Str',
23 init_arg => 'path',
24 predicate => 'has_path_prefix',
25);
26
27has action_namespace => (
28 is => 'rw',
29 isa => 'Str',
30 init_arg => 'namespace',
31 predicate => 'has_action_namespace',
32);
33
34has actions => (
35 accessor => '_controller_actions',
36 isa => 'HashRef',
37 init_arg => undef,
38);
ae29b412 39
eff60019 40has _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
50has _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
bf7c9c87 61has action_args => (is => 'ro');
62
bdd6684e 63# ->config(actions => { '*' => ...
64has _all_actions_attributes => (
65 is => 'ro',
66 isa => 'HashRef',
67 init_arg => undef,
68 lazy => 1,
69 builder => '_build__all_actions_attributes',
70);
71
7f22a5aa 72sub BUILD {
73 my ($self, $args) = @_;
ae29b412 74 my $action = delete $args->{action} || {};
75 my $actions = delete $args->{actions} || {};
7f22a5aa 76 my $attr_value = $self->merge_config_hashes($actions, $action);
77 $self->_controller_actions($attr_value);
5ee249f2 78
bdd6684e 79 # trigger lazy builder
80 $self->_all_actions_attributes;
eff60019 81 $self->_action_roles;
82}
83
84sub _build__action_roles {
85 my $self = shift;
86 my @roles = $self->_expand_role_shortname($self->_action_role_args);
c6392ad5 87 load_class($_) for @roles;
eff60019 88 return \@roles;
bdd6684e 89}
d0e5dfb5 90
bdd6684e 91sub _build__all_actions_attributes {
92 my ($self) = @_;
93 delete $self->_controller_actions->{'*'} || {};
94}
d0e5dfb5 95
5ee249f2 96=head1 NAME
97
98Catalyst::Controller - Catalyst Controller base class
99
100=head1 SYNOPSIS
101
234763d4 102 package MyApp::Controller::Search
a269e0c2 103 use base qw/Catalyst::Controller/;
234763d4 104
27ae4114 105 sub foo : Local {
85d9fce6 106 my ($self,$c,@args) = @_;
27ae4114 107 ...
234763d4 108 } # Dispatches to /search/foo
5ee249f2 109
110=head1 DESCRIPTION
111
a269e0c2 112Controllers are where the actions in the Catalyst framework
113reside. Each action is represented by a function with an attribute to
114identify what kind of action it is. See the L<Catalyst::Dispatcher>
115for more info about how Catalyst dispatches to actions.
234763d4 116
117=cut
118
ae29b412 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
eff60019 121__PACKAGE__->mk_classdata($_) for qw/_dispatch_steps _action_class _action_role_prefix/;
234763d4 122
123__PACKAGE__->_dispatch_steps( [qw/_BEGIN _AUTO _ACTION/] );
7b41db70 124__PACKAGE__->_action_class('Catalyst::Action');
eff60019 125__PACKAGE__->_action_role_prefix([ 'Catalyst::ActionRole::' ]);
234763d4 126
234763d4 127
128sub _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
138sub _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
146sub _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
156sub _ACTION : Private {
157 my ( $self, $c ) = @_;
158 if ( ref $c->action
159 && $c->action->can('execute')
53119b78 160 && defined $c->req->action )
234763d4 161 {
162 $c->action->dispatch( $c );
163 }
164 return !@{ $c->error };
165}
166
167sub _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
234763d4 175sub 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
27ae4114 181#my opinion is that this whole sub really should be a builder method, not
ae29b412 182#something that happens on every call. Anyone else disagree?? -- groditi
183## -- apparently this is all just waiting for app/ctx split
184around action_namespace => sub {
185 my $orig = shift;
234763d4 186 my ( $self, $c ) = @_;
ae29b412 187
df960201 188 my $class = ref($self) || $self;
189 my $appclass = ref($c) || $c;
ae29b412 190 if( ref($self) ){
191 return $self->$orig if $self->has_action_namespace;
192 } else {
df960201 193 return $class->config->{namespace} if exists $class->config->{namespace};
234763d4 194 }
234763d4 195
ae29b412 196 my $case_s;
197 if( $c ){
df960201 198 $case_s = $appclass->config->{case_sensitive};
ae29b412 199 } else {
200 if ($self->isa('Catalyst')) {
df960201 201 $case_s = $class->config->{case_sensitive};
ae29b412 202 } else {
203 if (ref $self) {
df960201 204 $case_s = ref($self->_application)->config->{case_sensitive};
ae29b412 205 } else {
206 confess("Can't figure out case_sensitive setting");
207 }
208 }
234763d4 209 }
ae29b412 210
8f6cebb2 211 my $namespace = Catalyst::Utils::class2prefix($self->catalyst_component_name, $case_s) || '';
ae29b412 212 $self->$orig($namespace) if ref($self);
213 return $namespace;
214};
215
216#Once again, this is probably better written as a builder method
217around 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};
234763d4 229
9ab7d83d 230sub get_action_methods {
231 my $self = shift;
2bf074ab 232 my $meta = find_meta($self) || confess("No metaclass setup for $self");
69048792 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');
cf37d21a 237 my @methods = $meta->get_nearest_methods_with_attributes;
fa649eb7 238
239 # actions specified via config are also action_methods
240 push(
241 @methods,
242 map {
d0e78355 243 $meta->find_method_by_name($_)
e87273a4 244 || confess( sprintf 'Action "%s" is not available from controller %s',
245 $_, ref $self )
bdd6684e 246 } keys %{ $self->_controller_actions }
fa649eb7 247 ) if ( ref $self );
4f4ab5b4 248 return uniq @methods;
9ab7d83d 249}
234763d4 250
fa649eb7 251
234763d4 252sub register_actions {
253 my ( $self, $c ) = @_;
9ab7d83d 254 $self->register_action_methods( $c, $self->get_action_methods );
255}
256
257sub register_action_methods {
258 my ( $self, $c, @methods ) = @_;
8f6cebb2 259 my $class = $self->catalyst_component_name;
ae29b412 260 #this is still not correct for some reason.
234763d4 261 my $namespace = $self->action_namespace($c);
234763d4 262
f3c5b1c9 263 # FIXME - fugly
a202886b 264 if (!blessed($self) && $self eq $c && scalar(@methods)) {
f3c5b1c9 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 }
a202886b 269 }
d2598ac8 270
ba545c13 271 foreach my $method (@methods) {
272 my $name = $method->name;
d0f30dbc 273 # Horrible hack! All method metaclasses should have an attributes
274 # method, core Moose bug - see r13354.
10e970e4 275 my $attributes = $method->can('attributes') ? $method->attributes : [];
ba545c13 276 my $attrs = $self->_parse_attrs( $c, $name, @{ $attributes } );
234763d4 277 if ( $attrs->{Private} && ( keys %$attrs > 1 ) ) {
278 $c->log->debug( 'Bad action definition "'
ba545c13 279 . join( ' ', @{ $attributes } )
280 . qq/" for "$class->$name"/ )
234763d4 281 if $c->debug;
282 next;
283 }
bc677969 284 my $reverse = $namespace ? "${namespace}/${name}" : $name;
234763d4 285 my $action = $self->create_action(
ba545c13 286 name => $name,
287 code => $method->body,
234763d4 288 reverse => $reverse,
289 namespace => $namespace,
290 class => $class,
291 attributes => $attrs,
292 );
293
294 $c->dispatcher->register( $c, $action );
295 }
296}
297
eff60019 298sub _apply_action_class_roles {
299 my ($self, $class, @roles) = @_;
300
c6392ad5 301 load_class($_) for @roles;
eff60019 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
f0a9b791 312sub action_class {
7b41db70 313 my $self = shift;
314 my %args = @_;
234763d4 315
316 my $class = (exists $args{attributes}{ActionClass}
f0a9b791 317 ? $args{attributes}{ActionClass}[0]
318 : $self->_action_class);
319
ae29b412 320 Class::MOP::load_class($class);
f0a9b791 321 return $class;
322}
323
324sub create_action {
325 my $self = shift;
326 my %args = @_;
a7e955ae 327
f0a9b791 328 my $class = $self->action_class(%args);
eff60019 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
bf7c9c87 339 my $action_args = (
340 ref($self)
341 ? $self->action_args
342 : $self->config->{action_args}
343 );
f0a9b791 344
a7e955ae 345 my %extra_args = (
346 %{ $action_args->{'*'} || {} },
347 %{ $action_args->{ $args{name} } || {} },
348 );
349
350 return $class->new({ %extra_args, %args });
234763d4 351}
352
eff60019 353sub gather_action_roles {
354 my ($self, %args) = @_;
355
356 return (
357 (blessed $self ? $self->_action_roles : ()),
358 @{ $args{attributes}->{Does} || [] },
359 );
360}
361
234763d4 362sub _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
bdd6684e 381 my ($actions_config, $all_actions_config);
ae29b412 382 if( ref($self) ) {
bdd6684e 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;
ae29b412 386 } else {
387 my $cfg = $self->config;
bdd6684e 388 $actions_config = $self->merge_config_hashes($cfg->{actions}, $cfg->{action});
389 $all_actions_config = {};
234763d4 390 }
391
ed9d06b6 392 %raw_attributes = (
393 %raw_attributes,
e95b2b49 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 } } : (),
ed9d06b6 397 );
ae29b412 398
ed9d06b6 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.
bdd6684e 405 %raw_attributes = (%{ $all_actions_config }, %raw_attributes)
406 unless $raw_attributes{Private};
ae29b412 407
234763d4 408 my %final_attributes;
409
0b0aee67 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 }
234763d4 414
0b0aee67 415 return \%final_attributes;
416}
234763d4 417
0b0aee67 418sub _parse_attr {
419 my ($self, $c, $name, $key, $values) = @_;
234763d4 420
0b0aee67 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;
234763d4 431 }
0b0aee67 432 }
433 else {
234763d4 434 push( @{ $final_attributes{$key} }, $value );
435 }
436 }
437
438 return \%final_attributes;
439}
440
441sub _parse_Global_attr {
442 my ( $self, $c, $name, $value ) = @_;
0b0aee67 443 # _parse_attr will call _parse_Path_attr for us
444 return Path => "/$name";
234763d4 445}
446
447sub _parse_Absolute_attr { shift->_parse_Global_attr(@_); }
448
449sub _parse_Local_attr {
450 my ( $self, $c, $name, $value ) = @_;
0b0aee67 451 # _parse_attr will call _parse_Path_attr for us
452 return Path => $name;
234763d4 453}
454
455sub _parse_Relative_attr { shift->_parse_Local_attr(@_); }
456
457sub _parse_Path_attr {
458 my ( $self, $c, $name, $value ) = @_;
53119b78 459 $value = '' if !defined $value;
234763d4 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
471sub _parse_Regex_attr {
472 my ( $self, $c, $name, $value ) = @_;
473 return ( 'Regex', $value );
474}
475
476sub _parse_Regexp_attr { shift->_parse_Regex_attr(@_); }
477
478sub _parse_LocalRegex_attr {
479 my ( $self, $c, $name, $value ) = @_;
480 unless ( $value =~ s/^\^// ) { $value = "(?:.*?)$value"; }
19c01ee1 481
482 my $prefix = $self->path_prefix( $c );
483 $prefix .= '/' if length( $prefix );
27ae4114 484
19c01ee1 485 return ( 'Regex', "^${prefix}${value}" );
234763d4 486}
487
488sub _parse_LocalRegexp_attr { shift->_parse_LocalRegex_attr(@_); }
489
f3107403 490sub _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);
fb56008f 496 } elsif (my ($rel, $rest) = $value =~ /^((?:\.{2}\/)+)(.*)$/) {
eb270c30 497 my @parts = split '/', $self->action_namespace($c);
fb56008f 498 my @levels = split '/', $rel;
499
500 $value = '/'.join('/', @parts[0 .. $#parts - @levels], $rest);
f3107403 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
9356b981 517sub _parse_ChainedParent_attr {
518 my ($self, $c, $name, $value) = @_;
519 return $self->_parse_Chained_attr($c, $name, '../'.$name);
520}
521
e5d2cfdb 522sub _parse_PathPrefix_attr {
02825551 523 my ( $self, $c ) = @_;
524 return PathPart => $self->path_prefix($c);
e5d2cfdb 525}
526
234763d4 527sub _parse_ActionClass_attr {
528 my ( $self, $c, $name, $value ) = @_;
5d8129e9 529 my $appname = $self->_application;
530 $value = Catalyst::Utils::resolve_namespace($appname . '::Action', $self->_action_class, $value);
234763d4 531 return ( 'ActionClass', $value );
532}
533
9287719b 534sub _parse_MyAction_attr {
535 my ( $self, $c, $name, $value ) = @_;
536
537 my $appclass = Catalyst::Utils::class2appclass($self);
0b0aee67 538 $value = "+${appclass}::Action::${value}";
234763d4 539
9287719b 540 return ( 'ActionClass', $value );
541}
234763d4 542
eff60019 543sub _parse_Does_attr {
544 my ($self, $app, $name, $value) = @_;
545 return Does => $self->_expand_role_shortname($value);
546}
547
548sub _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 {
c6392ad5 557 my $loaded = load_first_existing_class(
eff60019 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
ae29b412 569__PACKAGE__->meta->make_immutable;
570
234763d4 5711;
572
573__END__
574
575=head1 CONFIGURATION
576
a269e0c2 577Like any other L<Catalyst::Component>, controllers have a config hash,
578accessible through $self->config from the controller actions. Some
579settings are in use by the Catalyst framework:
234763d4 580
581=head2 namespace
582
a269e0c2 583This specifies the internal namespace the controller should be bound
584to. By default the controller is bound to the URI version of the
585controller name. For instance controller 'MyApp::Controller::Foo::Bar'
586will be bound to 'foo/bar'. The default Root controller is an example
587of setting namespace to '' (the null string).
234763d4 588
27ae4114 589=head2 path
234763d4 590
591Sets 'path_prefix', as described below.
592
0a2577a8 593=head2 action
594
595Allows you to set the attributes that the dispatcher creates actions out of.
596This allows you to do 'rails style routes', or override some of the
f4dda4a8 597attribute definitions of actions composed from Roles.
0a2577a8 598You can set arguments globally (for all actions of the controller) and
599specifically (for a single action).
600
601 __PACKAGE__->config(
602 action => {
603 '*' => { Chained => 'base', Args => 0 },
604 base => { Chained => '/', PathPart => '', CaptureArgs => 0 },
605 },
606 );
607
608In the case above every sub in the package would be made into a Chain
609endpoint with a URI the same as the sub name for each sub, chained
610to the sub named C<base>. Ergo dispatch to C</example> would call the
611C<base> method, then the C<example> method.
612
c8136648 613=head2 action_args
614
4d4e5de8 615Allows you to set constructor arguments on your actions. You can set arguments
0a2577a8 616globally and specifically (as above).
617This is particularly useful when using C<ActionRole>s
b939ae6b 618(L<Catalyst::Controller::ActionRole>) and custom C<ActionClass>es.
c8136648 619
b939ae6b 620 __PACKAGE__->config(
c8136648 621 action_args => {
b939ae6b 622 '*' => { globalarg1 => 'hello', globalarg2 => 'goodbye' },
623 'specific_action' => { customarg => 'arg1' },
cea3f28a 624 },
b939ae6b 625 );
cea3f28a 626
b939ae6b 627In the case above the action class associated with C<specific_action> would get
628passed the following arguments, in addition to the normal action constructor
629arguments, when it is instantiated:
630
631 (globalarg1 => 'hello', globalarg2 => 'goodbye', customarg => 'arg1')
c8136648 632
234763d4 633=head1 METHODS
634
c4d02967 635=head2 BUILDARGS ($app, @args)
234763d4 636
c4d02967 637From L<Catalyst::Component::ApplicationAttribute>, stashes the application
638instance as $self->_application.
234763d4 639
640=head2 $self->action_for('name')
641
a269e0c2 642Returns the Catalyst::Action object (if any) for a given method name
643in this component.
234763d4 644
234763d4 645=head2 $self->action_namespace($c)
646
a269e0c2 647Returns the private namespace for actions in this component. Defaults
648to a value from the controller name (for
649e.g. MyApp::Controller::Foo::Bar becomes "foo/bar") or can be
650overridden from the "namespace" config key.
234763d4 651
652
653=head2 $self->path_prefix($c)
654
e5d2cfdb 655Returns the default path prefix for :PathPrefix, :Local, :LocalRegex and
656relative :Path actions in this component. Defaults to the action_namespace or
a269e0c2 657can be overridden from the "path" config key.
234763d4 658
c4d02967 659=head2 $self->register_actions($c)
660
661Finds all applicable actions for this component, creates
662Catalyst::Action objects (using $self->create_action) for them and
663registers them with $c->dispatcher.
664
665=head2 $self->get_action_methods()
666
667Returns a list of L<Moose::Meta::Method> objects, doing the
668L<MooseX::MethodAttributes::Role::Meta::Method> role, which are the set of
669action methods for this package.
670
671=head2 $self->register_action_methods($c, @methods)
672
673Creates action objects for a set of action methods using C< create_action >,
674and registers them with the dispatcher.
675
f0a9b791 676=head2 $self->action_class(%args)
677
678Used when a controller is creating an action to determine the correct base
24d2dfaf 679action class to use.
f0a9b791 680
234763d4 681=head2 $self->create_action(%args)
682
a269e0c2 683Called with a hash of data to be use for construction of a new
684Catalyst::Action (or appropriate sub/alternative class) object.
234763d4 685
eff60019 686=head2 $self->gather_action_roles(\%action_args)
687
688Gathers the list of roles to apply to an action with the given %action_args.
689
a269e0c2 690=head2 $self->_application
234763d4 691
692=head2 $self->_app
693
694Returns the application instance stored by C<new()>
5ee249f2 695
0bf7ab71 696=head1 AUTHORS
5ee249f2 697
0bf7ab71 698Catalyst Contributors, see Catalyst.pm
5ee249f2 699
700=head1 COPYRIGHT
701
536bee89 702This library is free software. You can redistribute it and/or modify
a269e0c2 703it under the same terms as Perl itself.
5ee249f2 704
705=cut