Fixed some bugs and improved logs
[catagits/Catalyst-Runtime.git] / lib / Catalyst.pm
index 64318c9..8d59a4d 100644 (file)
@@ -11,16 +11,19 @@ use Catalyst::Request::Upload;
 use Catalyst::Response;
 use Catalyst::Utils;
 use NEXT;
-use Text::ASCIITable;
+use Text::SimpleTable;
 use Path::Class;
 use Time::HiRes qw/gettimeofday tv_interval/;
 use URI;
 use Scalar::Util qw/weaken/;
+use attributes;
 
 __PACKAGE__->mk_accessors(
     qw/counter depth request response state action namespace/
 );
 
+attributes->import( __PACKAGE__, \&namespace, 'lvalue' );
+
 # Laziness++
 *comp = \&component;
 *req  = \&request;
@@ -38,12 +41,12 @@ our $DETACH    = "catalyst_detach\n";
 require Module::Pluggable::Fast;
 
 # Helper script generation
-our $CATALYST_SCRIPT_GEN = 9;
+our $CATALYST_SCRIPT_GEN = 10;
 
 __PACKAGE__->mk_classdata($_)
   for qw/components arguments dispatcher engine log/;
 
-our $VERSION = '5.49_02';
+our $VERSION = '5.49_03';
 
 sub import {
     my ( $class, @arguments ) = @_;
@@ -219,6 +222,23 @@ sub component {
 
 Returns a hashref containing your applications settings.
 
+=cut
+
+=item $c->controller($name)
+
+Get a L<Catalyst::Controller> instance by name.
+
+    $c->controller('Foo')->do_stuff;
+
+=cut
+
+sub controller {
+    my ( $c, $name ) = @_;
+    my $controller = $c->comp("Controller::$name");
+    return $controller if $controller;
+    return $c->comp("C::$name");
+}
+
 =item debug
 
 Overload to enable debug messages.
@@ -257,6 +277,21 @@ from the function.
 
 sub forward { my $c = shift; $c->dispatcher->forward( $c, @_ ) }
 
+=item $c->model($name)
+
+Get a L<Catalyst::Model> instance by name.
+
+    $c->model('Foo')->do_stuff;
+
+=cut
+
+sub model {
+    my ( $c, $name ) = @_;
+    my $model = $c->comp("Model::$name");
+    return $model if $model;
+    return $c->comp("M::$name");
+}
+
 =item $c->namespace
 
 Accessor to the namespace of the current action
@@ -348,12 +383,8 @@ sub setup {
         }
 
         if (@plugins) {
-            my $t = Text::ASCIITable->new;
-            $t->setOptions( 'hide_HeadRow',  1 );
-            $t->setOptions( 'hide_HeadLine', 1 );
-            $t->setCols('Class');
-            $t->setColWidth( 'Class', 75, 1 );
-            $t->addRow($_) for @plugins;
+            my $t = Text::SimpleTable->new(76);
+            $t->row($_) for @plugins;
             $class->log->debug( "Loaded plugins:\n" . $t->draw );
         }
 
@@ -384,14 +415,13 @@ sub setup {
     $class->setup_components;
 
     if ( $class->debug ) {
-        my $t = Text::ASCIITable->new;
-        $t->setOptions( 'hide_HeadRow',  1 );
-        $t->setOptions( 'hide_HeadLine', 1 );
-        $t->setCols('Class');
-        $t->setColWidth( 'Class', 75, 1 );
-        $t->addRow($_) for sort keys %{ $class->components };
+        my $t = Text::SimpleTable->new( [ 37, 'Class' ], [ 36, 'Type' ] );
+        for my $comp ( sort keys %{ $class->components } ) {
+            my $type = ref $class->components->{$comp} ? 'instance' : 'class';
+            $t->row( $comp, $type );
+        }
         $class->log->debug( "Loaded components:\n" . $t->draw )
-          if ( @{ $t->{tbl_rows} } );
+          if ( keys %{ $class->components } );
     }
 
     # Add our self to components, since we are also a component
@@ -565,6 +595,21 @@ sub stash {
     return $c->{stash};
 }
 
+=item $c->view($name)
+
+Get a L<Catalyst::View> instance by name.
+
+    $c->view('Foo')->do_stuff;
+
+=cut
+
+sub view {
+    my ( $c, $name ) = @_;
+    my $view = $c->comp("View::$name");
+    return $view if $view;
+    return $c->comp("V::$name");
+}
+
 =item $c->welcome_message
 
 Returns the Catalyst welcome HTML page.
@@ -576,20 +621,24 @@ sub welcome_message {
     my $name   = $c->config->{name};
     my $logo   = $c->uri_for('/static/images/catalyst_logo.png');
     my $prefix = Catalyst::Utils::appprefix( ref $c );
+    $c->response->content_type('text/html; charset=utf-8');
     return <<"EOF";
-<html>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
     <head>
+       <meta http-equiv="Content-Language" content="en" />
+       <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
         <title>$name on Catalyst $VERSION</title>
         <style type="text/css">
             body {
-                text-align: center;
-                padding-left: 50%;
                 color: #000;
                 background-color: #eee;
             }
             div#content {
                 width: 640px;
-                margin-left: -320px;
+                margin-left: auto;
+                margin-right: auto;
                 margin-top: 10px;
                 margin-bottom: 10px;
                 text-align: left;
@@ -642,7 +691,8 @@ sub welcome_message {
                 float: right;
                 margin-left: 10px;
             }
-            b#appname {
+            span#appname {
+                font-weight: bold;
                 font-size: 1.6em;
             }
         </style>
@@ -650,12 +700,12 @@ sub welcome_message {
     <body>
         <div id="content">
             <div id="topbar">
-                <h1><b id="appname">$name</b> on <a href="http://catalyst.perl.org">Catalyst</a>
+                <h1><span id="appname">$name</span> on <a href="http://catalyst.perl.org">Catalyst</a>
                     $VERSION</h1>
              </div>
              <div id="answers">
                  <p>
-                 <img src="$logo"/>
+                 <img src="$logo" alt="Catalyst Logo" />
                  </p>
                  <p>Welcome to the wonderful world of Catalyst.
                     This <a href="http://en.wikipedia.org/wiki/MVC">MVC</a>
@@ -670,13 +720,13 @@ sub welcome_message {
 perldoc <a href="http://cpansearch.perl.org/dist/Catalyst/lib/Catalyst/Manual.pod">Catalyst::Manual</a></code></pre>
                  <h2>What to do next?</h2>
                  <p>Next it's time to write an actual application. Use the
-                    helper scripts to generate <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AController%3A%3A&mode=all">controllers</a>,
-                    <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AModel%3A%3A&mode=all">models</a> and
-                    <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AView%3A%3A&mode=all">views</a>,
+                    helper scripts to generate <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AController%3A%3A&amp;mode=all">controllers</a>,
+                    <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AModel%3A%3A&amp;mode=all">models</a> and
+                    <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AView%3A%3A&amp;mode=all">views</a>,
                     they can save you a lot of work.</p>
                     <pre><code>script/${prefix}_create.pl -help</code></pre>
                     <p>Also, be sure to check out the vast and growing
-                    collection of <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3APlugin%3A%3A&mode=all">plugins for Catalyst on CPAN</a>,
+                    collection of <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3APlugin%3A%3A&amp;mode=all">plugins for Catalyst on CPAN</a>,
                     you are likely to find what you need there.
                     </p>
 
@@ -818,8 +868,6 @@ sub execute {
                 chomp $error;
                 $error = qq/Caught exception "$error"/;
             }
-
-            $c->log->error($error);
             $c->error($error);
             $c->state(0);
         }
@@ -836,6 +884,10 @@ Finalize request.
 sub finalize {
     my $c = shift;
 
+    for my $error ( @{ $c->error } ) {
+        $c->log->error($error);
+    }
+
     $c->finalize_uploads;
 
     # Error
@@ -942,7 +994,7 @@ Get an action in a given namespace.
 
 =cut
 
-sub get_action { my $c = shift; $c->dispatcher->get_action( $c, @_ ) }
+sub get_action { my $c = shift; $c->dispatcher->get_action(@_) }
 
 =item $c->get_actions( $action, $namespace )
 
@@ -979,12 +1031,9 @@ sub handle_request {
             $elapsed = sprintf '%f', $elapsed;
             my $av = sprintf '%.3f',
               ( $elapsed == 0 ? '??' : ( 1 / $elapsed ) );
-            my $t = Text::ASCIITable->new;
-            $t->setCols( 'Action', 'Time' );
-            $t->setColWidth( 'Action', 64, 1 );
-            $t->setColWidth( 'Time',   9,  1 );
+            my $t = Text::SimpleTable->new( [ 64, 'Action' ], [ 9, 'Time' ] );
 
-            for my $stat (@stats) { $t->addRow( $stat->[0], $stat->[1] ) }
+            for my $stat (@stats) { $t->row( $stat->[0], $stat->[1] ) }
             $class->log->info(
                 "Request took ${elapsed}s ($av/s)\n" . $t->draw );
         }
@@ -1102,15 +1151,11 @@ sub prepare_body {
     $c->prepare_uploads;
 
     if ( $c->debug && keys %{ $c->req->body_parameters } ) {
-        my $t = Text::ASCIITable->new;
-        $t->setCols( 'Key', 'Value' );
-        $t->setColWidth( 'Key',   37, 1 );
-        $t->setColWidth( 'Value', 36, 1 );
-        $t->alignCol( 'Value', 'right' );
+        my $t = Text::SimpleTable->new( [ 37, 'Key' ], [ 36, 'Value' ] );
         for my $key ( sort keys %{ $c->req->body_parameters } ) {
             my $param = $c->req->body_parameters->{$key};
             my $value = defined($param) ? $param : '';
-            $t->addRow( $key,
+            $t->row( $key,
                 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
         }
         $c->log->debug( "Body Parameters are:\n" . $t->draw );
@@ -1198,15 +1243,11 @@ sub prepare_query_parameters {
     $c->engine->prepare_query_parameters( $c, @_ );
 
     if ( $c->debug && keys %{ $c->request->query_parameters } ) {
-        my $t = Text::ASCIITable->new;
-        $t->setCols( 'Key', 'Value' );
-        $t->setColWidth( 'Key',   37, 1 );
-        $t->setColWidth( 'Value', 36, 1 );
-        $t->alignCol( 'Value', 'right' );
+        my $t = Text::SimpleTable->new( [ 37, 'Key' ], [ 36, 'Value' ] );
         for my $key ( sort keys %{ $c->req->query_parameters } ) {
             my $param = $c->req->query_parameters->{$key};
             my $value = defined($param) ? $param : '';
-            $t->addRow( $key,
+            $t->row( $key,
                 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
         }
         $c->log->debug( "Query Parameters are:\n" . $t->draw );
@@ -1241,17 +1282,16 @@ sub prepare_uploads {
     $c->engine->prepare_uploads( $c, @_ );
 
     if ( $c->debug && keys %{ $c->request->uploads } ) {
-        my $t = Text::ASCIITable->new;
-        $t->setCols( 'Key', 'Filename', 'Type', 'Size' );
-        $t->setColWidth( 'Key',      12, 1 );
-        $t->setColWidth( 'Filename', 28, 1 );
-        $t->setColWidth( 'Type',     18, 1 );
-        $t->setColWidth( 'Size',     9,  1 );
-        $t->alignCol( 'Size', 'left' );
+        my $t = Text::SimpleTable->new(
+            [ 12, 'Key' ],
+            [ 28, 'Filename' ],
+            [ 18, 'Type' ],
+            [ 9,  'Size' ]
+        );
         for my $key ( sort keys %{ $c->request->uploads } ) {
             my $upload = $c->request->uploads->{$key};
             for my $u ( ref $upload eq 'ARRAY' ? @{$upload} : ($upload) ) {
-                $t->addRow( $key, $u->filename, $u->type, $u->size );
+                $t->row( $key, $u->filename, $u->type, $u->size );
             }
         }
         $c->log->debug( "File Uploads are:\n" . $t->draw );
@@ -1314,11 +1354,11 @@ sub setup_components {
     my $callback = sub {
         my ( $component, $context ) = @_;
 
-        unless ( $component->isa('Catalyst::Base') ) {
+        unless ( $component->isa('Catalyst::Component') ) {
             return $component;
         }
 
-        my $suffix = Catalyst::Utils::class2classsuffix($component);
+        my $suffix = Catalyst::Utils::class2classsuffix($class);
         my $config = $class->config->{$suffix} || {};
 
         my $instance;
@@ -1558,7 +1598,14 @@ sub setup_log {
         $class->log( Catalyst::Log->new );
     }
 
-    if ( $ENV{CATALYST_DEBUG} || $ENV{ uc($class) . '_DEBUG' } || $debug ) {
+    my $app_flag = Catalyst::Utils::class2env($class) . '_DEBUG';
+
+    if (
+          ( defined( $ENV{CATALYST_DEBUG} ) || defined( $ENV{$app_flag} ) )
+        ? ( $ENV{CATALYST_DEBUG} || $ENV{$app_flag} )
+        : $debug
+      )
+    {
         no strict 'refs';
         *{"$class\::debug"} = sub { 1 };
         $class->log->debug('Debug messages enabled');
@@ -1740,6 +1787,8 @@ Arthur Bergman
 
 Autrijus Tang
 
+Brian Cassidy
+
 Christian Hansen
 
 Christopher Hicks
@@ -1774,6 +1823,8 @@ Robert Sedlacek
 
 Sam Vilain
 
+Sascha Kiefer
+
 Tatsuhiko Miyagawa
 
 Ulf Edvinsson