X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCatalyst.pm;h=25b2c7a317fcfa2b5744b4b4c82706d5f90b2db3;hb=b248fa4a4191cd3eaa13d72e6ec8e64dfef973e0;hp=7310d71be1aecca3bd4e6597b633f84318176b73;hpb=9b0a3e0fc295d2d2b0af184f4ed1d05db41fc2c4;p=catagits%2FCatalyst-Runtime.git
diff --git a/lib/Catalyst.pm b/lib/Catalyst.pm
index 7310d71..25b2c7a 100644
--- a/lib/Catalyst.pm
+++ b/lib/Catalyst.pm
@@ -1,7 +1,7 @@
package Catalyst;
use strict;
-use base 'Catalyst::Base';
+use base 'Catalyst::Component';
use bytes;
use UNIVERSAL::require;
use Catalyst::Exception;
@@ -10,6 +10,7 @@ use Catalyst::Request;
use Catalyst::Request::Upload;
use Catalyst::Response;
use Catalyst::Utils;
+use Catalyst::Controller;
use File::stat;
use NEXT;
use Text::SimpleTable;
@@ -17,6 +18,8 @@ use Path::Class;
use Time::HiRes qw/gettimeofday tv_interval/;
use URI;
use Scalar::Util qw/weaken/;
+use Tree::Simple qw/use_weak_refs/;
+use Tree::Simple::Visitor::FindByUID;
use attributes;
__PACKAGE__->mk_accessors(
@@ -44,18 +47,18 @@ our $DETACH = "catalyst_detach\n";
require Module::Pluggable::Fast;
# Helper script generation
-our $CATALYST_SCRIPT_GEN = 25;
+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/;
+ engine_class context_class request_class response_class setup_finished/;
__PACKAGE__->dispatcher_class('Catalyst::Dispatcher');
__PACKAGE__->engine_class('Catalyst::Engine::CGI');
__PACKAGE__->request_class('Catalyst::Request');
__PACKAGE__->response_class('Catalyst::Response');
-our $VERSION = '5.62';
+our $VERSION = '5.64';
sub import {
my ( $class, @arguments ) = @_;
@@ -68,7 +71,7 @@ sub import {
unless ( $caller->isa('Catalyst') ) {
no strict 'refs';
- push @{"$caller\::ISA"}, $class;
+ push @{"$caller\::ISA"}, $class, 'Catalyst::Controller';
}
$caller->arguments( [@arguments] );
@@ -242,7 +245,10 @@ in an arrayref. The action will receive the arguments in C<@_> and
C<$c-E Welcome to the wonderful world of Catalyst.
This MVC
framework will make web development something you had
- never expected it to be: Fun, rewarding and quick.
That really depends on what you want to do. We do, however, provide you with a few starting points.
If you want to jump right into web development with Catalyst you might want to check out the documentation.
perldoc Catalyst::Manual::Intro
+perldoc Catalyst::Manual::Tutorial
perldoc Catalyst::Manual
Next it's time to write an actual application. Use the helper scripts to generate controllers, - models and - views, + models, and + views; they can save you a lot of work.
script/${prefix}_create.pl -help
Also, be sure to check out the vast and growing - collection of plugins for Catalyst on CPAN, + collection of plugins for Catalyst on CPAN; you are likely to find what you need there.
@@ -887,17 +930,11 @@ via $c->error. sub execute { my ( $c, $class, $code ) = @_; - $class = $c->components->{$class} || $class; + $class = $c->component($class) || $class; $c->state(0); - my $callsub = - ( caller(0) )[0]->isa('Catalyst::Action') - ? ( caller(2) )[3] - : ( caller(1) )[3]; - - my $action = ''; if ( $c->debug ) { - $action = "$code"; + my $action = "$code"; $action = "/$action" unless $action =~ /\-\>/; $c->counter->{"$code"}++; @@ -909,8 +946,61 @@ sub execute { return $c->state; } - $action = "-> $action" if $callsub =~ /forward$/; + # determine if the call was the result of a forward + # this is done by walking up the call stack and looking for a calling + # sub of Catalyst::forward before the eval + my $callsub = q{}; + for my $index ( 1 .. 10 ) { + last + if ( ( caller($index) )[0] eq 'Catalyst' + && ( caller($index) )[3] eq '(eval)' ); + + if ( ( caller($index) )[3] =~ /forward$/ ) { + $callsub = ( caller($index) )[3]; + $action = "-> $action"; + last; + } + } + + my $node = Tree::Simple->new( + { + action => $action, + elapsed => undef, # to be filled in later + } + ); + $node->setUID( "$code" . $c->counter->{"$code"} ); + + unless ( ( $code->name =~ /^_.*/ ) + && ( !$c->config->{show_internal_actions} ) ) + { + + # is this a root-level call or a forwarded call? + if ( $callsub =~ /forward$/ ) { + + # forward, locate the caller + if ( my $parent = $c->stack->[-1] ) { + my $visitor = Tree::Simple::Visitor::FindByUID->new; + $visitor->searchForUID( + "$parent" . $c->counter->{"$parent"} ); + $c->{stats}->accept($visitor); + if ( my $result = $visitor->getResult ) { + $result->addChild($node); + } + } + else { + + # forward with no caller may come from a plugin + $c->{stats}->addChild($node); + } + } + else { + + # root-level call + $c->{stats}->addChild($node); + } + } } + push( @{ $c->stack }, $code ); my $elapsed = 0; my $start = 0; @@ -922,14 +1012,28 @@ sub execute { unless ( ( $code->name =~ /^_.*/ ) && ( !$c->config->{show_internal_actions} ) ) { - push @{ $c->{stats} }, [ $action, sprintf( '%fs', $elapsed ) ]; + + # FindByUID uses an internal die, so we save the existing error + my $error = $@; + + # locate the node in the tree and update the elapsed time + my $visitor = Tree::Simple::Visitor::FindByUID->new; + $visitor->searchForUID( "$code" . $c->counter->{"$code"} ); + $c->{stats}->accept($visitor); + if ( my $result = $visitor->getResult ) { + my $value = $result->getNodeValue; + $value->{elapsed} = sprintf( '%fs', $elapsed ); + $result->setNodeValue($value); + } + + # restore error + $@ = $error || undef; } } my $last = ${ $c->stack }[-1]; pop( @{ $c->stack } ); if ( my $error = $@ ) { - if ( $error eq $DETACH ) { die $DETACH if $c->depth > 1 } else { unless ( ref $error ) { @@ -1099,11 +1203,11 @@ sub handle_request { # Always expect worst case! my $status = -1; eval { - my @stats = (); + my $stats = ( $class->debug ) ? Tree::Simple->new: q{}; my $handler = sub { my $c = $class->prepare(@arguments); - $c->{stats} = \@stats; + $c->{stats} = $stats; $c->dispatch; return $c->finalize; }; @@ -1117,7 +1221,15 @@ sub handle_request { ( $elapsed == 0 ? '??' : ( 1 / $elapsed ) ); my $t = Text::SimpleTable->new( [ 64, 'Action' ], [ 9, 'Time' ] ); - for my $stat (@stats) { $t->row( $stat->[0], $stat->[1] ) } + $stats->traverse( + sub { + my $action = shift; + my $stat = $action->getNodeValue; + $t->row( ( q{ } x $action->getDepth ) . $stat->{action}, + $stat->{elapsed} || '??' ); + } + ); + $class->log->info( "Request took ${elapsed}s ($av/s)\n" . $t->draw ); } @@ -1451,7 +1563,7 @@ sub setup_components { my $callback = sub { my ( $component, $context ) = @_; - unless ( $component->isa('Catalyst::Component') ) { + unless ( $component->can('COMPONENT') ) { return $component; } @@ -1460,7 +1572,7 @@ sub setup_components { my $instance; - eval { $instance = $component->new( $context, $config ); }; + eval { $instance = $component->COMPONENT( $context, $config ); }; if ( my $error = $@ ) { @@ -1471,7 +1583,7 @@ sub setup_components { } Catalyst::Exception->throw( message => -qq/Couldn't instantiate component "$component", "new() didn't return a object"/ +qq/Couldn't instantiate component "$component", "COMPONENT() didn't return a object"/ ) unless ref $instance; return $instance; @@ -1576,19 +1688,19 @@ sub setup_engine { if ( $software eq 'mod_perl' ) { if ( !$engine ) { - + if ( $version >= 1.99922 ) { $engine = 'Catalyst::Engine::Apache2::MP20'; } - + elsif ( $version >= 1.9901 ) { $engine = 'Catalyst::Engine::Apache2::MP19'; } - + elsif ( $version >= 1.24 ) { $engine = 'Catalyst::Engine::Apache::MP13'; } - + else { Catalyst::Exception->throw( message => qq/Unsupported mod_perl version: $ENV{MOD_PERL}/ );