Added $c->config->{show_internal_actions}
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Dispatcher.pm
index 1a1acbd..5def763 100644 (file)
@@ -7,6 +7,7 @@ use Catalyst::Utils;
 use Catalyst::Action;
 use Catalyst::ActionContainer;
 use Catalyst::DispatchType::Default;
+use Catalyst::DispatchType::Index;
 use Text::ASCIITable;
 use Tree::Simple;
 use Tree::Simple::Visitor::FindByPath;
@@ -19,6 +20,9 @@ __PACKAGE__->mk_accessors(qw/tree dispatch_types/);
 # Preload these action types
 our @PRELOAD = qw/Path Regex/;
 
+# Postload these action types
+our @POSTLOAD = qw/Index Default/;
+
 =head1 NAME
 
 Catalyst::Dispatcher - The Catalyst Dispatcher
@@ -51,56 +55,7 @@ sub dispatch {
     my ( $self, $c ) = @_;
 
     if ( $c->action ) {
-
-        my @containers = $self->get_containers( $c->namespace );
-        my %actions;
-        foreach my $name (qw/begin auto end/) {
-
-            # Go down the container list representing each part of the
-            # current namespace inheritance tree, grabbing the actions hash
-            # of the ActionContainer object and looking for actions of the
-            # appropriate name registered to the namespace
-
-            $actions{$name} = [
-                map    { $_->{$name} }
-                  grep { exists $_->{$name} }
-                  map  { $_->actions } @containers
-            ];
-        }
-
-        # Errors break the normal flow and the end action is instantly run
-        my $error = 0;
-
-        # Execute last begin
-        $c->state(1);
-        if ( my $begin = @{ $actions{begin} }[-1] ) {
-            $begin->execute($c);
-            $error++ if scalar @{ $c->error };
-        }
-
-        # Execute the auto chain
-        my $autorun = 0;
-        for my $auto ( @{ $actions{auto} } ) {
-            last if $error;
-            $autorun++;
-            $auto->execute($c);
-            $error++ if scalar @{ $c->error };
-            last unless $c->state;
-        }
-
-        # Execute the action or last default
-        my $mkay = $autorun ? $c->state ? 1 : 0 : 1;
-        if ($mkay) {
-            unless ($error) {
-                $c->action->execute($c);
-                $error++ if scalar @{ $c->error };
-            }
-        }
-
-        # Execute last end
-        if ( my $end = @{ $actions{end} }[-1] ) {
-            $end->execute($c);
-        }
+        $c->forward( join( '/', '', $c->namespace, '_DISPATCH' ) );
     }
 
     else {
@@ -180,8 +135,8 @@ qq/Couldn't forward to command "$command". Invalid action or component./;
                     name      => $method,
                     code      => $code,
                     reverse   => "$class->$method",
+                    class     => $class,
                     namespace => $class,
-                    prefix    => $class,
                 }
             );
             $results = [ [$action] ];
@@ -249,18 +204,32 @@ sub prepare_action {
 sub get_action {
     my ( $self, $c, $action, $namespace, $inherit ) = @_;
     return [] unless $action;
-    $namespace ||= '/';
-    $inherit   ||= 0;
+    $namespace ||= '';
+    $namespace = '' if $namespace eq '/';
+    $inherit ||= 0;
 
     my @match = $self->get_containers($namespace);
 
-    my @results;
+    if ($inherit) {    # Return [ [ $act_obj ], ... ] for valid containers
+        return [
+            map    { [ $_->{$action} ] }        # Make [ $action_obj ]
+              grep { defined $_->{$action} }    # If it exists in the container
+              map  { $_->actions }              # Get action hash for container
+              @match
+        ];
+    }
+    else {
+        my $node = $match[-1]->actions;    # Only bother looking at the last one
 
-    foreach my $child ( $inherit ? @match : $match[-1] ) {
-        my $node = $child->actions;
-        push( @results, [ $node->{$action} ] ) if defined $node->{$action};
+        if ( defined $node->{$action}
+            && ( $node->{$action}->namespace eq $namespace ) )
+        {
+            return [ [ $node->{$action} ] ];
+        }
+        else {
+            return [];
+        }
     }
-    return \@results;
 }
 
 =item $self->get_containers( $namespace )
@@ -305,15 +274,15 @@ sub get_containers {
     return map { $_->getNodeValue } @match;
 }
 
-=item $self->set_action( $c, $action, $code, $namespace, $attrs )
+=item $self->set_action( $c, $action, $code, $class, $attrs )
 
 =cut
 
 sub set_action {
-    my ( $self, $c, $method, $code, $namespace, $attrs ) = @_;
+    my ( $self, $c, $method, $code, $class, $attrs ) = @_;
 
-    my $prefix =
-      Catalyst::Utils::class2prefix( $namespace, $c->config->{case_sensitive} )
+    my $namespace =
+      Catalyst::Utils::class2prefix( $class, $c->config->{case_sensitive} )
       || '';
     my %attributes;
 
@@ -344,7 +313,7 @@ sub set_action {
     if ( $attributes{Private} && ( keys %attributes > 1 ) ) {
         $c->log->debug( 'Bad action definition "'
               . join( ' ', @{$attrs} )
-              . qq/" for "$namespace->$method"/ )
+              . qq/" for "$class->$method"/ )
           if $c->debug;
         return;
     }
@@ -353,8 +322,8 @@ sub set_action {
     my $parent  = $self->tree;
     my $visitor = Tree::Simple::Visitor::FindByPath->new;
 
-    if ($prefix) {
-        for my $part ( split '/', $prefix ) {
+    if ($namespace) {
+        for my $part ( split '/', $namespace ) {
             $visitor->setSearchPath($part);
             $parent->accept($visitor);
             my $child = $visitor->getResult;
@@ -377,7 +346,7 @@ sub set_action {
         }
     }
 
-    my $reverse = $prefix ? "$prefix/$method" : $method;
+    my $reverse = $namespace ? "$namespace/$method" : $method;
 
     my $action = Catalyst::Action->new(
         {
@@ -385,7 +354,7 @@ sub set_action {
             code       => $code,
             reverse    => $reverse,
             namespace  => $namespace,
-            prefix     => $prefix,
+            class      => $class,
             attributes => \%attributes,
         }
     );
@@ -404,7 +373,7 @@ sub set_action {
 =cut
 
 sub setup_actions {
-    my ( $self, $class ) = @_;
+    my ( $self, $c ) = @_;
 
     $self->dispatch_types( [] );
 
@@ -422,7 +391,7 @@ sub setup_actions {
       Catalyst::ActionContainer->new( { part => '/', actions => {} } );
     $self->tree( Tree::Simple->new( $container, Tree::Simple->ROOT ) );
 
-    for my $comp ( keys %{ $class->components } ) {
+    for my $comp ( keys %{ $c->components } ) {
 
         # We only setup components that inherit from Catalyst::Base
         next unless $comp->isa('Catalyst::Base');
@@ -432,22 +401,22 @@ sub setup_actions {
             my $name = '';
             no strict 'refs';
             my @cache = ( $comp, @{"$comp\::ISA"} );
-            my %namespaces;
+            my %classes;
 
-            while ( my $namespace = shift @cache ) {
-                $namespaces{$namespace}++;
-                for my $isa ( @{"$comp\::ISA"} ) {
-                    next if $namespaces{$isa};
+            while ( my $class = shift @cache ) {
+                $classes{$class}++;
+                for my $isa ( @{"$class\::ISA"} ) {
+                    next if $classes{$isa};
                     push @cache, $isa;
-                    $namespaces{$isa}++;
+                    $classes{$isa}++;
                 }
             }
 
-            for my $namespace ( keys %namespaces ) {
-                for my $sym ( values %{ $namespace . '::' } ) {
+            for my $class ( keys %classes ) {
+                for my $sym ( values %{ $class . '::' } ) {
                     if ( *{$sym}{CODE} && *{$sym}{CODE} == $code ) {
                         $name = *{$sym}{NAME};
-                        $class->set_action( $name, $code, $comp, $attrs );
+                        $self->set_action( $c, $name, $code, $comp, $attrs );
                         last;
                     }
                 }
@@ -455,10 +424,16 @@ sub setup_actions {
         }
     }
 
-    # Default actions are always last in the chain
-    push @{ $self->dispatch_types }, Catalyst::DispatchType::Default->new;
+    # Postload action types
+    for my $type (@POSTLOAD) {
+        my $class = "Catalyst::DispatchType::$type";
+        eval "require $class";
+        Catalyst::Exception->throw( message => qq/Couldn't load "$class"/ )
+          if $@;
+        push @{ $self->dispatch_types }, $class->new;
+    }
 
-    return unless $class->debug;
+    return unless $c->debug;
 
     my $privates = Text::ASCIITable->new;
     $privates->setCols( 'Private', 'Class' );
@@ -473,18 +448,21 @@ sub setup_actions {
 
         for my $action ( keys %{$node} ) {
             my $action_obj = $node->{$action};
-            $privates->addRow( "$prefix$action", $action_obj->namespace );
+            next
+              if ( ( $action =~ /^_.*/ )
+                && ( !$c->config->{show_internal_actions} ) );
+            $privates->addRow( "$prefix$action", $action_obj->class );
         }
 
         $walker->( $walker, $_, $prefix ) for $parent->getAllChildren;
     };
 
     $walker->( $walker, $self->tree, '' );
-    $class->log->debug( "Loaded Private actions:\n" . $privates->draw )
+    $c->log->debug( "Loaded Private actions:\n" . $privates->draw )
       if ( @{ $privates->{tbl_rows} } );
 
     # List all public actions
-    $_->list($class) for @{ $self->dispatch_types };
+    $_->list($c) for @{ $self->dispatch_types };
 }
 
 =back