X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Runtime.git;a=blobdiff_plain;f=lib%2FCatalyst.pm;h=8ed0016da6e339a40b24a0e0990703a459303c3a;hp=6da13290677779902335bf9cc4d963302415b4e6;hb=0ba80bce27a56d366c8d44c254332dd83f9ba0f9;hpb=5513038d01b39b9a30d2c55e8ec85895bbe90f10 diff --git a/lib/Catalyst.pm b/lib/Catalyst.pm index 6da1329..8ed0016 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; @@ -46,7 +47,7 @@ our $DETACH = "catalyst_detach\n"; require Module::Pluggable::Fast; # Helper script generation -our $CATALYST_SCRIPT_GEN = 25; +our $CATALYST_SCRIPT_GEN = 26; __PACKAGE__->mk_classdata($_) for qw/components arguments dispatcher engine log dispatcher_class @@ -57,7 +58,7 @@ __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 ) = @_; @@ -70,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] ); @@ -244,7 +245,10 @@ in an arrayref. The action will receive the arguments in C<@_> and C<$c-Ereq-Eargs>. Upon returning from the function, C<$c-Ereq-Eargs> will be restored to the previous values. - $c->forward('/foo'); +Any data Ced from the action forwarded to, will be returned by the +call to forward. + + my $foodata = $c->forward('/foo'); $c->forward('index'); $c->forward(qw/MyApp::Model::CDBI::Foo do_stuff/); $c->forward('MyApp::View::TT'); @@ -366,13 +370,23 @@ sub component { if ( exists $c->components->{$try} ) { - return $c->components->{$try}; + my $comp = $c->components->{$try}; + if ( eval { $comp->can('ACCEPT_CONTEXT'); } ) { + return $comp->ACCEPT_CONTEXT($c); + } + else { return $comp } } } foreach my $component ( keys %{ $c->components } ) { - - return $c->components->{$component} if $component =~ /$name/i; + my $comp; + $comp = $c->components->{$component} if $component =~ /$name/i; + if ($comp) { + if ( ref $comp && $comp->can('ACCEPT_CONTEXT') ) { + return $comp->ACCEPT_CONTEXT($c); + } + else { return $comp } + } } } @@ -431,7 +445,7 @@ sub view { Returns or takes a hashref containing the application's configuration. - __PACKAGE__->config({ db => 'dsn:SQLite:foo.db' }); + __PACKAGE__->config( { db => 'dsn:SQLite:foo.db' } ); =head2 $c->debug @@ -453,10 +467,16 @@ L. =head2 $c->log -Returns the logging object instance. Unless it is already set, Catalyst -sets this up with a L object. To use your own log class: +Returns the logging object instance. Unless it is already set, Catalyst sets +this up with a L object. To use your own log class, set the +logger with the C<< __PACKAGE__->log >> method prior to calling +C<< __PACKAGE__->setup >>. + + __PACKAGE__->log( MyLogger->new ); + __PACKAGE__->setup; + +And later: - $c->log( MyLogger->new ); $c->log->info( 'Now logging with my own logger!' ); Your log class should implement the methods described in the @@ -561,11 +581,12 @@ sub setup { } } + $class->setup_home( delete $flags->{home} ); + $class->setup_log( delete $flags->{log} ); $class->setup_plugins( delete $flags->{plugins} ); $class->setup_dispatcher( delete $flags->{dispatcher} ); $class->setup_engine( delete $flags->{engine} ); - $class->setup_home( delete $flags->{home} ); for my $flag ( sort keys %{$flags} ) { @@ -594,9 +615,9 @@ EOF { no strict 'refs'; - @plugins = - map { $_ . ' ' . ( $_->VERSION || '' ) } - grep { /^Catalyst::Plugin/ } @{"$class\::ISA"}; + @plugins = + map { $_ . ' ' . ( $_->VERSION || '' ) } + grep { /^Catalyst::Plugin/ } @{"$class\::ISA"}; } if (@plugins) { @@ -793,6 +814,7 @@ sub welcome_message {

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

What to do next?

Next it's time to write an actual application. Use the @@ -889,18 +911,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"}++; @@ -912,42 +927,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 - } ); + 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( + $visitor->searchForUID( "$parent" . $c->counter->{"$parent"} ); - $c->{stats}->accept( $visitor ); + $c->{stats}->accept($visitor); if ( my $result = $visitor->getResult ) { - $result->addChild( $node ); + $result->addChild($node); } } else { + # forward with no caller may come from a plugin - $c->{stats}->addChild( $node ); + $c->{stats}->addChild($node); } } else { + # root-level call - $c->{stats}->addChild( $node ); + $c->{stats}->addChild($node); } } } - + push( @{ $c->stack }, $code ); my $elapsed = 0; my $start = 0; @@ -959,19 +993,20 @@ sub execute { unless ( ( $code->name =~ /^_.*/ ) && ( !$c->config->{show_internal_actions} ) ) { + # 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 ); + $c->{stats}->accept($visitor); if ( my $result = $visitor->getResult ) { my $value = $result->getNodeValue; $value->{elapsed} = sprintf( '%fs', $elapsed ); - $result->setNodeValue( $value ); + $result->setNodeValue($value); } - + # restore error $@ = $error || undef; } @@ -1149,7 +1184,7 @@ sub handle_request { # Always expect worst case! my $status = -1; eval { - my $stats = ( $class->debug ) ? Tree::Simple->new : q{}; + my $stats = ( $class->debug ) ? Tree::Simple->new: q{}; my $handler = sub { my $c = $class->prepare(@arguments); @@ -1166,16 +1201,16 @@ sub handle_request { my $av = sprintf '%.3f', ( $elapsed == 0 ? '??' : ( 1 / $elapsed ) ); my $t = Text::SimpleTable->new( [ 64, 'Action' ], [ 9, 'Time' ] ); - - $stats->traverse( sub { - my $action = shift; - my $stat = $action->getNodeValue; - $t->row( - ( q{ } x $action->getDepth ) . $stat->{action}, - $stat->{elapsed} || '??' - ); - } ); - + + $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 ); } @@ -1509,7 +1544,7 @@ sub setup_components { my $callback = sub { my ( $component, $context ) = @_; - unless ( $component->isa('Catalyst::Component') ) { + unless ( $component->can('COMPONENT') ) { return $component; } @@ -1518,7 +1553,7 @@ sub setup_components { my $instance; - eval { $instance = $component->new( $context, $config ); }; + eval { $instance = $component->COMPONENT( $context, $config ); }; if ( my $error = $@ ) { @@ -1529,7 +1564,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; @@ -1634,19 +1669,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}/ );