File Coverage

blib/lib/Catalyst/Dispatcher.pm
Criterion Covered Total %
statement 318 331 96.0
branch 104 128 81.2
condition 23 31 74.1
subroutine 46 46 100.0
pod 15 15 100.0
total 506 551 91.8


line stmt bran cond sub pod time code
1              
2             use Moose;
3 154     154   111406 use Class::MOP;
  154         412  
  154         1267  
4 154     154   1048041 with 'MooseX::Emulate::Class::Accessor::Fast';
  154         431  
  154         6213  
5              
6             use Catalyst::Exception;
7 154     154   1448 use Catalyst::Utils;
  154         367  
  154         4212  
8 154     154   936 use Catalyst::Action;
  154         387  
  154         4043  
9 154     154   75248 use Catalyst::ActionContainer;
  154         651  
  154         6798  
10 154     154   83904 use Catalyst::DispatchType::Default;
  154         620  
  154         6016  
11 154     154   76252 use Catalyst::DispatchType::Index;
  154         666  
  154         5921  
12 154     154   75174 use Catalyst::Utils;
  154         623  
  154         5958  
13 154     154   1247 use Text::SimpleTable;
  154         393  
  154         3849  
14 154     154   1422 use Tree::Simple;
  154         2978  
  154         3835  
15 154     154   1490 use Class::Load qw(load_class try_load_class);
  154         3831  
  154         1555  
16 154     154   4589 use Encode 2.21 'decode_utf8';
  154         403  
  154         13468  
17 154     154   1663  
  154         18578  
  154         9189  
18             use namespace::clean -except => 'meta';
19 154     154   1196  
  154         420  
  154         1087  
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 163     163   553 my $container =
70             Catalyst::ActionContainer->new( { part => '/', actions => {} } );
71 163         6784  
72             return Tree::Simple->new($container, Tree::Simple->ROOT);
73             }
74 163         2990  
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 964     964 1 2920 }
106 964 100       26609 else {
107 955         26390 my $path = $c->req->path;
108             $path =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
109             $path = decode_utf8($path);
110 9         42  
111 9         35 my $error = $path
  0         0  
112 9         115 ? qq/Unknown resource "$path"/
113             : "No default action defined";
114 9 50       108 $c->log->error($error) if $c->debug;
115             $c->error($error);
116             }
117 9 50       40 }
118 9         77  
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 6958     6958   14623 return 0;
129             }
130 6958 50       14924  
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 6958         11300 }
136              
137 6958 100       15679 if ( ref( $extra_params[-1] ) eq 'ARRAY' ) {
138 4         11 @args = @{ pop @extra_params }
  4         17  
139             } else {
140             # this is a copy, it may take some abuse from
141 6958 100       15419 # ->_invoke_as_path if the path had trailing parts
142 24         59 @args = @{ $c->request->arguments };
  24         76  
143             }
144              
145             my $action;
146 6934         9942  
  6934         184078  
147             # go to a string path ("/foo/bar/gorch")
148             # or action object
149 6958         12102 if (blessed($command) && $command->isa('Catalyst::Action')) {
150             $action = $command;
151             }
152             else {
153 6958 100 100     23682 $action = $self->_invoke_as_path( $c, "$command", \@args );
154 2         7 }
155              
156             # go to a component ( "View::Foo" or $c->component("...")
157 6956         24496 # - 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 6957 100       19159  
163 133 100       532 return $action, \@args, \@captures;
164 133         584 }
165              
166             =head2 $self->visit( $c, $command [, \@arguments ] )
167 6957         25887  
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 65 my $opname = shift;
178 26         94 my ( $c, $command ) = @_;
179             my ( $action, $args, $captures ) = $self->_command2action(@_);
180             my $error = qq/Couldn't $opname("$command"): /;
181              
182 50     50   90 if (!$action) {
183 50         96 $error .= qq/Couldn't $opname to command "$command": /
184 50         118 .qq/Invalid action or component./;
185 50         133 }
186 50         180 elsif (!defined $action->namespace) {
187             $error .= qq/Action has no namespace: cannot $opname() to a plain /
188 50 50       141 .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         13 }
194             else {
195             $error = q();
196             }
197 4         27  
198             if($error) {
199             $c->error($error);
200             $c->log->debug($error) if $c->debug;
201 44         126 return 0;
202             }
203              
204 50 100       149 $action = $self->expand_action($action);
205 6         31  
206 6 50       23 local $c->request->{arguments} = $args;
207 6         202 local $c->request->{captures} = $captures;
208             local $c->{namespace} = $action->{'namespace'};
209             local $c->{action} = $action;
210 44         158  
211             $self->dispatch($c);
212 44         1102 }
213 44         1002  
214 44         164 =head2 $self->go( $c, $command [, \@arguments ] )
215 44         98  
216             Documented in L<Catalyst>
217 44         182  
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 48 Documented in L<Catalyst>
228 24         117  
229 13         180 =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 6894     6894 1 11975 my ( $action, $args, $captures ) = $self->_command2action(@_);
240 154     154   231573  
  154         504  
  154         29572  
241 6894         20128 if (!$action) {
242             my $error .= qq/Couldn't $opname to command "$command": /
243             .qq/Invalid action or component./;
244             $c->error($error);
245 6908     6908   10797 $c->log->debug($error) if $c->debug;
246 6908         10755 return 0;
247 6908         14715 }
248 6908         16115  
249              
250 6907 100       17022 local $c->request->{arguments} = $args;
251 1         7 no warnings 'recursion';
252             $action->dispatch( $c );
253 1         5  
254 1 50       5 #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 6906         170571 }
260 154     154   1324 return $c->state;
  154         458  
  154         518071  
261 6906         26363 }
262              
263             =head2 $self->detach( $c, $command [, \@arguments ] )
264              
265             Documented in L<Catalyst>
266 6862 100       13067  
  6862         19441  
267 1074         24928 =cut
268              
269 6862         162050 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 60 $path = "$namespace/$path";
280 16 100       91 }
281 14         364  
282 14         142 $path =~ s#^/##;
283             return $path;
284             }
285              
286 6956     6956   13550 my ( $self, $c, $rel_path, $args ) = @_;
287              
288 6956 100       18386 my $path = $self->_action_rel2abs( $c, $rel_path );
289 5970         139549  
290 5969         16633 my ( $tail, @extra_args );
291             while ( ( $path, $tail ) = ( $path =~ m#^(?:(.*)/)?(\w+)?$# ) )
292             { # allow $path to be empty
293 6955         18559 if ( my $action = $c->get_action( $tail, $path ) ) {
294 6955         16012 push @$args, @extra_args;
295             return $action;
296             }
297             else {
298 6956     6956   15019 return
299             unless $path
300 6956         15712 ; # if a match on the global namespace failed then the whole lookup failed
301             }
302 6955         12167  
303 6955         44514 unshift @extra_args, $tail;
304             }
305 6843 100       23249 }
306 6822         13220  
307 6822         19227 my ( $self, $c, $component ) = @_;
308              
309             # fugly, why doesn't ->component('MyApp') work?
310             return $c if ($component eq blessed($c));
311 21 100       72  
312             return blessed($component)
313             ? $component
314             : $c->component($component);
315 17         130 }
316              
317             my ( $self, $c, $component_or_class, $method ) = @_;
318              
319             my $component = $self->_find_component($c, $component_or_class);
320 133     133   354 my $component_class = blessed $component || return 0;
321              
322             if (my $code = $component_class->can('action_for')) {
323 133 100       724 my $possible_action = $component->$code($method);
324             return $possible_action if $possible_action;
325 130 100       786 }
326              
327             if ( my $code = $component_class->can($method) ) {
328             return $self->_method_action_class->new(
329             {
330             name => $method,
331 133     133   462 code => $code,
332             reverse => "$component_class->$method",
333 133         470 class => $component_class,
334 133   100     764 ( blessed($component_or_class) ? (instance => $component_or_class):() ),
335             namespace => Catalyst::Utils::class2prefix(
336 132 100       1622 $component_class, ref($c)->config->{case_sensitive}
337 24         117 ),
338 24 100       113 }
339             );
340             }
341 110 50       805 else {
342             my $error =
343             qq/Couldn't forward to "$component_class". Does not implement "$method"/;
344             $c->error($error);
345             $c->log->debug($error)
346             if $c->debug;
347             return 0;
348             }
349             }
350              
351 110 100       4049 =head2 $self->prepare_action($c)
352              
353             Find an dispatch type that matches $c->req->path, and set args from it.
354              
355             =cut
356 0         0  
357             my ( $self, $c ) = @_;
358 0         0 my $req = $c->req;
359 0 0       0 my $path = $req->path;
360             my @path = split /\//, $req->path;
361 0         0 $req->args( \my @args );
362              
363             unshift( @path, '' ); # Root action
364              
365             DESCEND: while (@path) {
366             $path = join '/', @path;
367             $path =~ s#^/+##;
368              
369             # Check out dispatch types to see if any will handle the path at
370             # this level
371              
372 922     922 1 2929 foreach my $type ( @{ $self->dispatch_types } ) {
373 922         3829 last DESCEND if $type->match( $c, $path );
374 922         5042 }
375 922         3303  
376 922         5478 # If not, move the last part path to args
377             my $arg = pop(@path);
378 922         2998 $arg =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
379             unshift @args, $arg;
380 922         3090 }
381 1399         5023  
382 1399         5910 s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg for grep { defined } @{$req->captures||[]};
383              
384             if($c->debug && defined $req->match && length $req->match) {
385             my $match = $req->match;
386             $match =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
387 1399         2967 $match = decode_utf8($match);
  1399         43340  
388 5003 100       24710 $c->log->debug( 'Path is "' . $match . '"' )
389             }
390              
391             $c->log->debug( 'Arguments are "' . join( '/', map { decode_utf8 $_ } @args ) . '"' )
392 487         1973 if ( $c->debug && @args );
393 487         1401 }
  71         311  
394 487         1771  
395             =head2 $self->get_action( $action_name, $namespace )
396              
397 922 50       2483 returns a named action from a given namespace. C<$action_name>
  194         1025  
  922         26039  
  39         207  
398             may be a relative path on that C<$namespace> such as
399 922 50 66     3793  
      66        
400 16         396 $self->get_action('../bar', 'foo/baz');
401 16         96  
  0         0  
402 16         263 In which case we look for the action at 'foo/bar'.
403 16         179  
404             =cut
405              
406 922 100 100     3075 my ( $self, $name, $namespace ) = @_;
  7         48  
407             return unless $name;
408              
409             $namespace = join( "/", grep { length } split '/', ( defined $namespace ? $namespace : "" ) );
410              
411             return $self->get_action_by_path("${namespace}/${name}");
412             }
413              
414             =head2 $self->get_action_by_path( $path );
415              
416             Returns the named action by its full private path.
417              
418             This method performs some normalization on C<$path> so that if
419             it includes '..' it will do the right thing (for example if
420             C<$path> is '/foo/../bar' that is normalized to '/bar'.
421              
422 7830     7830 1 18978 =cut
423 7830 50       20032  
424             my ( $self, $path ) = @_;
425 7830 100       28088 $path =~s/[^\/]+\/\.\.\/// while $path=~m/[^\/]+\/\.\.\//;
  8585         20929  
426             $path =~ s/^\///;
427 7830         27231 $path = "/$path" unless $path =~ /\//;
428             $self->_action_hash->{$path};
429             }
430              
431             =head2 $self->get_actions( $c, $action, $namespace )
432              
433             =cut
434              
435             my ( $self, $c, $action, $namespace ) = @_;
436             return [] unless $action;
437              
438             $namespace = join( "/", grep { length } split '/', $namespace || "" );
439              
440             my @match = $self->get_containers($namespace);
441 7865     7865 1 17151  
442 7865         23050 return map { $_->get_action($action) } @match;
443 7865         19563 }
444 7865 100       23514  
445 7865         245142 =head2 $self->get_containers( $namespace )
446              
447             Return all the action containers for a given namespace, inclusive
448              
449             =cut
450              
451             my ( $self, $namespace ) = @_;
452             $namespace ||= '';
453 2907     2907 1 8187 $namespace = '' if $namespace eq '/';
454 2907 50       6701  
455             my @containers;
456 2907   100     12279  
  3663         9495  
457             if ( length $namespace ) {
458 2907         8472 do {
459             push @containers, $self->_container_hash->{$namespace};
460 2907         5965 } while ( $namespace =~ s#/[^/]+$## );
  6175         18738  
461             }
462              
463             return reverse grep { defined } @containers, $self->_container_hash->{''};
464             }
465              
466             =head2 $self->uri_for_action($action, \@captures)
467              
468             Takes a Catalyst::Action object and action parameters and returns a URI
469             part such that if $c->req->path were this URI part, this action would be
470 2907     2907 1 6410 dispatched to with $c->req->captures set to the supplied arrayref.
471 2907   100     7808  
472 2907 50       6927 If the action object is not available for external dispatch or the dispatcher
473             cannot determine an appropriate URI, this method will return undef.
474 2907         4601  
475             =cut
476 2907 100       6628  
477 2282         3783 my ( $self, $action, $captures) = @_;
478 3663         109628 $captures ||= [];
479             foreach my $dispatch_type ( @{ $self->dispatch_types } ) {
480             my $uri = $dispatch_type->uri_for_action( $action, $captures );
481             return( $uri eq '' ? '/' : $uri )
482 2907         82061 if defined($uri);
  6570         17704  
483             }
484             return undef;
485             }
486              
487             =head2 expand_action
488              
489             expand an action into a full representation of the dispatch.
490             mostly useful for chained, other actions will just return a
491             single action.
492              
493             =cut
494              
495             my ($self, $action) = @_;
496              
497 78     78 1 221 foreach my $dispatch_type (@{ $self->dispatch_types }) {
498 78   100     216 my $expanded = $dispatch_type->expand_action($action);
499 78         137 return $expanded if $expanded;
  78         2384  
500 270         933 }
501 270 100       1203  
    100          
502             return $action;
503             }
504 8         35  
505             =head2 $self->register( $c, $action )
506              
507             Make sure all required dispatch types for this action are loaded, then
508             pass the action to our dispatch types so they can register it if required.
509             Also, set up the tree with the action containers.
510              
511             =cut
512              
513             my ( $self, $c, $action ) = @_;
514              
515             my $registered = $self->_registered_dispatch_types;
516 178     178 1 409  
517             foreach my $key ( keys %{ $action->attributes } ) {
518 178         287 next if $key eq 'Private';
  178         5461  
519 780         2456 my $class = "Catalyst::DispatchType::$key";
520 780 100       1759 unless ( $registered->{$class} ) {
521             # FIXME - Some error checking and re-throwing needed here, as
522             # we eat exceptions loading dispatch types.
523 81         191 # see also try_load_class
524             eval { load_class($class) };
525             my $load_failed = $@;
526             $self->_check_deprecated_dispatch_type( $key, $load_failed );
527             push( @{ $self->dispatch_types }, $class->new ) unless $load_failed;
528             $registered->{$class} = 1;
529             }
530             }
531              
532             my @dtypes = @{ $self->dispatch_types };
533             my @normal_dtypes;
534             my @low_precedence_dtypes;
535 69176     69176 1 158319  
536             for my $type ( @dtypes ) {
537 69176         2229312 if ($type->_is_low_precedence) {
538             push @low_precedence_dtypes, $type;
539 69176         111467 } else {
  69176         1799524  
540 97098 100       228788 push @normal_dtypes, $type;
541 55516         107584 }
542 55516 100       150871 }
543              
544             # Pass the action to our dispatch types so they can register it if reqd.
545             my $was_registered = 0;
546 1154         2810 foreach my $type ( @normal_dtypes ) {
  1154         4424  
547 1154         642295 $was_registered = 1 if $type->register( $c, $action );
548 1154         6193 }
549 1154 100       3541  
  106         3957  
550 1154         5007 if (not $was_registered) {
551             foreach my $type ( @low_precedence_dtypes ) {
552             $type->register( $c, $action );
553             }
554 69176         116768 }
  69176         1940080  
555 69176         128463  
556             my $namespace = $action->namespace;
557             my $name = $action->name;
558 69176         123495  
559 285840 100       680865 my $container = $self->_find_or_create_action_container($namespace);
560 76273         155407  
561             # Set the method value
562 209567         336237 $container->add_action($action);
563              
564             $self->_action_hash->{"$namespace/$name"} = $action;
565             $self->_container_hash->{$namespace} = $container;
566             }
567 69176         104943  
568 69176         108777 my ( $self, $namespace ) = @_;
569 209556 100       556472  
570             my $tree ||= $self->_tree;
571              
572 69172 100       148469 return $tree->getNodeValue unless $namespace;
573 41756         71807  
574 45817         122002 my @namespace = split '/', $namespace;
575             return $self->_find_or_create_namespace_node( $tree, @namespace )
576             ->getNodeValue;
577             }
578 69172         1780727  
579 69172         1675238 my ( $self, $parent, $part, @namespace ) = @_;
580              
581 69172         173728 return $parent unless $part;
582              
583             my $child =
584 69172         393081 ( grep { $_->getNodeValue->part eq $part } $parent->getAllChildren )[0];
585              
586 69172         1895399 unless ($child) {
587 69172         1936381 my $container = Catalyst::ActionContainer->new($part);
588             $parent->addChild( $child = Tree::Simple->new($container) );
589             }
590              
591 69172     69172   137042 $self->_find_or_create_namespace_node( $child, @namespace );
592             }
593 69172   33     1887820  
594             =head2 $self->setup_actions( $class, $context )
595 69172 100       152203  
596             Loads all of the pre-load dispatch types, registers their actions and then
597 65438         204915 loads all of the post-load dispatch types, and iterates over the tree of
598 65438         160111 actions, displaying the debug information if appropriate.
599              
600             =cut
601              
602             my ( $self, $c ) = @_;
603 208734     208734   446473  
604             my @classes =
605 208734 100       508922 $self->_load_dispatch_types( @{ $self->preload_dispatch_types } );
606             @{ $self->_registered_dispatch_types }{@classes} = (1) x @classes;
607              
608 143296         356585 foreach my $comp ( map @{$_}{sort keys %$_}, $c->components ) {
  776490         2337721  
609             $comp = $comp->() if ref($comp) eq 'CODE';
610 143296 100       348023 $comp->register_actions($c) if $comp->can('register_actions');
611 6235         189799 }
612 6235         31682  
613             $self->_load_dispatch_types( @{ $self->postload_dispatch_types } );
614              
615 143296         1300693 return unless $c->debug;
616             $self->_display_action_tables($c);
617             }
618              
619             my ($self, $c) = @_;
620              
621             my $avail_width = Catalyst::Utils::term_width() - 12;
622             my $col1_width = ($avail_width * .25) < 20 ? 20 : int($avail_width * .25);
623             my $col2_width = ($avail_width * .50) < 36 ? 36 : int($avail_width * .50);
624             my $col3_width = $avail_width - $col1_width - $col2_width;
625             my $privates = Text::SimpleTable->new(
626             [ $col1_width, 'Private' ], [ $col2_width, 'Class' ], [ $col3_width, 'Method' ]
627 168     168 1 847 );
628              
629             my $has_private = 0;
630 168         796 my $walker = sub {
  168         1259  
631 168         789 my ( $walker, $parent, $prefix ) = @_;
  168         6100  
632             $prefix .= $parent->getNodeValue || '';
633 168         1720 $prefix .= '/' unless $prefix =~ /\/$/;
  168         3921  
634 7535 100       36286 my $node = $parent->getNodeValue->actions;
635 7535 100       92768  
636             for my $action ( keys %{$node} ) {
637             my $action_obj = $node->{$action};
638 164         1435 next
  164         1488  
639             if ( ( $action =~ /^_.*/ )
640 164 100       1514 && ( !$c->config->{show_internal_actions} ) );
641 7         64 $privates->row( "$prefix$action", $action_obj->class, $action );
642             $has_private = 1;
643             }
644              
645 7     7   41 $walker->( $walker, $_, $prefix ) for $parent->getAllChildren;
646             };
647 7         47  
648 7 50       46 $walker->( $walker, $self->_tree, '' );
649 7 50       31 $c->log->debug( "Loaded Private actions:\n" . $privates->draw . "\n" )
650 7         19 if $has_private;
651 7         78  
652             # List all public actions
653             $_->list($c) for @{ $self->dispatch_types };
654             }
655 7         958  
656             my ( $self, @types ) = @_;
657 11     11   72  
658 11   50     44 my @loaded;
659 11 100       62 # Preload action types
660 11         39 for my $type (@types) {
661             # first param is undef because we cannot get the appclass
662 11         26 my $class = Catalyst::Utils::resolve_namespace(undef, 'Catalyst::DispatchType', $type);
  11         52  
663 71         135  
664             my ($success, $error) = try_load_class($class);
665             Catalyst::Exception->throw( message => $error ) if not $success;
666 71 100 100     347 push @{ $self->dispatch_types }, $class->new;
667 26         788  
668 26         3458 push @loaded, $class;
669             }
670              
671 11         54 return @loaded;
672 7         78 }
673              
674 7         265 =head2 $self->dispatch_type( $type )
675 7 100       95  
676             Get the DispatchType object of the relevant type, i.e. passing C<$type> of
677             C<Chained> would return a L<Catalyst::DispatchType::Chained> object (assuming
678             of course it's being used.)
679 7         24  
  7         210  
680             =cut
681              
682             my ($self, $name) = @_;
683 332     332   85311  
684             # first param is undef because we cannot get the appclass
685 332         861 $name = Catalyst::Utils::resolve_namespace(undef, 'Catalyst::DispatchType', $name);
686              
687 332         1222 for (@{ $self->dispatch_types }) {
688             return $_ if ref($_) eq $name;
689 663         3281 }
690             return undef;
691 663         46723 }
692 663 50       162629  
693 663         1519 my ($self, $key, $load_failed) = @_;
  663         24135  
694              
695 663         145615 return unless $key =~ /^(Local)?Regexp?/;
696              
697             # TODO: Should these throw an exception rather than just warning?
698 332         3100 if ($load_failed) {
699             warn( "Attempt to use deprecated $key dispatch type.\n"
700             . " Use Chained methods or install the standalone\n"
701             . " Catalyst::DispatchType::Regex if necessary.\n" );
702             } elsif ( !defined $Catalyst::DispatchType::Regex::VERSION
703             || $Catalyst::DispatchType::Regex::VERSION le '5.90020' ) {
704             # We loaded the old core version of the Regex module this will break
705             warn( "The $key DispatchType has been removed from Catalyst core.\n"
706             . " An old version of the core Catalyst::DispatchType::Regex\n"
707             . " has been loaded and will likely fail. Please remove\n"
708             . " $INC{'Catalyst/DispatchType/Regex.pm'}\n"
709             . " and use Chained methods or install the standalone\n"
710 1     1 1 5 . " Catalyst::DispatchType::Regex if necessary.\n" );
711             }
712             }
713 1         6  
714             use Moose;
715 1         81  
  1         38  
716 3 100       17 # 5.70 backwards compatibility hacks.
717              
718 0         0 # Various plugins (e.g. Plugin::Server and Plugin::Authorization::ACL)
719             # need the methods here which *should* be private..
720              
721             # You should be able to use get_actions or get_containers appropriately
722 1154     1154   3682 # instead of relying on these methods which expose implementation details
723             # of the dispatcher..
724 1154 50       5426 #
725             # IRC backlog included below, please come ask if this doesn't work for you.
726             #
727 0 0 0       # <@t0m> 5.80, the state of. There are things in the dispatcher which have
    0          
728 0           # been deprecated, that we yell at anyone for using, which there isn't
729             # a good alternative for yet..
730             # <@mst> er, get_actions/get_containers provides that doesn't it?
731             # <@mst> DispatchTypes are loaded on demand anyway
732             # <@t0m> I'm thinking of things like _tree which is aliased to 'tree' with
733             # warnings otherwise shit breaks.. We're issuing warnings about the
734 0           # correct set of things which you shouldn't be calling..
735             # <@mst> right
736             # <@mst> basically, I don't see there's a need for a replacement for anything
737             # <@mst> it was never a good idea to call ->tree
738             # <@mst> nothingmuch was the only one who did AFAIK
739             # <@mst> and he admitted it was a hack ;)
740              
741             # See also t/lib/TestApp/Plugin/AddDispatchTypes.pm
742              
743 154     154   1561 # Alias _method_name to method_name, add a before modifier to warn..
  154         508  
  154         1187  
744             foreach my $public_method_name (qw/
745             tree
746             registered_dispatch_types
747             method_action_class
748             action_hash
749             container_hash
750             /) {
751             my $private_method_name = '_' . $public_method_name;
752             my $meta = __PACKAGE__->meta; # Calling meta method here fine as we happen at compile time.
753             $meta->add_method($public_method_name, $meta->get_method($private_method_name));
754             {
755             my %package_hash; # Only warn once per method, per package. These are infrequent enough that
756             # I haven't provided a way to disable them, patches welcome.
757             $meta->add_before_method_modifier($public_method_name, sub {
758             my $class = caller(2);
759             chomp($class);
760             $package_hash{$class}++ || do {
761             warn("Class $class is calling the deprecated method\n"
762             . " Catalyst::Dispatcher::$public_method_name,\n"
763             . " this will be removed in Catalyst 5.9\n");
764             };
765             });
766             }
767             }
768             # End 5.70 backwards compatibility hacks.
769              
770             __PACKAGE__->meta->make_immutable;
771              
772             =head2 meta
773              
774             Provided by Moose
775              
776             =head1 AUTHORS
777              
778             Catalyst Contributors, see Catalyst.pm
779              
780             =head1 COPYRIGHT
781              
782             This library is free software. You can redistribute it and/or modify it under
783             the same terms as Perl itself.
784              
785             =cut
786              
787             1;