moved version to ::Runtime, modified Makefile.PL
[catagits/Catalyst-Runtime.git] / lib / Catalyst.pm
index 4e13edb..0d05976 100644 (file)
@@ -10,7 +10,10 @@ use Catalyst::Request::Upload;
 use Catalyst::Response;
 use Catalyst::Utils;
 use Catalyst::Controller;
+use Catalyst::Runtime;
+use Devel::InnerPackage ();
 use File::stat;
+use Module::Pluggable::Object;
 use NEXT;
 use Text::SimpleTable;
 use Path::Class::Dir;
@@ -48,11 +51,6 @@ our $START     = time;
 our $RECURSION = 1000;
 our $DETACH    = "catalyst_detach\n";
 
-require Module::Pluggable::Fast;
-
-# Helper script generation
-our $CATALYST_SCRIPT_GEN = 27;
-
 __PACKAGE__->mk_classdata($_)
   for qw/components arguments dispatcher engine log dispatcher_class
   engine_class context_class request_class response_class setup_finished/;
@@ -62,7 +60,7 @@ __PACKAGE__->engine_class('Catalyst::Engine::CGI');
 __PACKAGE__->request_class('Catalyst::Request');
 __PACKAGE__->response_class('Catalyst::Response');
 
-our $VERSION = '5.6902';
+our $VERSION = $Catalyst::Runtime::VERSION;
 
 sub import {
     my ( $class, @arguments ) = @_;
@@ -779,8 +777,9 @@ sub setup {
         }
     }
 
-    $class->log->warn(
-        <<"EOF") if ( $ENV{CATALYST_SCRIPT_GEN} && ( $ENV{CATALYST_SCRIPT_GEN} < $Catalyst::CATALYST_SCRIPT_GEN ) );
+    eval { require Catalyst::Devel; };
+    if( !$@ && $ENV{CATALYST_SCRIPT_GEN} && ( $ENV{CATALYST_SCRIPT_GEN} < $Catalyst::Devel::CATALYST_SCRIPT_GEN ) ) {
+        $class->log->warn(<<"EOF");
 You are running an old script!
 
   Please update by running (this will overwrite existing files):
@@ -789,7 +788,8 @@ You are running an old script!
   or (this will not overwrite existing files):
     catalyst.pl -scripts $class
 EOF
-
+    }
+    
     if ( $class->debug ) {
 
         my @plugins = ();
@@ -866,6 +866,11 @@ end of the path.  If the last argument to uri_for is a hash reference,
 it is assumed to contain GET parameter key/value pairs, which will be
 appended to the URI in standard fashion.
 
+Instead of $path, you can also optionally pass a $action object which will
+be resolved to a path using $c->dispatcher->uri_for_action; if the first
+element of @args is an arrayref it is treated as a list of captures to be
+passed to uri_for_action.
+
 =cut
 
 sub uri_for {
@@ -876,6 +881,14 @@ sub uri_for {
     $basepath .= '/';
     my $namespace = $c->namespace || '';
 
+    if ( Scalar::Util::blessed($path) ) { # action object
+        my $captures = ( scalar @args && ref $args[0] eq 'ARRAY'
+                         ? shift(@args)
+                         : [] );
+        $path = $c->dispatcher->uri_for_action($path, $captures);
+        return undef unless defined($path);
+    }
+
     # massage namespace, empty if absolute path
     $namespace =~ s/^\/// if $namespace;
     $namespace .= '/' if $namespace;
@@ -1789,64 +1802,73 @@ sub setup_actions { my $c = shift; $c->dispatcher->setup_actions( $c, @_ ) }
 
 =head2 $c->setup_components
 
-Sets up components.
+Sets up components. Specify a C<setup_components> config option to pass additional options
+directly to L<Module::Pluggable>. To add additional search paths, specify a key named
+C<search_extra> as an array reference. Items in the array beginning with C<::> will have the
+application class name prepended to them.
 
 =cut
 
 sub setup_components {
     my $class = shift;
 
-    my $callback = sub {
-        my ( $component, $context ) = @_;
-
-        unless ( $component->can('COMPONENT') ) {
-            return $component;
+    my @paths   = qw( ::Controller ::C ::Model ::M ::View ::V );
+    my $config  = $class->config->{ setup_components };
+    my $extra   = delete $config->{ search_extra } || [];
+    
+    push @paths, @$extra;
+        
+    my $locator = Module::Pluggable::Object->new(
+        search_path => [ map { s/^(?=::)/$class/; $_; } @paths ],
+        %$config
+    );
+    
+    for my $component ( sort { length $a <=> length $b } $locator->plugins ) {
+        Catalyst::Utils::ensure_class_loaded( $component );
+
+        my $module  = $class->setup_component( $component );
+        my %modules = (
+            $component => $module,
+            map {
+                $_ => $class->setup_component( $_ )
+            } Devel::InnerPackage::list_packages( $component )
+        );
+        
+        for my $key ( keys %modules ) {
+            $class->components->{ $key } = $modules{ $key };
         }
+    }
+}
 
-        my $suffix = Catalyst::Utils::class2classsuffix($component);
-        my $config = $class->config->{$suffix} || {};
-
-        my $instance;
-
-        eval { $instance = $component->COMPONENT( $context, $config ); };
+=head2 $c->setup_component
 
-        if ( my $error = $@ ) {
+=cut
 
-            chomp $error;
+sub setup_component {
+    my( $class, $component ) = @_;
 
-            Catalyst::Exception->throw( message =>
-                  qq/Couldn't instantiate component "$component", "$error"/ );
-        }
+    unless ( $component->can( 'COMPONENT' ) ) {
+        return $component;
+    }
 
-        Catalyst::Exception->throw( message =>
-qq/Couldn't instantiate component "$component", "COMPONENT() didn't return a object"/
-          )
-          unless ref $instance;
-        return $instance;
-    };
+    my $suffix = Catalyst::Utils::class2classsuffix( $component );
+    my $config = $class->config->{ $suffix } || {};
 
-    eval "package $class;\n" . q!Module::Pluggable::Fast->import(
-            name   => '_catalyst_components',
-            search => [
-                "$class\::Controller", "$class\::C",
-                "$class\::Model",      "$class\::M",
-                "$class\::View",       "$class\::V"
-            ],
-            callback => $callback
-        );
-    !;
+    my $instance = eval { $component->COMPONENT( $class, $config ); };
 
     if ( my $error = $@ ) {
-
         chomp $error;
-
         Catalyst::Exception->throw(
-            message => qq/Couldn't load components "$error"/ );
+            message => qq/Couldn't instantiate component "$component", "$error"/
+        );
     }
 
-    for my $component ( $class->_catalyst_components($class) ) {
-        $class->components->{ ref $component || $component } = $component;
-    }
+    Catalyst::Exception->throw(
+        message =>
+        qq/Couldn't instantiate component "$component", "COMPONENT() didn't return an object-like value"/
+    ) unless eval { $instance->can( 'can' ) };
+
+    return $instance;
 }
 
 =head2 $c->setup_dispatcher