File Coverage

blib/lib/Catalyst/Dispatcher.pm
Criterion Covered Total %
statement 318 331 96.0
branch 102 126 80.9
condition 23 31 74.1
subroutine 46 46 100.0
pod 15 15 100.0
total 504 549 91.8


line stmt bran cond sub pod time code
1              
2             use Moose;
3 153     153   92390 use Class::MOP;
  153         379  
  153         1042  
4 153     153   887956 with 'MooseX::Emulate::Class::Accessor::Fast';
  153         357  
  153         5284  
5              
6             use Catalyst::Exception;
7 153     153   1282 use Catalyst::Utils;
  153         351  
  153         3623  
8 153     153   845 use Catalyst::Action;
  153         326  
  153         3706  
9 153     153   65535 use Catalyst::ActionContainer;
  153         544  
  153         6419  
10 153     153   66940 use Catalyst::DispatchType::Default;
  153         646  
  153         4656  
11 153     153   58199 use Catalyst::DispatchType::Index;
  153         549  
  153         6211  
12 153     153   58067 use Catalyst::Utils;
  153         601  
  153         4669  
13 153     153   1187 use Text::SimpleTable;
  153         371  
  153         3432  
14 153     153   1254 use Tree::Simple;
  153         2456  
  153         3421  
15 153     153   1336 use Class::Load qw(load_class try_load_class);
  153         3177  
  153         1633  
16 153     153   3870 use Encode 2.21 'decode_utf8';
  153         349  
  153         11851  
17 153     153   1432  
  153         16126  
  153         7647  
18             use namespace::clean -except => 'meta';
19 153     153   1038  
  153         451  
  153         954  
20             # Refactoring note:
21             # do these belong as package vars or should we build these via a builder method?
22             # See Catalyst-Plugin-Server for them being added to, which should be much less ugly.
23              
24             # Preload these action types
25             our @PRELOAD = qw/Index Path/;
26              
27             # Postload these action types
28             our @POSTLOAD = qw/Default/;
29              
30             # Note - see back-compat methods at end of file.
31             has _tree => (is => 'rw', builder => '_build__tree');
32             has dispatch_types => (is => 'rw', default => sub { [] }, required => 1, lazy => 1);
33             has _registered_dispatch_types => (is => 'rw', default => sub { {} }, required => 1, lazy => 1);
34             has _method_action_class => (is => 'rw', default => 'Catalyst::Action');
35             has _action_hash => (is => 'rw', required => 1, lazy => 1, default => sub { {} });
36             has _container_hash => (is => 'rw', required => 1, lazy => 1, default => sub { {} });
37              
38             my %dispatch_types = ( pre => \@PRELOAD, post => \@POSTLOAD );
39             foreach my $type (keys %dispatch_types) {
40             has $type . "load_dispatch_types" => (
41             is => 'rw', required => 1, lazy => 1, default => sub { $dispatch_types{$type} },
42             traits => ['MooseX::Emulate::Class::Accessor::Fast::Meta::Role::Attribute'], # List assignment is CAF style
43             );
44             }
45              
46             =head1 NAME
47              
48             Catalyst::Dispatcher - The Catalyst Dispatcher
49              
50             =head1 SYNOPSIS
51              
52             See L<Catalyst>.
53              
54             =head1 DESCRIPTION
55              
56             This is the class that maps public urls to actions in your Catalyst
57             application based on the attributes you set.
58              
59             =head1 METHODS
60              
61             =head2 new
62              
63             Construct a new dispatcher.
64              
65             =cut
66              
67             my ($self) = @_;
68              
69 162     162   432 my $container =
70             Catalyst::ActionContainer->new( { part => '/', actions => {} } );
71 162         5545  
72             return Tree::Simple->new($container, Tree::Simple->ROOT);
73             }
74 162         2730  
75             =head2 $self->preload_dispatch_types
76              
77             An arrayref of pre-loaded dispatchtype classes
78              
79             Entries are considered to be available as C<Catalyst::DispatchType::CLASS>
80             To use a custom class outside the regular C<Catalyst> namespace, prefix
81             it with a C<+>, like so:
82              
83             +My::Dispatch::Type
84              
85             =head2 $self->postload_dispatch_types
86              
87             An arrayref of post-loaded dispatchtype classes
88              
89             Entries are considered to be available as C<Catalyst::DispatchType::CLASS>
90             To use a custom class outside the regular C<Catalyst> namespace, prefix
91             it with a C<+>, like so:
92              
93             +My::Dispatch::Type
94              
95             =head2 $self->dispatch($c)
96              
97             Delegate the dispatch to the action that matched the url, or return a
98             message about unknown resource
99              
100             =cut
101              
102             my ( $self, $c ) = @_;
103             if ( my $action = $c->action ) {
104             $c->forward( join( '/', '', $action->namespace, '_DISPATCH' ) );
105 962     962 1 2339 }
106 962 100       22207 else {
107 953         22098 my $path = $c->req->path;
108             $path =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
109             $path = decode_utf8($path);
110 9         48  
111 9         31 my $error = $path
  0         0  
112 9         161 ? qq/Unknown resource "$path"/
113             : "No default action defined";
114 9 50       100 $c->log->error($error) if $c->debug;
115             $c->error($error);
116             }
117 9 50       36 }
118 9         39  
119             # $self->_command2action( $c, $command [, \@arguments ] )
120             # $self->_command2action( $c, $command [, \@captures, \@arguments ] )
121             # Search for an action, from the command and returns C<($action, $args, $captures)> on
122             # success. Returns C<(0)> on error.
123              
124             my ( $self, $c, $command, @extra_params ) = @_;
125              
126             unless ($command) {
127             $c->log->debug('Nothing to go to') if $c->debug;
128 6946     6946   12016 return 0;
129             }
130 6946 50       12385  
131 0 0       0 my (@args, @captures);
132 0         0  
133             if ( ref( $extra_params[-2] ) eq 'ARRAY' ) {
134             @captures = @{ splice @extra_params, -2, 1 };
135 6946         9090 }
136              
137 6946 100       12971 if ( ref( $extra_params[-1] ) eq 'ARRAY' ) {
138 4         9 @args = @{ pop @extra_params }
  4         15  
139             } else {
140             # this is a copy, it may take some abuse from
141 6946 100       11694 # ->_invoke_as_path if the path had trailing parts
142 24         46 @args = @{ $c->request->arguments };
  24         58  
143             }
144              
145             my $action;
146 6922         8619  
  6922         152516  
147             # go to a string path ("/foo/bar/gorch")
148             # or action object
149 6946         10234 if (blessed($command) && $command->isa('Catalyst::Action')) {
150             $action = $command;
151             }
152             else {
153 6946 100 100     19404 $action = $self->_invoke_as_path( $c, "$command", \@args );
154 2         5 }
155              
156             # go to a component ( "View::Foo" or $c->component("...")
157 6944         19917 # - a path or an object)
158             unless ($action) {
159             my $method = @extra_params ? $extra_params[0] : "process";
160             $action = $self->_invoke_as_component( $c, $command, $method );
161             }
162 6945 100       16147  
163 131 100       406 return $action, \@args, \@captures;
164 131         418 }
165              
166             =head2 $self->visit( $c, $command [, \@arguments ] )
167 6945         20865  
168             Documented in L<Catalyst>
169              
170             =cut
171              
172             my $self = shift;
173             $self->_do_visit('visit', @_);
174             }
175              
176             my $self = shift;
177 26     26 1 36 my $opname = shift;
178 26         90 my ( $c, $command ) = @_;
179             my ( $action, $args, $captures ) = $self->_command2action(@_);
180             my $error = qq/Couldn't $opname("$command"): /;
181              
182 50     50   91 if (!$action) {
183 50         65 $error .= qq/Couldn't $opname to command "$command": /
184 50         136 .qq/Invalid action or component./;
185 50         105 }
186 50         168 elsif (!defined $action->namespace) {
187             $error .= qq/Action has no namespace: cannot $opname() to a plain /
188 50 50       120 .qq/method or component, must be an :Action of some sort./
    100          
    100          
189 0         0 }
190             elsif (!$action->class->can('_DISPATCH')) {
191             $error .= qq/Action cannot _DISPATCH. /
192             .qq/Did you try to $opname() a non-controller action?/;
193 2         21 }
194             else {
195             $error = q();
196             }
197 4         24  
198             if($error) {
199             $c->error($error);
200             $c->log->debug($error) if $c->debug;
201 44         87 return 0;
202             }
203              
204 50 100       117 $action = $self->expand_action($action);
205 6         25  
206 6 50       22 local $c->request->{arguments} = $args;
207 6         157 local $c->request->{captures} = $captures;
208             local $c->{namespace} = $action->{'namespace'};
209             local $c->{action} = $action;
210 44         113  
211             $self->dispatch($c);
212 44         874 }
213 44         853  
214 44         138 =head2 $self->go( $c, $command [, \@arguments ] )
215 44         90  
216             Documented in L<Catalyst>
217 44         173  
218             =cut
219              
220             my $self = shift;
221             $self->_do_visit('go', @_);
222             Catalyst::Exception::Go->throw;
223             }
224              
225             =head2 $self->forward( $c, $command [, \@arguments ] )
226              
227 24     24 1 74 Documented in L<Catalyst>
228 24         107  
229 13         165 =cut
230              
231             my $self = shift;
232             no warnings 'recursion';
233             return $self->_do_forward(forward => @_);
234             }
235              
236             my $self = shift;
237             my $opname = shift;
238             my ( $c, $command ) = @_;
239 6882     6882 1 9758 my ( $action, $args, $captures ) = $self->_command2action(@_);
240 153     153   195606  
  153         567  
  153         25676  
241 6882         15973 if (!$action) {
242             my $error .= qq/Couldn't $opname to command "$command": /
243             .qq/Invalid action or component./;
244             $c->error($error);
245 6896     6896   8789 $c->log->debug($error) if $c->debug;
246 6896         8834 return 0;
247 6896         11506 }
248 6896         12894  
249              
250 6895 100       14335 local $c->request->{arguments} = $args;
251 1         5 no warnings 'recursion';
252             $action->dispatch( $c );
253 1         14  
254 1 50       3 #If there is an error, all bets off regarding state. Documentation
255 1         7 #Specifies that when you forward, if there's an error you must expect
256             #state to be 0.
257             if( @{ $c->error }) {
258             $c->state(0);
259 6894         141967 }
260 153     153   1214 return $c->state;
  153         510  
  153         446490  
261 6894         22408 }
262              
263             =head2 $self->detach( $c, $command [, \@arguments ] )
264              
265             Documented in L<Catalyst>
266 6850 100       9702  
  6850         16003  
267 1074         20926 =cut
268              
269 6850         134138 my ( $self, $c, $command, @args ) = @_;
270             $self->_do_forward(detach => $c, $command, @args ) if $command;
271             $c->state(0); # Needed in order to skip any auto functions
272             Catalyst::Exception::Detach->throw;
273             }
274              
275             my ( $self, $c, $path ) = @_;
276              
277             unless ( $path =~ m#^/# ) {
278             my $namespace = $c->stack->[-1]->namespace;
279 16     16 1 57 $path = "$namespace/$path";
280 16 100       81 }
281 14         326  
282 14         114 $path =~ s#^/##;
283             return $path;
284             }
285              
286 6944     6944   11113 my ( $self, $c, $rel_path, $args ) = @_;
287              
288 6944 100       14714 my $path = $self->_action_rel2abs( $c, $rel_path );
289 5960         114827  
290 5959         13579 my ( $tail, @extra_args );
291             while ( ( $path, $tail ) = ( $path =~ m#^(?:(.*)/)?(\w+)?$# ) )
292             { # allow $path to be empty
293 6943         15272 if ( my $action = $c->get_action( $tail, $path ) ) {
294 6943         12732 push @$args, @extra_args;
295             return $action;
296             }
297             else {
298 6944     6944   12245 return
299             unless $path
300 6944         13150 ; # if a match on the global namespace failed then the whole lookup failed
301             }
302 6943         9898  
303 6943         36741 unshift @extra_args, $tail;
304             }
305 6833 100       19204 }
306 6812         10438  
307 6812         16532 my ( $self, $c, $component ) = @_;
308              
309             # fugly, why doesn't ->component('MyApp') work?
310             return $c if ($component eq blessed($c));
311 21 100       81  
312             return blessed($component)
313             ? $component
314             : $c->component($component);
315 17         99 }
316              
317             my ( $self, $c, $component_or_class, $method ) = @_;
318              
319             my $component = $self->_find_component($c, $component_or_class);
320 131     131   268 my $component_class = blessed $component || return 0;
321              
322             if (my $code = $component_class->can('action_for')) {
323 131 100       592 my $possible_action = $component->$code($method);
324             return $possible_action if $possible_action;
325 128 100       606 }
326              
327             if ( my $code = $component_class->can($method) ) {
328             return $self->_method_action_class->new(
329             {
330             name => $method,
331 131     131   318 code => $code,
332             reverse => "$component_class->$method",
333 131         328 class => $component_class,
334 131   100     583 namespace => Catalyst::Utils::class2prefix(
335             $component_class, ref($c)->config->{case_sensitive}
336 130 100       1321 ),
337 24         84 }
338 24 100       119 );
339             }
340             else {
341 108 50       555 my $error =
342             qq/Couldn't forward to "$component_class". Does not implement "$method"/;
343             $c->error($error);
344             $c->log->debug($error)
345             if $c->debug;
346             return 0;
347             }
348             }
349              
350 108         3241 =head2 $self->prepare_action($c)
351              
352             Find an dispatch type that matches $c->req->path, and set args from it.
353              
354             =cut
355 0         0  
356             my ( $self, $c ) = @_;
357 0         0 my $req = $c->req;
358 0 0       0 my $path = $req->path;
359             my @path = split /\//, $req->path;
360 0         0 $req->args( \my @args );
361              
362             unshift( @path, '' ); # Root action
363              
364             DESCEND: while (@path) {
365             $path = join '/', @path;
366             $path =~ s#^/+##;
367              
368             # Check out dispatch types to see if any will handle the path at
369             # this level
370              
371 920     920 1 2199 foreach my $type ( @{ $self->dispatch_types } ) {
372 920         2617 last DESCEND if $type->match( $c, $path );
373 920         4175 }
374 920         2493  
375 920         3856 # If not, move the last part path to args
376             my $arg = pop(@path);
377 920         2292 $arg =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
378             unshift @args, $arg;
379 920         2209 }
380 1397         3804  
381 1397         4538 s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg for grep { defined } @{$req->captures||[]};
382              
383             if($c->debug && defined $req->match && length $req->match) {
384             my $match = $req->match;
385             $match =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
386 1397         2224 $match = decode_utf8($match);
  1397         35222  
387 4999 100       17315 $c->log->debug( 'Path is "' . $match . '"' )
388             }
389              
390             $c->log->debug( 'Arguments are "' . join( '/', map { decode_utf8 $_ } @args ) . '"' )
391 487         1618 if ( $c->debug && @args );
392 487         1051 }
  71         241  
393 487         1418  
394             =head2 $self->get_action( $action_name, $namespace )
395              
396 920 50       1745 returns a named action from a given namespace. C<$action_name>
  194         781  
  920         20919  
  39         143  
397             may be a relative path on that C<$namespace> such as
398 920 50 66     2855  
      66        
399 16         328 $self->get_action('../bar', 'foo/baz');
400 16         41  
  0         0  
401 16         150 In which case we look for the action at 'foo/bar'.
402 16         132  
403             =cut
404              
405 920 100 100     2142 my ( $self, $name, $namespace ) = @_;
  7         47  
406             return unless $name;
407              
408             $namespace = join( "/", grep { length } split '/', ( defined $namespace ? $namespace : "" ) );
409              
410             return $self->get_action_by_path("${namespace}/${name}");
411             }
412              
413             =head2 $self->get_action_by_path( $path );
414              
415             Returns the named action by its full private path.
416              
417             This method performs some normalization on C<$path> so that if
418             it includes '..' it will do the right thing (for example if
419             C<$path> is '/foo/../bar' that is normalized to '/bar'.
420              
421 7818     7818 1 15182 =cut
422 7818 50       13611  
423             my ( $self, $path ) = @_;
424 7818 100       23239 $path =~s/[^\/]+\/\.\.\/// while $path=~m/[^\/]+\/\.\.\//;
  8571         16985  
425             $path =~ s/^\///;
426 7818         21904 $path = "/$path" unless $path =~ /\//;
427             $self->_action_hash->{$path};
428             }
429              
430             =head2 $self->get_actions( $c, $action, $namespace )
431              
432             =cut
433              
434             my ( $self, $c, $action, $namespace ) = @_;
435             return [] unless $action;
436              
437             $namespace = join( "/", grep { length } split '/', $namespace || "" );
438              
439             my @match = $self->get_containers($namespace);
440 7853     7853 1 14263  
441 7853         20773 return map { $_->get_action($action) } @match;
442 7853         16126 }
443 7853 100       18666  
444 7853         202298 =head2 $self->get_containers( $namespace )
445              
446             Return all the action containers for a given namespace, inclusive
447              
448             =cut
449              
450             my ( $self, $namespace ) = @_;
451             $namespace ||= '';
452 2901     2901 1 6593 $namespace = '' if $namespace eq '/';
453 2901 50       5595  
454             my @containers;
455 2901   100     9812  
  3657         7603  
456             if ( length $namespace ) {
457 2901         6530 do {
458             push @containers, $self->_container_hash->{$namespace};
459 2901         4900 } while ( $namespace =~ s#/[^/]+$## );
  6163         14643  
460             }
461              
462             return reverse grep { defined } @containers, $self->_container_hash->{''};
463             }
464              
465             =head2 $self->uri_for_action($action, \@captures)
466              
467             Takes a Catalyst::Action object and action parameters and returns a URI
468             part such that if $c->req->path were this URI part, this action would be
469 2901     2901 1 5044 dispatched to with $c->req->captures set to the supplied arrayref.
470 2901   100     6464  
471 2901 50       5326 If the action object is not available for external dispatch or the dispatcher
472             cannot determine an appropriate URI, this method will return undef.
473 2901         3759  
474             =cut
475 2901 100       5202  
476 2276         2935 my ( $self, $action, $captures) = @_;
477 3657         91066 $captures ||= [];
478             foreach my $dispatch_type ( @{ $self->dispatch_types } ) {
479             my $uri = $dispatch_type->uri_for_action( $action, $captures );
480             return( $uri eq '' ? '/' : $uri )
481 2901         68722 if defined($uri);
  6558         14943  
482             }
483             return undef;
484             }
485              
486             =head2 expand_action
487              
488             expand an action into a full representation of the dispatch.
489             mostly useful for chained, other actions will just return a
490             single action.
491              
492             =cut
493              
494             my ($self, $action) = @_;
495              
496 78     78 1 175 foreach my $dispatch_type (@{ $self->dispatch_types }) {
497 78   100     183 my $expanded = $dispatch_type->expand_action($action);
498 78         112 return $expanded if $expanded;
  78         2089  
499 270         823 }
500 270 100       1005  
    100          
501             return $action;
502             }
503 8         35  
504             =head2 $self->register( $c, $action )
505              
506             Make sure all required dispatch types for this action are loaded, then
507             pass the action to our dispatch types so they can register it if required.
508             Also, set up the tree with the action containers.
509              
510             =cut
511              
512             my ( $self, $c, $action ) = @_;
513              
514             my $registered = $self->_registered_dispatch_types;
515 178     178 1 342  
516             foreach my $key ( keys %{ $action->attributes } ) {
517 178         224 next if $key eq 'Private';
  178         4532  
518 780         2030 my $class = "Catalyst::DispatchType::$key";
519 780 100       1457 unless ( $registered->{$class} ) {
520             # FIXME - Some error checking and re-throwing needed here, as
521             # we eat exceptions loading dispatch types.
522 81         182 # see also try_load_class
523             eval { load_class($class) };
524             my $load_failed = $@;
525             $self->_check_deprecated_dispatch_type( $key, $load_failed );
526             push( @{ $self->dispatch_types }, $class->new ) unless $load_failed;
527             $registered->{$class} = 1;
528             }
529             }
530              
531             my @dtypes = @{ $self->dispatch_types };
532             my @normal_dtypes;
533             my @low_precedence_dtypes;
534 69164     69164 1 128146  
535             for my $type ( @dtypes ) {
536 69164         1846550 if ($type->_is_low_precedence) {
537             push @low_precedence_dtypes, $type;
538 69164         91424 } else {
  69164         1488076  
539 97084 100       191675 push @normal_dtypes, $type;
540 55512         85655 }
541 55512 100       123181 }
542              
543             # Pass the action to our dispatch types so they can register it if reqd.
544             my $was_registered = 0;
545 1153         2831 foreach my $type ( @normal_dtypes ) {
  1153         3626  
546 1153         538682 $was_registered = 1 if $type->register( $c, $action );
547 1153         5102 }
548 1153 100       2805  
  106         3321  
549 1153         4396 if (not $was_registered) {
550             foreach my $type ( @low_precedence_dtypes ) {
551             $type->register( $c, $action );
552             }
553 69164         96388 }
  69164         1602295  
554 69164         105262  
555             my $namespace = $action->namespace;
556             my $name = $action->name;
557 69164         102684  
558 285816 100       564420 my $container = $self->_find_or_create_action_container($namespace);
559 76261         129935  
560             # Set the method value
561 209555         279818 $container->add_action($action);
562              
563             $self->_action_hash->{"$namespace/$name"} = $action;
564             $self->_container_hash->{$namespace} = $container;
565             }
566 69164         86094  
567 69164         90455 my ( $self, $namespace ) = @_;
568 209544 100       463078  
569             my $tree ||= $self->_tree;
570              
571 69160 100       121958 return $tree->getNodeValue unless $namespace;
572 41746         57994  
573 45807         100768 my @namespace = split '/', $namespace;
574             return $self->_find_or_create_namespace_node( $tree, @namespace )
575             ->getNodeValue;
576             }
577 69160         1468098  
578 69160         1383446 my ( $self, $parent, $part, @namespace ) = @_;
579              
580 69160         145614 return $parent unless $part;
581              
582             my $child =
583 69160         327586 ( grep { $_->getNodeValue->part eq $part } $parent->getAllChildren )[0];
584              
585 69160         1566367 unless ($child) {
586 69160         1592804 my $container = Catalyst::ActionContainer->new($part);
587             $parent->addChild( $child = Tree::Simple->new($container) );
588             }
589              
590 69160     69160   113482 $self->_find_or_create_namespace_node( $child, @namespace );
591             }
592 69160   33     1562592  
593             =head2 $self->setup_actions( $class, $context )
594 69160 100       126774  
595             Loads all of the pre-load dispatch types, registers their actions and then
596 65431         170092 loads all of the post-load dispatch types, and iterates over the tree of
597 65431         133600 actions, displaying the debug information if appropriate.
598              
599             =cut
600              
601             my ( $self, $c ) = @_;
602 208720     208720   366358  
603             my @classes =
604 208720 100       423784 $self->_load_dispatch_types( @{ $self->preload_dispatch_types } );
605             @{ $self->_registered_dispatch_types }{@classes} = (1) x @classes;
606              
607 143289         296886 foreach my $comp ( map @{$_}{sort keys %$_}, $c->components ) {
  776484         1944078  
608             $comp = $comp->() if ref($comp) eq 'CODE';
609 143289 100       287106 $comp->register_actions($c) if $comp->can('register_actions');
610 6234         152151 }
611 6234         22629  
612             $self->_load_dispatch_types( @{ $self->postload_dispatch_types } );
613              
614 143289         978998 return unless $c->debug;
615             $self->_display_action_tables($c);
616             }
617              
618             my ($self, $c) = @_;
619              
620             my $avail_width = Catalyst::Utils::term_width() - 12;
621             my $col1_width = ($avail_width * .25) < 20 ? 20 : int($avail_width * .25);
622             my $col2_width = ($avail_width * .50) < 36 ? 36 : int($avail_width * .50);
623             my $col3_width = $avail_width - $col1_width - $col2_width;
624             my $privates = Text::SimpleTable->new(
625             [ $col1_width, 'Private' ], [ $col2_width, 'Class' ], [ $col3_width, 'Method' ]
626 167     167 1 625 );
627              
628             my $has_private = 0;
629 167         481 my $walker = sub {
  167         1197  
630 167         909 my ( $walker, $parent, $prefix ) = @_;
  167         6666  
631             $prefix .= $parent->getNodeValue || '';
632 167         1362 $prefix .= '/' unless $prefix =~ /\/$/;
  167         5451  
633 7532 100       41082 my $node = $parent->getNodeValue->actions;
634 7532 100       78408  
635             for my $action ( keys %{$node} ) {
636             my $action_obj = $node->{$action};
637 163         1315 next
  163         1514  
638             if ( ( $action =~ /^_.*/ )
639 163 100       1519 && ( !$c->config->{show_internal_actions} ) );
640 7         62 $privates->row( "$prefix$action", $action_obj->class, $action );
641             $has_private = 1;
642             }
643              
644 7     7   39 $walker->( $walker, $_, $prefix ) for $parent->getAllChildren;
645             };
646 7         29  
647 7 50       40 $walker->( $walker, $self->_tree, '' );
648 7 50       26 $c->log->debug( "Loaded Private actions:\n" . $privates->draw . "\n" )
649 7         17 if $has_private;
650 7         70  
651             # List all public actions
652             $_->list($c) for @{ $self->dispatch_types };
653             }
654 7         806  
655             my ( $self, @types ) = @_;
656 11     11   87  
657 11   50     52 my @loaded;
658 11 100       60 # Preload action types
659 11         28 for my $type (@types) {
660             # first param is undef because we cannot get the appclass
661 11         33 my $class = Catalyst::Utils::resolve_namespace(undef, 'Catalyst::DispatchType', $type);
  11         50  
662 71         123  
663             my ($success, $error) = try_load_class($class);
664             Catalyst::Exception->throw( message => $error ) if not $success;
665 71 100 100     281 push @{ $self->dispatch_types }, $class->new;
666 26         733  
667 26         3016 push @loaded, $class;
668             }
669              
670 11         84 return @loaded;
671 7         61 }
672              
673 7         204 =head2 $self->dispatch_type( $type )
674 7 100       97  
675             Get the DispatchType object of the relevant type, i.e. passing C<$type> of
676             C<Chained> would return a L<Catalyst::DispatchType::Chained> object (assuming
677             of course it's being used.)
678 7         28  
  7         176  
679             =cut
680              
681             my ($self, $name) = @_;
682 330     330   75073  
683             # first param is undef because we cannot get the appclass
684 330         712 $name = Catalyst::Utils::resolve_namespace(undef, 'Catalyst::DispatchType', $name);
685              
686 330         1204 for (@{ $self->dispatch_types }) {
687             return $_ if ref($_) eq $name;
688 660         2752 }
689             return undef;
690 660         38717 }
691 660 50       141732  
692 660         1290 my ($self, $key, $load_failed) = @_;
  660         20900  
693              
694 660         127291 return unless $key =~ /^(Local)?Regexp?/;
695              
696             # TODO: Should these throw an exception rather than just warning?
697 330         1679 if ($load_failed) {
698             warn( "Attempt to use deprecated $key dispatch type.\n"
699             . " Use Chained methods or install the standalone\n"
700             . " Catalyst::DispatchType::Regex if necessary.\n" );
701             } elsif ( !defined $Catalyst::DispatchType::Regex::VERSION
702             || $Catalyst::DispatchType::Regex::VERSION le '5.90020' ) {
703             # We loaded the old core version of the Regex module this will break
704             warn( "The $key DispatchType has been removed from Catalyst core.\n"
705             . " An old version of the core Catalyst::DispatchType::Regex\n"
706             . " has been loaded and will likely fail. Please remove\n"
707             . " $INC{'Catalyst/DispatchType/Regex.pm'}\n"
708             . " and use Chained methods or install the standalone\n"
709 1     1 1 4 . " Catalyst::DispatchType::Regex if necessary.\n" );
710             }
711             }
712 1         6  
713             use Moose;
714 1         51  
  1         31  
715 3 100       19 # 5.70 backwards compatibility hacks.
716              
717 0         0 # Various plugins (e.g. Plugin::Server and Plugin::Authorization::ACL)
718             # need the methods here which *should* be private..
719              
720             # You should be able to use get_actions or get_containers appropriately
721 1153     1153   2919 # instead of relying on these methods which expose implementation details
722             # of the dispatcher..
723 1153 50       4490 #
724             # IRC backlog included below, please come ask if this doesn't work for you.
725             #
726 0 0 0       # <@t0m> 5.80, the state of. There are things in the dispatcher which have
    0          
727 0           # been deprecated, that we yell at anyone for using, which there isn't
728             # a good alternative for yet..
729             # <@mst> er, get_actions/get_containers provides that doesn't it?
730             # <@mst> DispatchTypes are loaded on demand anyway
731             # <@t0m> I'm thinking of things like _tree which is aliased to 'tree' with
732             # warnings otherwise shit breaks.. We're issuing warnings about the
733 0           # correct set of things which you shouldn't be calling..
734             # <@mst> right
735             # <@mst> basically, I don't see there's a need for a replacement for anything
736             # <@mst> it was never a good idea to call ->tree
737             # <@mst> nothingmuch was the only one who did AFAIK
738             # <@mst> and he admitted it was a hack ;)
739              
740             # See also t/lib/TestApp/Plugin/AddDispatchTypes.pm
741              
742 153     153   1465 # Alias _method_name to method_name, add a before modifier to warn..
  153         497  
  153         957  
743             foreach my $public_method_name (qw/
744             tree
745             registered_dispatch_types
746             method_action_class
747             action_hash
748             container_hash
749             /) {
750             my $private_method_name = '_' . $public_method_name;
751             my $meta = __PACKAGE__->meta; # Calling meta method here fine as we happen at compile time.
752             $meta->add_method($public_method_name, $meta->get_method($private_method_name));
753             {
754             my %package_hash; # Only warn once per method, per package. These are infrequent enough that
755             # I haven't provided a way to disable them, patches welcome.
756             $meta->add_before_method_modifier($public_method_name, sub {
757             my $class = caller(2);
758             chomp($class);
759             $package_hash{$class}++ || do {
760             warn("Class $class is calling the deprecated method\n"
761             . " Catalyst::Dispatcher::$public_method_name,\n"
762             . " this will be removed in Catalyst 5.9\n");
763             };
764             });
765             }
766             }
767             # End 5.70 backwards compatibility hacks.
768              
769             __PACKAGE__->meta->make_immutable;
770              
771             =head2 meta
772              
773             Provided by Moose
774              
775             =head1 AUTHORS
776              
777             Catalyst Contributors, see Catalyst.pm
778              
779             =head1 COPYRIGHT
780              
781             This library is free software. You can redistribute it and/or modify it under
782             the same terms as Perl itself.
783              
784             =cut
785              
786             1;