- Refactored get_action into get_action and get_actions
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Dispatcher.pm
index 44e5afe..cd56ad4 100644 (file)
@@ -20,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
@@ -52,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 {
@@ -134,7 +88,7 @@ sub forward {
 
     my $arguments = ( ref( $_[-1] ) eq 'ARRAY' ) ? pop(@_) : $c->req->args;
 
-    my $results = [];
+    my $result;
 
     my $command_copy = $command;
 
@@ -146,14 +100,14 @@ sub forward {
     }
 
     unless ( $command_copy =~ /\// ) {
-        $results = $c->get_action( $command_copy, '/' );
+        $result = $c->get_action( $command_copy, '/' );
     }
     else {
         my @extra_args;
       DESCEND: while ( $command_copy =~ s/^(.*)\/(\w+)$/$1/ ) {
             my $tail = $2;
-            $results = $c->get_action( $tail, $1 );
-            if ( @{$results} ) {
+            $result = $c->get_action( $tail, $1 );
+            if ( $result ) {
                 $command = $tail;
                 push( @{$arguments}, @extra_args );
                 last DESCEND;
@@ -162,7 +116,7 @@ sub forward {
         }
     }
 
-    unless ( @{$results} ) {
+    unless ( $result ) {
 
         unless ( $c->components->{$command} ) {
             my $error =
@@ -181,11 +135,11 @@ 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] ];
+            $result = $action;
         }
 
         else {
@@ -201,11 +155,7 @@ qq/Couldn't forward to command "$command". Invalid action or component./;
 
     local $c->request->{arguments} = [ @{$arguments} ];
 
-    for my $result ( @{$results} ) {
-        $result->[0]->execute($c);
-        return if scalar @{ $c->error };
-        last unless $c->state;
-    }
+    $result->execute($c);
 
     return $c->state;
 }
@@ -243,37 +193,44 @@ sub prepare_action {
       if ( $c->debug && @args );
 }
 
-=item $self->get_action( $c, $action, $namespace, $inherit )
+=item $self->get_action( $c, $action, $namespace )
 
 =cut
 
 sub get_action {
-    my ( $self, $c, $action, $namespace, $inherit ) = @_;
+    my ( $self, $c, $action, $namespace ) = @_;
     return [] unless $action;
     $namespace ||= '';
-    $inherit   ||= 0;
+    $namespace = '' if $namespace eq '/';
 
     my @match = $self->get_containers($namespace);
 
-    my @results;
-
-    foreach my $child ( $inherit ? @match : $match[-1] ) {
-        my $node = $child->actions;
-        if ( defined $node->{$action} ) {
-            unless ($inherit) {
-                $namespace = '' if $namespace eq '/';
-                my $reverse = $node->{$action}->reverse;
-                my $name    = $namespace
-                  ? $namespace =~ /\/$/
-                  ? "$namespace$action"
-                  : "$namespace/$action"
-                  : $action;
-                last unless $name eq $reverse;
-            }
-            push( @results, [ $node->{$action} ] );
-        }
+    my $node = $match[-1]->actions;    # Only bother looking at the last one
+
+    if ( defined $node->{$action}
+        && ( $node->{$action}->namespace eq $namespace ) )
+    {
+        return $node->{$action};
     }
-    return \@results;
+}
+
+=item $self->get_actions( $c, $action, $namespace )
+
+=cut
+
+sub get_actions {
+    my ( $self, $c, $action, $namespace ) = @_;
+    return [] unless $action;
+    $namespace ||= '';
+    $namespace = '' if $namespace eq '/';
+
+    my @match = $self->get_containers($namespace);
+
+    return
+        map    { $_->{$action} }
+          grep { defined $_->{$action} }    # If it exists in the container
+          map  { $_->actions }              # Get action hash for container
+          @match
 }
 
 =item $self->get_containers( $namespace )
@@ -318,15 +275,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;
 
@@ -357,7 +314,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;
     }
@@ -366,8 +323,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;
@@ -390,7 +347,7 @@ sub set_action {
         }
     }
 
-    my $reverse = $prefix ? "$prefix/$method" : $method;
+    my $reverse = $namespace ? "$namespace/$method" : $method;
 
     my $action = Catalyst::Action->new(
         {
@@ -398,7 +355,7 @@ sub set_action {
             code       => $code,
             reverse    => $reverse,
             namespace  => $namespace,
-            prefix     => $prefix,
+            class      => $class,
             attributes => \%attributes,
         }
     );
@@ -417,7 +374,7 @@ sub set_action {
 =cut
 
 sub setup_actions {
-    my ( $self, $class ) = @_;
+    my ( $self, $c ) = @_;
 
     $self->dispatch_types( [] );
 
@@ -435,7 +392,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');
@@ -445,22 +402,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;
                     }
                 }
@@ -468,11 +425,16 @@ sub setup_actions {
         }
     }
 
-    # Default actions are always last in the chain
-    push @{ $self->dispatch_types }, Catalyst::DispatchType::Index->new;
-    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' );
@@ -487,18 +449,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