Merge master into gsoc_breadboard
[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);
ae29b412 26
aea897b2 27has action_namespace => (
28 is => 'rw',
29 isa => 'Str',
30 init_arg => 'namespace',
31 predicate => 'has_action_namespace',
32);
ae29b412 33
aea897b2 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');
ae29b412 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;
b527cc7d 190
191 # FIXME - catalyst_component_name is no longer a class accessor, because
192 # 'MyApp as a controller' behavior is removed. But is this call to
193 # catalyst_component_name necessary, or is it always the same as $class?
194 my $component_name = ref($self) ? $self->catalyst_component_name : $self;
195
ae29b412 196 if( ref($self) ){
197 return $self->$orig if $self->has_action_namespace;
198 } else {
df960201 199 return $class->config->{namespace} if exists $class->config->{namespace};
234763d4 200 }
234763d4 201
ae29b412 202 my $case_s;
203 if( $c ){
df960201 204 $case_s = $appclass->config->{case_sensitive};
ae29b412 205 } else {
206 if ($self->isa('Catalyst')) {
df960201 207 $case_s = $class->config->{case_sensitive};
ae29b412 208 } else {
209 if (ref $self) {
df960201 210 $case_s = ref($self->_application)->config->{case_sensitive};
ae29b412 211 } else {
212 confess("Can't figure out case_sensitive setting");
213 }
214 }
234763d4 215 }
ae29b412 216
b527cc7d 217 my $namespace = Catalyst::Utils::class2prefix($component_name, $case_s) || '';
ae29b412 218 $self->$orig($namespace) if ref($self);
219 return $namespace;
220};
221
222#Once again, this is probably better written as a builder method
223around path_prefix => sub {
224 my $orig = shift;
225 my $self = shift;
226 if( ref($self) ){
227 return $self->$orig if $self->has_path_prefix;
228 } else {
229 return $self->config->{path} if exists $self->config->{path};
230 }
231 my $namespace = $self->action_namespace(@_);
232 $self->$orig($namespace) if ref($self);
233 return $namespace;
234};
234763d4 235
9ab7d83d 236sub get_action_methods {
237 my $self = shift;
2bf074ab 238 my $meta = find_meta($self) || confess("No metaclass setup for $self");
69048792 239 confess(
240 sprintf "Metaclass %s for %s cannot support register_actions.",
241 ref $meta, $meta->name,
242 ) unless $meta->can('get_nearest_methods_with_attributes');
cf37d21a 243 my @methods = $meta->get_nearest_methods_with_attributes;
fa649eb7 244
245 # actions specified via config are also action_methods
246 push(
247 @methods,
248 map {
d0e78355 249 $meta->find_method_by_name($_)
e87273a4 250 || confess( sprintf 'Action "%s" is not available from controller %s',
251 $_, ref $self )
bdd6684e 252 } keys %{ $self->_controller_actions }
fa649eb7 253 ) if ( ref $self );
4f4ab5b4 254 return uniq @methods;
9ab7d83d 255}
234763d4 256
fa649eb7 257
234763d4 258sub register_actions {
259 my ( $self, $c ) = @_;
9ab7d83d 260 $self->register_action_methods( $c, $self->get_action_methods );
261}
262
263sub register_action_methods {
264 my ( $self, $c, @methods ) = @_;
8f6cebb2 265 my $class = $self->catalyst_component_name;
ae29b412 266 #this is still not correct for some reason.
234763d4 267 my $namespace = $self->action_namespace($c);
234763d4 268
f3c5b1c9 269 # FIXME - fugly
a202886b 270 if (!blessed($self) && $self eq $c && scalar(@methods)) {
f3c5b1c9 271 my @really_bad_methods = grep { ! /^_(DISPATCH|BEGIN|AUTO|ACTION|END)$/ } map { $_->name } @methods;
272 if (scalar(@really_bad_methods)) {
273 $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.");
274 }
a202886b 275 }
d2598ac8 276
ba545c13 277 foreach my $method (@methods) {
278 my $name = $method->name;
d0f30dbc 279 # Horrible hack! All method metaclasses should have an attributes
280 # method, core Moose bug - see r13354.
10e970e4 281 my $attributes = $method->can('attributes') ? $method->attributes : [];
ba545c13 282 my $attrs = $self->_parse_attrs( $c, $name, @{ $attributes } );
234763d4 283 if ( $attrs->{Private} && ( keys %$attrs > 1 ) ) {
284 $c->log->debug( 'Bad action definition "'
ba545c13 285 . join( ' ', @{ $attributes } )
286 . qq/" for "$class->$name"/ )
234763d4 287 if $c->debug;
288 next;
289 }
bc677969 290 my $reverse = $namespace ? "${namespace}/${name}" : $name;
234763d4 291 my $action = $self->create_action(
ba545c13 292 name => $name,
293 code => $method->body,
234763d4 294 reverse => $reverse,
295 namespace => $namespace,
296 class => $class,
297 attributes => $attrs,
298 );
299
300 $c->dispatcher->register( $c, $action );
301 }
302}
303
eff60019 304sub _apply_action_class_roles {
305 my ($self, $class, @roles) = @_;
306
c6392ad5 307 load_class($_) for @roles;
eff60019 308 my $meta = Moose::Meta::Class->initialize($class)->create_anon_class(
309 superclasses => [$class],
310 roles => \@roles,
311 cache => 1,
312 );
313 $meta->add_method(meta => sub { $meta });
314
315 return $meta->name;
316}
317
f0a9b791 318sub action_class {
7b41db70 319 my $self = shift;
320 my %args = @_;
234763d4 321
322 my $class = (exists $args{attributes}{ActionClass}
f0a9b791 323 ? $args{attributes}{ActionClass}[0]
324 : $self->_action_class);
325
ae29b412 326 Class::MOP::load_class($class);
f0a9b791 327 return $class;
328}
329
330sub create_action {
331 my $self = shift;
332 my %args = @_;
a7e955ae 333
f0a9b791 334 my $class = $self->action_class(%args);
eff60019 335
336 load_class($class);
337 Moose->init_meta(for_class => $class)
338 unless Class::MOP::does_metaclass_exist($class);
339
340 unless ($args{name} =~ /^_(DISPATCH|BEGIN|AUTO|ACTION|END)$/) {
341 my @roles = $self->gather_action_roles(%args);
342 $class = $self->_apply_action_class_roles($class, @roles) if @roles;
343 }
344
bf7c9c87 345 my $action_args = (
346 ref($self)
347 ? $self->action_args
348 : $self->config->{action_args}
349 );
f0a9b791 350
a7e955ae 351 my %extra_args = (
352 %{ $action_args->{'*'} || {} },
353 %{ $action_args->{ $args{name} } || {} },
354 );
355
356 return $class->new({ %extra_args, %args });
234763d4 357}
358
eff60019 359sub gather_action_roles {
360 my ($self, %args) = @_;
361
362 return (
363 (blessed $self ? $self->_action_roles : ()),
364 @{ $args{attributes}->{Does} || [] },
365 );
366}
367
234763d4 368sub _parse_attrs {
369 my ( $self, $c, $name, @attrs ) = @_;
370
371 my %raw_attributes;
372
373 foreach my $attr (@attrs) {
374
375 # Parse out :Foo(bar) into Foo => bar etc (and arrayify)
376
377 if ( my ( $key, $value ) = ( $attr =~ /^(.*?)(?:\(\s*(.+?)\s*\))?$/ ) )
378 {
379
380 if ( defined $value ) {
381 ( $value =~ s/^'(.*)'$/$1/ ) || ( $value =~ s/^"(.*)"/$1/ );
382 }
383 push( @{ $raw_attributes{$key} }, $value );
384 }
385 }
386
bdd6684e 387 my ($actions_config, $all_actions_config);
ae29b412 388 if( ref($self) ) {
bdd6684e 389 $actions_config = $self->_controller_actions;
390 # No, you're not getting actions => { '*' => ... } with actions in MyApp.
391 $all_actions_config = $self->_all_actions_attributes;
ae29b412 392 } else {
393 my $cfg = $self->config;
bdd6684e 394 $actions_config = $self->merge_config_hashes($cfg->{actions}, $cfg->{action});
395 $all_actions_config = {};
234763d4 396 }
397
ed9d06b6 398 %raw_attributes = (
399 %raw_attributes,
e95b2b49 400 # Note we deep copy array refs here to stop crapping on config
401 # when attributes are parsed. RT#65463
402 exists $actions_config->{$name} ? map { ref($_) eq 'ARRAY' ? [ @$_ ] : $_ } %{ $actions_config->{$name } } : (),
ed9d06b6 403 );
ae29b412 404
ed9d06b6 405 # Private actions with additional attributes will raise a warning and then
406 # be ignored. Adding '*' arguments to the default _DISPATCH / etc. methods,
407 # which are Private, will prevent those from being registered. They should
408 # probably be turned into :Actions instead, or we might want to otherwise
409 # disambiguate between those built-in internal actions and user-level
410 # Private ones.
bdd6684e 411 %raw_attributes = (%{ $all_actions_config }, %raw_attributes)
412 unless $raw_attributes{Private};
ae29b412 413
234763d4 414 my %final_attributes;
415
416 foreach my $key (keys %raw_attributes) {
417
418 my $raw = $raw_attributes{$key};
419
420 foreach my $value (ref($raw) eq 'ARRAY' ? @$raw : $raw) {
421
422 my $meth = "_parse_${key}_attr";
ae29b412 423 if ( my $code = $self->can($meth) ) {
424 ( $key, $value ) = $self->$code( $c, $name, $value );
234763d4 425 }
426 push( @{ $final_attributes{$key} }, $value );
427 }
428 }
429
430 return \%final_attributes;
431}
432
433sub _parse_Global_attr {
434 my ( $self, $c, $name, $value ) = @_;
435 return $self->_parse_Path_attr( $c, $name, "/$name" );
436}
437
438sub _parse_Absolute_attr { shift->_parse_Global_attr(@_); }
439
440sub _parse_Local_attr {
441 my ( $self, $c, $name, $value ) = @_;
442 return $self->_parse_Path_attr( $c, $name, $name );
443}
444
445sub _parse_Relative_attr { shift->_parse_Local_attr(@_); }
446
447sub _parse_Path_attr {
448 my ( $self, $c, $name, $value ) = @_;
53119b78 449 $value = '' if !defined $value;
234763d4 450 if ( $value =~ m!^/! ) {
451 return ( 'Path', $value );
452 }
453 elsif ( length $value ) {
454 return ( 'Path', join( '/', $self->path_prefix($c), $value ) );
455 }
456 else {
457 return ( 'Path', $self->path_prefix($c) );
458 }
459}
460
461sub _parse_Regex_attr {
462 my ( $self, $c, $name, $value ) = @_;
463 return ( 'Regex', $value );
464}
465
466sub _parse_Regexp_attr { shift->_parse_Regex_attr(@_); }
467
468sub _parse_LocalRegex_attr {
469 my ( $self, $c, $name, $value ) = @_;
470 unless ( $value =~ s/^\^// ) { $value = "(?:.*?)$value"; }
19c01ee1 471
472 my $prefix = $self->path_prefix( $c );
473 $prefix .= '/' if length( $prefix );
27ae4114 474
19c01ee1 475 return ( 'Regex', "^${prefix}${value}" );
234763d4 476}
477
478sub _parse_LocalRegexp_attr { shift->_parse_LocalRegex_attr(@_); }
479
f3107403 480sub _parse_Chained_attr {
481 my ($self, $c, $name, $value) = @_;
482
483 if (defined($value) && length($value)) {
484 if ($value eq '.') {
485 $value = '/'.$self->action_namespace($c);
fb56008f 486 } elsif (my ($rel, $rest) = $value =~ /^((?:\.{2}\/)+)(.*)$/) {
eb270c30 487 my @parts = split '/', $self->action_namespace($c);
fb56008f 488 my @levels = split '/', $rel;
489
490 $value = '/'.join('/', @parts[0 .. $#parts - @levels], $rest);
f3107403 491 } elsif ($value !~ m/^\//) {
492 my $action_ns = $self->action_namespace($c);
493
494 if ($action_ns) {
495 $value = '/'.join('/', $action_ns, $value);
496 } else {
497 $value = '/'.$value; # special case namespace '' (root)
498 }
499 }
500 } else {
501 $value = '/'
502 }
503
504 return Chained => $value;
505}
506
9356b981 507sub _parse_ChainedParent_attr {
508 my ($self, $c, $name, $value) = @_;
509 return $self->_parse_Chained_attr($c, $name, '../'.$name);
510}
511
e5d2cfdb 512sub _parse_PathPrefix_attr {
02825551 513 my ( $self, $c ) = @_;
514 return PathPart => $self->path_prefix($c);
e5d2cfdb 515}
516
234763d4 517sub _parse_ActionClass_attr {
518 my ( $self, $c, $name, $value ) = @_;
5d8129e9 519 my $appname = $self->_application;
520 $value = Catalyst::Utils::resolve_namespace($appname . '::Action', $self->_action_class, $value);
234763d4 521 return ( 'ActionClass', $value );
522}
523
9287719b 524sub _parse_MyAction_attr {
525 my ( $self, $c, $name, $value ) = @_;
526
527 my $appclass = Catalyst::Utils::class2appclass($self);
528 $value = "${appclass}::Action::${value}";
234763d4 529
9287719b 530 return ( 'ActionClass', $value );
531}
234763d4 532
eff60019 533sub _parse_Does_attr {
534 my ($self, $app, $name, $value) = @_;
535 return Does => $self->_expand_role_shortname($value);
536}
537
538sub _expand_role_shortname {
539 my ($self, @shortnames) = @_;
540 my $app = $self->_application;
541
542 my $prefix = $self->can('_action_role_prefix') ? $self->_action_role_prefix : ['Catalyst::ActionRole::'];
543 my @prefixes = (qq{${app}::ActionRole::}, @$prefix);
544
545 return String::RewritePrefix->rewrite(
546 { '' => sub {
c6392ad5 547 my $loaded = load_first_existing_class(
eff60019 548 map { "$_$_[0]" } @prefixes
549 );
550 return first { $loaded =~ /^$_/ }
551 sort { length $b <=> length $a } @prefixes;
552 },
553 '~' => $prefixes[0],
554 '+' => '' },
555 @shortnames,
556 );
557}
558
ae29b412 559__PACKAGE__->meta->make_immutable;
560
234763d4 5611;
562
563__END__
564
565=head1 CONFIGURATION
566
a269e0c2 567Like any other L<Catalyst::Component>, controllers have a config hash,
568accessible through $self->config from the controller actions. Some
569settings are in use by the Catalyst framework:
234763d4 570
571=head2 namespace
572
a269e0c2 573This specifies the internal namespace the controller should be bound
574to. By default the controller is bound to the URI version of the
575controller name. For instance controller 'MyApp::Controller::Foo::Bar'
576will be bound to 'foo/bar'. The default Root controller is an example
577of setting namespace to '' (the null string).
234763d4 578
27ae4114 579=head2 path
234763d4 580
581Sets 'path_prefix', as described below.
582
0a2577a8 583=head2 action
584
585Allows you to set the attributes that the dispatcher creates actions out of.
586This allows you to do 'rails style routes', or override some of the
f4dda4a8 587attribute definitions of actions composed from Roles.
0a2577a8 588You can set arguments globally (for all actions of the controller) and
589specifically (for a single action).
590
591 __PACKAGE__->config(
592 action => {
593 '*' => { Chained => 'base', Args => 0 },
594 base => { Chained => '/', PathPart => '', CaptureArgs => 0 },
595 },
596 );
597
598In the case above every sub in the package would be made into a Chain
599endpoint with a URI the same as the sub name for each sub, chained
600to the sub named C<base>. Ergo dispatch to C</example> would call the
601C<base> method, then the C<example> method.
602
c8136648 603=head2 action_args
604
4d4e5de8 605Allows you to set constructor arguments on your actions. You can set arguments
0a2577a8 606globally and specifically (as above).
607This is particularly useful when using C<ActionRole>s
b939ae6b 608(L<Catalyst::Controller::ActionRole>) and custom C<ActionClass>es.
c8136648 609
b939ae6b 610 __PACKAGE__->config(
c8136648 611 action_args => {
b939ae6b 612 '*' => { globalarg1 => 'hello', globalarg2 => 'goodbye' },
613 'specific_action' => { customarg => 'arg1' },
cea3f28a 614 },
b939ae6b 615 );
cea3f28a 616
b939ae6b 617In the case above the action class associated with C<specific_action> would get
618passed the following arguments, in addition to the normal action constructor
619arguments, when it is instantiated:
620
621 (globalarg1 => 'hello', globalarg2 => 'goodbye', customarg => 'arg1')
c8136648 622
234763d4 623=head1 METHODS
624
c4d02967 625=head2 BUILDARGS ($app, @args)
234763d4 626
c4d02967 627From L<Catalyst::Component::ApplicationAttribute>, stashes the application
628instance as $self->_application.
234763d4 629
630=head2 $self->action_for('name')
631
a269e0c2 632Returns the Catalyst::Action object (if any) for a given method name
633in this component.
234763d4 634
234763d4 635=head2 $self->action_namespace($c)
636
a269e0c2 637Returns the private namespace for actions in this component. Defaults
638to a value from the controller name (for
639e.g. MyApp::Controller::Foo::Bar becomes "foo/bar") or can be
640overridden from the "namespace" config key.
234763d4 641
642
643=head2 $self->path_prefix($c)
644
e5d2cfdb 645Returns the default path prefix for :PathPrefix, :Local, :LocalRegex and
646relative :Path actions in this component. Defaults to the action_namespace or
a269e0c2 647can be overridden from the "path" config key.
234763d4 648
c4d02967 649=head2 $self->register_actions($c)
650
651Finds all applicable actions for this component, creates
652Catalyst::Action objects (using $self->create_action) for them and
653registers them with $c->dispatcher.
654
655=head2 $self->get_action_methods()
656
657Returns a list of L<Moose::Meta::Method> objects, doing the
658L<MooseX::MethodAttributes::Role::Meta::Method> role, which are the set of
659action methods for this package.
660
661=head2 $self->register_action_methods($c, @methods)
662
663Creates action objects for a set of action methods using C< create_action >,
664and registers them with the dispatcher.
665
f0a9b791 666=head2 $self->action_class(%args)
667
668Used when a controller is creating an action to determine the correct base
24d2dfaf 669action class to use.
f0a9b791 670
234763d4 671=head2 $self->create_action(%args)
672
a269e0c2 673Called with a hash of data to be use for construction of a new
674Catalyst::Action (or appropriate sub/alternative class) object.
234763d4 675
eff60019 676=head2 $self->gather_action_roles(\%action_args)
677
678Gathers the list of roles to apply to an action with the given %action_args.
679
a269e0c2 680=head2 $self->_application
234763d4 681
682=head2 $self->_app
683
684Returns the application instance stored by C<new()>
5ee249f2 685
0bf7ab71 686=head1 AUTHORS
5ee249f2 687
0bf7ab71 688Catalyst Contributors, see Catalyst.pm
5ee249f2 689
690=head1 COPYRIGHT
691
536bee89 692This library is free software. You can redistribute it and/or modify
a269e0c2 693it under the same terms as Perl itself.
5ee249f2 694
695=cut