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             package Catalyst::Dispatcher;
2              
3 155     155   122232 use Moose;
  155         466  
  155         1330  
4 155     155   1134483 use Class::MOP;
  155         454  
  155         6942  
5             with 'MooseX::Emulate::Class::Accessor::Fast';
6              
7 155     155   1719 use Catalyst::Exception;
  155         428  
  155         4692  
8 155     155   1168 use Catalyst::Utils;
  155         428  
  155         4609  
9 155     155   83802 use Catalyst::Action;
  155         736  
  155         7549  
10 155     155   93918 use Catalyst::ActionContainer;
  155         772  
  155         6133  
11 155     155   80114 use Catalyst::DispatchType::Default;
  155         770  
  155         6139  
12 155     155   77565 use Catalyst::DispatchType::Index;
  155         786  
  155         6185  
13 155     155   1490 use Catalyst::Utils;
  155         449  
  155         4412  
14 155     155   1547 use Text::SimpleTable;
  155         3122  
  155         4312  
15 155     155   1592 use Tree::Simple;
  155         3917  
  155         1914  
16 155     155   5233 use Class::Load qw(load_class try_load_class);
  155         491  
  155         14789  
17 155     155   1971 use Encode 2.21 'decode_utf8';
  155         20387  
  155         10458  
18              
19 155     155   1346 use namespace::clean -except => 'meta';
  155         572  
  155         1232  
20              
21             # Refactoring note:
22             # do these belong as package vars or should we build these via a builder method?
23             # See Catalyst-Plugin-Server for them being added to, which should be much less ugly.
24              
25             # Preload these action types
26             our @PRELOAD = qw/Index Path/;
27              
28             # Postload these action types
29             our @POSTLOAD = qw/Default/;
30              
31             # Note - see back-compat methods at end of file.
32             has _tree => (is => 'rw', builder => '_build__tree');
33             has dispatch_types => (is => 'rw', default => sub { [] }, required => 1, lazy => 1);
34             has _registered_dispatch_types => (is => 'rw', default => sub { {} }, required => 1, lazy => 1);
35             has _method_action_class => (is => 'rw', default => 'Catalyst::Action');
36             has _action_hash => (is => 'rw', required => 1, lazy => 1, default => sub { {} });
37             has _container_hash => (is => 'rw', required => 1, lazy => 1, default => sub { {} });
38              
39             my %dispatch_types = ( pre => \@PRELOAD, post => \@POSTLOAD );
40             foreach my $type (keys %dispatch_types) {
41             has $type . "load_dispatch_types" => (
42             is => 'rw', required => 1, lazy => 1, default => sub { $dispatch_types{$type} },
43             traits => ['MooseX::Emulate::Class::Accessor::Fast::Meta::Role::Attribute'], # List assignment is CAF style
44             );
45             }
46              
47             =head1 NAME
48              
49             Catalyst::Dispatcher - The Catalyst Dispatcher
50              
51             =head1 SYNOPSIS
52              
53             See L<Catalyst>.
54              
55             =head1 DESCRIPTION
56              
57             This is the class that maps public urls to actions in your Catalyst
58             application based on the attributes you set.
59              
60             =head1 METHODS
61              
62             =head2 new
63              
64             Construct a new dispatcher.
65              
66             =cut
67              
68             sub _build__tree {
69 164     164   585 my ($self) = @_;
70              
71 164         7296 my $container =
72             Catalyst::ActionContainer->new( { part => '/', actions => {} } );
73              
74 164         6772 return Tree::Simple->new($container, Tree::Simple->ROOT);
75             }
76              
77             =head2 $self->preload_dispatch_types
78              
79             An arrayref of pre-loaded dispatchtype classes
80              
81             Entries are considered to be available as C<Catalyst::DispatchType::CLASS>
82             To use a custom class outside the regular C<Catalyst> namespace, prefix
83             it with a C<+>, like so:
84              
85             +My::Dispatch::Type
86              
87             =head2 $self->postload_dispatch_types
88              
89             An arrayref of post-loaded dispatchtype classes
90              
91             Entries are considered to be available as C<Catalyst::DispatchType::CLASS>
92             To use a custom class outside the regular C<Catalyst> namespace, prefix
93             it with a C<+>, like so:
94              
95             +My::Dispatch::Type
96              
97             =head2 $self->dispatch($c)
98              
99             Delegate the dispatch to the action that matched the url, or return a
100             message about unknown resource
101              
102             =cut
103              
104             sub dispatch {
105 969     969 1 3356 my ( $self, $c ) = @_;
106 969 100       28334 if ( my $action = $c->action ) {
107 960         28023 $c->forward( join( '/', '', $action->namespace, '_DISPATCH' ) );
108             }
109             else {
110 9         51 my $path = $c->req->path;
111 9         51 $path =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
  0         0  
112 9         125 $path = decode_utf8($path);
113              
114 9 50       125 my $error = $path
115             ? qq/Unknown resource "$path"/
116             : "No default action defined";
117 9 50       48 $c->log->error($error) if $c->debug;
118 9         108 $c->error($error);
119             }
120             }
121              
122             # $self->_command2action( $c, $command [, \@arguments ] )
123             # $self->_command2action( $c, $command [, \@captures, \@arguments ] )
124             # Search for an action, from the command and returns C<($action, $args, $captures)> on
125             # success. Returns C<(0)> on error.
126              
127             sub _command2action {
128 6983     6983   14479 my ( $self, $c, $command, @extra_params ) = @_;
129              
130 6983 50       15113 unless ($command) {
131 0 0       0 $c->log->debug('Nothing to go to') if $c->debug;
132 0         0 return 0;
133             }
134              
135 6983         11295 my (@args, @captures);
136              
137 6983 100       16242 if ( ref( $extra_params[-2] ) eq 'ARRAY' ) {
138 4         17 @captures = @{ splice @extra_params, -2, 1 };
  4         18  
139             }
140              
141 6983 100       14065 if ( ref( $extra_params[-1] ) eq 'ARRAY' ) {
142 24         59 @args = @{ pop @extra_params }
  24         74  
143             } else {
144             # this is a copy, it may take some abuse from
145             # ->_invoke_as_path if the path had trailing parts
146 6959         10269 @args = @{ $c->request->arguments };
  6959         192938  
147             }
148              
149 6983         12658 my $action;
150              
151             # go to a string path ("/foo/bar/gorch")
152             # or action object
153 6983 100 100     24561 if (blessed($command) && $command->isa('Catalyst::Action')) {
154 2         8 $action = $command;
155             }
156             else {
157 6981         25066 $action = $self->_invoke_as_path( $c, "$command", \@args );
158             }
159              
160             # go to a component ( "View::Foo" or $c->component("...")
161             # - a path or an object)
162 6982 100       20162 unless ($action) {
163 133 100       601 my $method = @extra_params ? $extra_params[0] : "process";
164 133         619 $action = $self->_invoke_as_component( $c, $command, $method );
165             }
166              
167 6982         26160 return $action, \@args, \@captures;
168             }
169              
170             =head2 $self->visit( $c, $command [, \@arguments ] )
171              
172             Documented in L<Catalyst>
173              
174             =cut
175              
176             sub visit {
177 26     26 1 55 my $self = shift;
178 26         133 $self->_do_visit('visit', @_);
179             }
180              
181             sub _do_visit {
182 50     50   83 my $self = shift;
183 50         84 my $opname = shift;
184 50         117 my ( $c, $command ) = @_;
185 50         116 my ( $action, $args, $captures ) = $self->_command2action(@_);
186 50         202 my $error = qq/Couldn't $opname("$command"): /;
187              
188 50 50       145 if (!$action) {
    100          
    100          
189 0         0 $error .= qq/Couldn't $opname to command "$command": /
190             .qq/Invalid action or component./;
191             }
192             elsif (!defined $action->namespace) {
193 2         13 $error .= qq/Action has no namespace: cannot $opname() to a plain /
194             .qq/method or component, must be an :Action of some sort./
195             }
196             elsif (!$action->class->can('_DISPATCH')) {
197 4         22 $error .= qq/Action cannot _DISPATCH. /
198             .qq/Did you try to $opname() a non-controller action?/;
199             }
200             else {
201 44         106 $error = q();
202             }
203              
204 50 100       566 if($error) {
205 6         30 $c->error($error);
206 6 50       29 $c->log->debug($error) if $c->debug;
207 6         204 return 0;
208             }
209              
210 44         194 $action = $self->expand_action($action);
211              
212 44         1126 local $c->request->{arguments} = $args;
213 44         1046 local $c->request->{captures} = $captures;
214 44         122 local $c->{namespace} = $action->{'namespace'};
215 44         131 local $c->{action} = $action;
216              
217 44         230 $self->dispatch($c);
218             }
219              
220             =head2 $self->go( $c, $command [, \@arguments ] )
221              
222             Documented in L<Catalyst>
223              
224             =cut
225              
226             sub go {
227 24     24 1 48 my $self = shift;
228 24         139 $self->_do_visit('go', @_);
229 13         158 Catalyst::Exception::Go->throw;
230             }
231              
232             =head2 $self->forward( $c, $command [, \@arguments ] )
233              
234             Documented in L<Catalyst>
235              
236             =cut
237              
238             sub forward {
239 6919     6919 1 12195 my $self = shift;
240 155     155   252730 no warnings 'recursion';
  155         631  
  155         32691  
241 6919         20649 return $self->_do_forward(forward => @_);
242             }
243              
244             sub _do_forward {
245 6933     6933   10509 my $self = shift;
246 6933         10994 my $opname = shift;
247 6933         14657 my ( $c, $command ) = @_;
248 6933         16501 my ( $action, $args, $captures ) = $self->_command2action(@_);
249              
250 6932 100       17994 if (!$action) {
251 1         6 my $error .= qq/Couldn't $opname to command "$command": /
252             .qq/Invalid action or component./;
253 1         5 $c->error($error);
254 1 50       6 $c->log->debug($error) if $c->debug;
255 1         7 return 0;
256             }
257              
258              
259 6931         177786 local $c->request->{arguments} = $args;
260 155     155   1568 no warnings 'recursion';
  155         597  
  155         567445  
261 6931         28335 $action->dispatch( $c );
262              
263             #If there is an error, all bets off regarding state. Documentation
264             #Specifies that when you forward, if there's an error you must expect
265             #state to be 0.
266 6887 100       13568 if( @{ $c->error }) {
  6887         21090  
267 1074         26693 $c->state(0);
268             }
269 6887         168510 return $c->state;
270             }
271              
272             =head2 $self->detach( $c, $command [, \@arguments ] )
273              
274             Documented in L<Catalyst>
275              
276             =cut
277              
278             sub detach {
279 16     16 1 63 my ( $self, $c, $command, @args ) = @_;
280 16 100       96 $self->_do_forward(detach => $c, $command, @args ) if $command;
281 14         380 $c->state(0); # Needed in order to skip any auto functions
282 14         156 Catalyst::Exception::Detach->throw;
283             }
284              
285             sub _action_rel2abs {
286 6981     6981   13369 my ( $self, $c, $path ) = @_;
287              
288 6981 100       18169 unless ( $path =~ m#^/# ) {
289 5990         146931 my $namespace = $c->stack->[-1]->namespace;
290 5989         17172 $path = "$namespace/$path";
291             }
292              
293 6980         18989 $path =~ s#^/##;
294 6980         15838 return $path;
295             }
296              
297             sub _invoke_as_path {
298 6981     6981   15331 my ( $self, $c, $rel_path, $args ) = @_;
299              
300 6981         15559 my $path = $self->_action_rel2abs( $c, $rel_path );
301              
302 6980         12216 my ( $tail, @extra_args );
303 6980         46500 while ( ( $path, $tail ) = ( $path =~ m#^(?:(.*)/)?(\w+)?$# ) )
304             { # allow $path to be empty
305 6868 100       23209 if ( my $action = $c->get_action( $tail, $path ) ) {
306 6847         13448 push @$args, @extra_args;
307 6847         19711 return $action;
308             }
309             else {
310             return
311 21 100       96 unless $path
312             ; # if a match on the global namespace failed then the whole lookup failed
313             }
314              
315 17         140 unshift @extra_args, $tail;
316             }
317             }
318              
319             sub _find_component {
320 133     133   395 my ( $self, $c, $component ) = @_;
321              
322             # fugly, why doesn't ->component('MyApp') work?
323 133 100       665 return $c if ($component eq blessed($c));
324              
325 130 100       850 return blessed($component)
326             ? $component
327             : $c->component($component);
328             }
329              
330             sub _invoke_as_component {
331 133     133   433 my ( $self, $c, $component_or_class, $method ) = @_;
332              
333 133         476 my $component = $self->_find_component($c, $component_or_class);
334 133   100     744 my $component_class = blessed $component || return 0;
335              
336 132 100       1688 if (my $code = $component_class->can('action_for')) {
337 24         126 my $possible_action = $component->$code($method);
338 24 100       113 return $possible_action if $possible_action;
339             }
340              
341 110 50       698 if ( my $code = $component_class->can($method) ) {
342             return $self->_method_action_class->new(
343             {
344             name => $method,
345             code => $code,
346             reverse => "$component_class->$method",
347             class => $component_class,
348             ( blessed($component_or_class) ? (instance => $component_or_class):() ),
349             namespace => Catalyst::Utils::class2prefix(
350             $component_class, ref($c)->config->{case_sensitive}
351 110 100       4185 ),
352             }
353             );
354             }
355             else {
356 0         0 my $error =
357             qq/Couldn't forward to "$component_class". Does not implement "$method"/;
358 0         0 $c->error($error);
359 0 0       0 $c->log->debug($error)
360             if $c->debug;
361 0         0 return 0;
362             }
363             }
364              
365             =head2 $self->prepare_action($c)
366              
367             Find an dispatch type that matches $c->req->path, and set args from it.
368              
369             =cut
370              
371             sub prepare_action {
372 927     927 1 3252 my ( $self, $c ) = @_;
373 927         3491 my $req = $c->req;
374 927         5973 my $path = $req->path;
375 927         3687 my @path = split /\//, $req->path;
376 927         5053 $req->args( \my @args );
377              
378 927         3021 unshift( @path, '' ); # Root action
379              
380 927         3181 DESCEND: while (@path) {
381 1404         4882 $path = join '/', @path;
382 1404         6065 $path =~ s#^/+##;
383              
384             # Check out dispatch types to see if any will handle the path at
385             # this level
386              
387 1404         2882 foreach my $type ( @{ $self->dispatch_types } ) {
  1404         44655  
388 5018 100       23529 last DESCEND if $type->match( $c, $path );
389             }
390              
391             # If not, move the last part path to args
392 487         2008 my $arg = pop(@path);
393 487         1350 $arg =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
  71         322  
394 487         1820 unshift @args, $arg;
395             }
396              
397 927 50       2163 s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg for grep { defined } @{$req->captures||[]};
  195         1081  
  927         26702  
  39         189  
398              
399 927 50 66     3936 if($c->debug && defined $req->match && length $req->match) {
      66        
400 16         419 my $match = $req->match;
401 16         70 $match =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
  0         0  
402 16         216 $match = decode_utf8($match);
403 16         172 $c->log->debug( 'Path is "' . $match . '"' )
404             }
405              
406 927 100 100     2763 $c->log->debug( 'Arguments are "' . join( '/', map { decode_utf8 $_ } @args ) . '"' )
  7         54  
407             if ( $c->debug && @args );
408             }
409              
410             =head2 $self->get_action( $action_name, $namespace )
411              
412             returns a named action from a given namespace. C<$action_name>
413             may be a relative path on that C<$namespace> such as
414              
415             $self->get_action('../bar', 'foo/baz');
416              
417             In which case we look for the action at 'foo/bar'.
418              
419             =cut
420              
421             sub get_action {
422 7860     7860 1 19254 my ( $self, $name, $namespace ) = @_;
423 7860 50       20386 return unless $name;
424              
425 7860 100       29655 $namespace = join( "/", grep { length } split '/', ( defined $namespace ? $namespace : "" ) );
  8615         21061  
426              
427 7860         27368 return $self->get_action_by_path("${namespace}/${name}");
428             }
429              
430             =head2 $self->get_action_by_path( $path );
431              
432             Returns the named action by its full private path.
433              
434             This method performs some normalization on C<$path> so that if
435             it includes '..' it will do the right thing (for example if
436             C<$path> is '/foo/../bar' that is normalized to '/bar'.
437              
438             =cut
439              
440             sub get_action_by_path {
441 7895     7895 1 17352 my ( $self, $path ) = @_;
442 7895         22429 $path =~s/[^\/]+\/\.\.\/// while $path=~m/[^\/]+\/\.\.\//;
443 7895         19928 $path =~ s/^\///;
444 7895 100       22837 $path = "/$path" unless $path =~ /\//;
445 7895         254706 $self->_action_hash->{$path};
446             }
447              
448             =head2 $self->get_actions( $c, $action, $namespace )
449              
450             =cut
451              
452             sub get_actions {
453 2922     2922 1 8997 my ( $self, $c, $action, $namespace ) = @_;
454 2922 50       6821 return [] unless $action;
455              
456 2922   100     12586 $namespace = join( "/", grep { length } split '/', $namespace || "" );
  3675         9293  
457              
458 2922         8555 my @match = $self->get_containers($namespace);
459              
460 2922         6224 return map { $_->get_action($action) } @match;
  6202         18624  
461             }
462              
463             =head2 $self->get_containers( $namespace )
464              
465             Return all the action containers for a given namespace, inclusive
466              
467             =cut
468              
469             sub get_containers {
470 2922     2922 1 6336 my ( $self, $namespace ) = @_;
471 2922   100     8311 $namespace ||= '';
472 2922 50       6946 $namespace = '' if $namespace eq '/';
473              
474 2922         4777 my @containers;
475              
476 2922 100       6808 if ( length $namespace ) {
477 2294         3634 do {
478 3675         113992 push @containers, $self->_container_hash->{$namespace};
479             } while ( $namespace =~ s#/[^/]+$## );
480             }
481              
482 2922         85923 return reverse grep { defined } @containers, $self->_container_hash->{''};
  6597         18464  
483             }
484              
485             =head2 $self->uri_for_action($action, \@captures)
486              
487             Takes a Catalyst::Action object and action parameters and returns a URI
488             part such that if $c->req->path were this URI part, this action would be
489             dispatched to with $c->req->captures set to the supplied arrayref.
490              
491             If the action object is not available for external dispatch or the dispatcher
492             cannot determine an appropriate URI, this method will return undef.
493              
494             =cut
495              
496             sub uri_for_action {
497 78     78 1 264 my ( $self, $action, $captures) = @_;
498 78   100     226 $captures ||= [];
499 78         149 foreach my $dispatch_type ( @{ $self->dispatch_types } ) {
  78         2486  
500 270         1066 my $uri = $dispatch_type->uri_for_action( $action, $captures );
501 270 100       1273 return( $uri eq '' ? '/' : $uri )
    100          
502             if defined($uri);
503             }
504 8         43 return undef;
505             }
506              
507             =head2 expand_action
508              
509             expand an action into a full representation of the dispatch.
510             mostly useful for chained, other actions will just return a
511             single action.
512              
513             =cut
514              
515             sub expand_action {
516 178     178 1 431 my ($self, $action) = @_;
517              
518 178         274 foreach my $dispatch_type (@{ $self->dispatch_types }) {
  178         5807  
519 780         2549 my $expanded = $dispatch_type->expand_action($action);
520 780 100       1859 return $expanded if $expanded;
521             }
522              
523 81         224 return $action;
524             }
525              
526             =head2 $self->register( $c, $action )
527              
528             Make sure all required dispatch types for this action are loaded, then
529             pass the action to our dispatch types so they can register it if required.
530             Also, set up the tree with the action containers.
531              
532             =cut
533              
534             sub register {
535 69208     69208 1 158878 my ( $self, $c, $action ) = @_;
536              
537 69208         2289193 my $registered = $self->_registered_dispatch_types;
538              
539 69208         113809 foreach my $key ( keys %{ $action->attributes } ) {
  69208         1846233  
540 97154 100       235231 next if $key eq 'Private';
541 55552         109458 my $class = "Catalyst::DispatchType::$key";
542 55552 100       155892 unless ( $registered->{$class} ) {
543             # FIXME - Some error checking and re-throwing needed here, as
544             # we eat exceptions loading dispatch types.
545             # see also try_load_class
546 1158         3855 eval { load_class($class) };
  1158         4696  
547 1158         707184 my $load_failed = $@;
548 1158         6483 $self->_check_deprecated_dispatch_type( $key, $load_failed );
549 1158 100       3751 push( @{ $self->dispatch_types }, $class->new ) unless $load_failed;
  107         4361  
550 1158         5984 $registered->{$class} = 1;
551             }
552             }
553              
554 69208         118782 my @dtypes = @{ $self->dispatch_types };
  69208         1992921  
555 69208         129685 my @normal_dtypes;
556             my @low_precedence_dtypes;
557              
558 69208         130039 for my $type ( @dtypes ) {
559 285926 100       702787 if ($type->_is_low_precedence) {
560 76305         160928 push @low_precedence_dtypes, $type;
561             } else {
562 209621         344002 push @normal_dtypes, $type;
563             }
564             }
565              
566             # Pass the action to our dispatch types so they can register it if reqd.
567 69208         107021 my $was_registered = 0;
568 69208         109137 foreach my $type ( @normal_dtypes ) {
569 209610 100       568552 $was_registered = 1 if $type->register( $c, $action );
570             }
571              
572 69204 100       151235 if (not $was_registered) {
573 41776         71901 foreach my $type ( @low_precedence_dtypes ) {
574 45837         123422 $type->register( $c, $action );
575             }
576             }
577              
578 69204         1828933 my $namespace = $action->namespace;
579 69204         1715667 my $name = $action->name;
580              
581 69204         178185 my $container = $self->_find_or_create_action_container($namespace);
582              
583             # Set the method value
584 69204         402438 $container->add_action($action);
585              
586 69204         1942798 $self->_action_hash->{"$namespace/$name"} = $action;
587 69204         1980999 $self->_container_hash->{$namespace} = $container;
588             }
589              
590             sub _find_or_create_action_container {
591 69204     69204   140537 my ( $self, $namespace ) = @_;
592              
593 69204   33     1936942 my $tree ||= $self->_tree;
594              
595 69204 100       154842 return $tree->getNodeValue unless $namespace;
596              
597 65456         214368 my @namespace = split '/', $namespace;
598 65456         168018 return $self->_find_or_create_namespace_node( $tree, @namespace )
599             ->getNodeValue;
600             }
601              
602             sub _find_or_create_namespace_node {
603 208770     208770   455534 my ( $self, $parent, $part, @namespace ) = @_;
604              
605 208770 100       516430 return $parent unless $part;
606              
607             my $child =
608 143314         361672 ( grep { $_->getNodeValue->part eq $part } $parent->getAllChildren )[0];
  776514         2421073  
609              
610 143314 100       353810 unless ($child) {
611 6237         194856 my $container = Catalyst::ActionContainer->new($part);
612 6237         32745 $parent->addChild( $child = Tree::Simple->new($container) );
613             }
614              
615 143314         1284335 $self->_find_or_create_namespace_node( $child, @namespace );
616             }
617              
618             =head2 $self->setup_actions( $class, $context )
619              
620             Loads all of the pre-load dispatch types, registers their actions and then
621             loads all of the post-load dispatch types, and iterates over the tree of
622             actions, displaying the debug information if appropriate.
623              
624             =cut
625              
626             sub setup_actions {
627 169     169 1 837 my ( $self, $c ) = @_;
628              
629             my @classes =
630 169         554 $self->_load_dispatch_types( @{ $self->preload_dispatch_types } );
  169         3563  
631 169         1996 @{ $self->_registered_dispatch_types }{@classes} = (1) x @classes;
  169         7864  
632              
633 169         1778 foreach my $comp ( map @{$_}{sort keys %$_}, $c->components ) {
  169         3733  
634 7539 100       45577 $comp = $comp->() if ref($comp) eq 'CODE';
635 7539 100       99275 $comp->register_actions($c) if $comp->can('register_actions');
636             }
637              
638 165         1655 $self->_load_dispatch_types( @{ $self->postload_dispatch_types } );
  165         1716  
639              
640 165 100       1650 return unless $c->debug;
641 7         68 $self->_display_action_tables($c);
642             }
643              
644             sub _display_action_tables {
645 7     7   25 my ($self, $c) = @_;
646              
647 7         36 my $avail_width = Catalyst::Utils::term_width() - 12;
648 7 50       62 my $col1_width = ($avail_width * .25) < 20 ? 20 : int($avail_width * .25);
649 7 50       56 my $col2_width = ($avail_width * .50) < 36 ? 36 : int($avail_width * .50);
650 7         24 my $col3_width = $avail_width - $col1_width - $col2_width;
651 7         95 my $privates = Text::SimpleTable->new(
652             [ $col1_width, 'Private' ], [ $col2_width, 'Class' ], [ $col3_width, 'Method' ]
653             );
654              
655 7         1041 my $has_private = 0;
656             my $walker = sub {
657 11     11   91 my ( $walker, $parent, $prefix ) = @_;
658 11   50     49 $prefix .= $parent->getNodeValue || '';
659 11 100       85 $prefix .= '/' unless $prefix =~ /\/$/;
660 11         46 my $node = $parent->getNodeValue->actions;
661              
662 11         32 for my $action ( keys %{$node} ) {
  11         65  
663 71         136 my $action_obj = $node->{$action};
664             next
665             if ( ( $action =~ /^_.*/ )
666 71 100 100     352 && ( !$c->config->{show_internal_actions} ) );
667 26         831 $privates->row( "$prefix$action", $action_obj->class, $action );
668 26         4015 $has_private = 1;
669             }
670              
671 11         62 $walker->( $walker, $_, $prefix ) for $parent->getAllChildren;
672 7         64 };
673              
674 7         261 $walker->( $walker, $self->_tree, '' );
675 7 100       120 $c->log->debug( "Loaded Private actions:\n" . $privates->draw . "\n" )
676             if $has_private;
677              
678             # List all public actions
679 7         27 $_->list($c) for @{ $self->dispatch_types };
  7         251  
680             }
681              
682             sub _load_dispatch_types {
683 334     334   94728 my ( $self, @types ) = @_;
684              
685 334         908 my @loaded;
686             # Preload action types
687 334         1197 for my $type (@types) {
688             # first param is undef because we cannot get the appclass
689 666         3595 my $class = Catalyst::Utils::resolve_namespace(undef, 'Catalyst::DispatchType', $type);
690              
691 666         50215 my ($success, $error) = try_load_class($class);
692 666 50       182678 Catalyst::Exception->throw( message => $error ) if not $success;
693 666         1650 push @{ $self->dispatch_types }, $class->new;
  666         26086  
694              
695 666         157601 push @loaded, $class;
696             }
697              
698 334         1960 return @loaded;
699             }
700              
701             =head2 $self->dispatch_type( $type )
702              
703             Get the DispatchType object of the relevant type, i.e. passing C<$type> of
704             C<Chained> would return a L<Catalyst::DispatchType::Chained> object (assuming
705             of course it's being used.)
706              
707             =cut
708              
709             sub dispatch_type {
710 1     1 1 4 my ($self, $name) = @_;
711              
712             # first param is undef because we cannot get the appclass
713 1         7 $name = Catalyst::Utils::resolve_namespace(undef, 'Catalyst::DispatchType', $name);
714              
715 1         65 for (@{ $self->dispatch_types }) {
  1         39  
716 3 100       20 return $_ if ref($_) eq $name;
717             }
718 0         0 return undef;
719             }
720              
721             sub _check_deprecated_dispatch_type {
722 1158     1158   3810 my ($self, $key, $load_failed) = @_;
723              
724 1158 50       5734 return unless $key =~ /^(Local)?Regexp?/;
725              
726             # TODO: Should these throw an exception rather than just warning?
727 0 0 0       if ($load_failed) {
    0          
728 0           warn( "Attempt to use deprecated $key dispatch type.\n"
729             . " Use Chained methods or install the standalone\n"
730             . " Catalyst::DispatchType::Regex if necessary.\n" );
731             } elsif ( !defined $Catalyst::DispatchType::Regex::VERSION
732             || $Catalyst::DispatchType::Regex::VERSION le '5.90020' ) {
733             # We loaded the old core version of the Regex module this will break
734 0           warn( "The $key DispatchType has been removed from Catalyst core.\n"
735             . " An old version of the core Catalyst::DispatchType::Regex\n"
736             . " has been loaded and will likely fail. Please remove\n"
737             . " $INC{'Catalyst/DispatchType/Regex.pm'}\n"
738             . " and use Chained methods or install the standalone\n"
739             . " Catalyst::DispatchType::Regex if necessary.\n" );
740             }
741             }
742              
743 155     155   1767 use Moose;
  155         629  
  155         1210  
744              
745             # 5.70 backwards compatibility hacks.
746              
747             # Various plugins (e.g. Plugin::Server and Plugin::Authorization::ACL)
748             # need the methods here which *should* be private..
749              
750             # You should be able to use get_actions or get_containers appropriately
751             # instead of relying on these methods which expose implementation details
752             # of the dispatcher..
753             #
754             # IRC backlog included below, please come ask if this doesn't work for you.
755             #
756             # <@t0m> 5.80, the state of. There are things in the dispatcher which have
757             # been deprecated, that we yell at anyone for using, which there isn't
758             # a good alternative for yet..
759             # <@mst> er, get_actions/get_containers provides that doesn't it?
760             # <@mst> DispatchTypes are loaded on demand anyway
761             # <@t0m> I'm thinking of things like _tree which is aliased to 'tree' with
762             # warnings otherwise shit breaks.. We're issuing warnings about the
763             # correct set of things which you shouldn't be calling..
764             # <@mst> right
765             # <@mst> basically, I don't see there's a need for a replacement for anything
766             # <@mst> it was never a good idea to call ->tree
767             # <@mst> nothingmuch was the only one who did AFAIK
768             # <@mst> and he admitted it was a hack ;)
769              
770             # See also t/lib/TestApp/Plugin/AddDispatchTypes.pm
771              
772             # Alias _method_name to method_name, add a before modifier to warn..
773             foreach my $public_method_name (qw/
774             tree
775             registered_dispatch_types
776             method_action_class
777             action_hash
778             container_hash
779             /) {
780             my $private_method_name = '_' . $public_method_name;
781             my $meta = __PACKAGE__->meta; # Calling meta method here fine as we happen at compile time.
782             $meta->add_method($public_method_name, $meta->get_method($private_method_name));
783             {
784             my %package_hash; # Only warn once per method, per package. These are infrequent enough that
785             # I haven't provided a way to disable them, patches welcome.
786             $meta->add_before_method_modifier($public_method_name, sub {
787             my $class = caller(2);
788             chomp($class);
789             $package_hash{$class}++ || do {
790             warn("Class $class is calling the deprecated method\n"
791             . " Catalyst::Dispatcher::$public_method_name,\n"
792             . " this will be removed in Catalyst 5.9\n");
793             };
794             });
795             }
796             }
797             # End 5.70 backwards compatibility hacks.
798              
799             __PACKAGE__->meta->make_immutable;
800              
801             =head2 meta
802              
803             Provided by Moose
804              
805             =head1 AUTHORS
806              
807             Catalyst Contributors, see Catalyst.pm
808              
809             =head1 COPYRIGHT
810              
811             This library is free software. You can redistribute it and/or modify it under
812             the same terms as Perl itself.
813              
814             =cut
815              
816             1;