X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCatalyst.pm;h=60d8a3c76e39191d8eef87d4677e5d4895f1d6ca;hb=56cf18648867ed69585864babff6956b3b630cb7;hp=04a8ad443e1c2ad863384790340a6ae1167f4eb6;hpb=081ea9220deb31273cc4e778d6debdb96256beda;p=catagits%2FCatalyst-Runtime.git diff --git a/lib/Catalyst.pm b/lib/Catalyst.pm index 04a8ad4..60d8a3c 100644 --- a/lib/Catalyst.pm +++ b/lib/Catalyst.pm @@ -14,6 +14,7 @@ use Catalyst::Request::Upload; use Catalyst::Response; use Catalyst::Utils; use Catalyst::Controller; +use Data::OptList; use Devel::InnerPackage (); use File::stat; use Module::Pluggable::Object (); @@ -66,7 +67,7 @@ our $GO = Catalyst::Exception::Go->new; #I imagine that very few of these really need to be class variables. if any. #maybe we should just make them attributes with a default? __PACKAGE__->mk_classdata($_) - for qw/components arguments dispatcher engine log dispatcher_class + for qw/container components arguments dispatcher engine log dispatcher_class engine_class context_class request_class response_class stats_class setup_finished/; @@ -78,7 +79,7 @@ __PACKAGE__->stats_class('Catalyst::Stats'); # Remember to update this in Catalyst::Runtime as well! -our $VERSION = '5.80022'; +our $VERSION = '5.80032'; sub import { my ( $class, @arguments ) = @_; @@ -99,7 +100,12 @@ sub import { $meta->superclasses(grep { $_ ne 'Moose::Object' } $meta->superclasses); unless( $meta->has_method('meta') ){ - $meta->add_method(meta => sub { Moose::Meta::Class->initialize("${caller}") } ); + if ($Moose::VERSION >= 1.15) { + $meta->_add_meta_method('meta'); + } + else { + $meta->add_method(meta => sub { Moose::Meta::Class->initialize("${caller}") } ); + } } $caller->arguments( [@arguments] ); @@ -280,14 +286,15 @@ Specifies a comma-delimited list of log levels. =head2 -Stats -Enables statistics collection and reporting. You can also force this setting -from the system environment with CATALYST_STATS or _STATS. The -environment settings override the application, with _STATS having the -highest priority. +Enables statistics collection and reporting. + + use Catalyst qw/-Stats=1/; -e.g. +You can also force this setting from the system environment with CATALYST_STATS +or _STATS. The environment settings override the application, with +_STATS having the highest priority. - use Catalyst qw/-Stats=1/ +Stats are also enabled if L<< debugging |/"-Debug" >> is enabled. =head1 METHODS @@ -363,6 +370,8 @@ or stash it like so: and access it from the stash. +Keep in mind that the C method used is that of the caller action. So a C<$c-Edetach> inside a forwarded action would run the C method from the original action requested. + =cut sub forward { my $c = shift; no warnings 'recursion'; $c->dispatcher->forward( $c, @_ ) } @@ -426,6 +435,10 @@ with localized C<< $c->action >> and C<< $c->namespace >>. Like C, C escapes the processing of the current request chain on completion, and does not return to its caller. +@arguments are arguments to the final destination of $action. @captures are +arguments to the intermediate steps, if any, on the way to the final sub of +$action. + =cut sub go { my $c = shift; $c->dispatcher->go( $c, @_ ) } @@ -523,98 +536,6 @@ sub clear_errors { $c->error(0); } -sub _comp_search_prefixes { - my $c = shift; - return map $c->components->{ $_ }, $c->_comp_names_search_prefixes(@_); -} - -# search components given a name and some prefixes -sub _comp_names_search_prefixes { - my ( $c, $name, @prefixes ) = @_; - my $appclass = ref $c || $c; - my $filter = "^${appclass}::(" . join( '|', @prefixes ) . ')::'; - $filter = qr/$filter/; # Compile regex now rather than once per loop - - # map the original component name to the sub part that we will search against - my %eligible = map { my $n = $_; $n =~ s{^$appclass\::[^:]+::}{}; $_ => $n; } - grep { /$filter/ } keys %{ $c->components }; - - # undef for a name will return all - return keys %eligible if !defined $name; - - my $query = ref $name ? $name : qr/^$name$/i; - my @result = grep { $eligible{$_} =~ m{$query} } keys %eligible; - - return @result if @result; - - # if we were given a regexp to search against, we're done. - return if ref $name; - - # skip regexp fallback if configured - return - if $appclass->config->{disable_component_resolution_regex_fallback}; - - # regexp fallback - $query = qr/$name/i; - @result = grep { $eligible{ $_ } =~ m{$query} } keys %eligible; - - # no results? try against full names - if( !@result ) { - @result = grep { m{$query} } keys %eligible; - } - - # don't warn if we didn't find any results, it just might not exist - if( @result ) { - # Disgusting hack to work out correct method name - my $warn_for = lc $prefixes[0]; - my $msg = "Used regexp fallback for \$c->${warn_for}('${name}'), which found '" . - (join '", "', @result) . "'. Relying on regexp fallback behavior for " . - "component resolution is unreliable and unsafe."; - my $short = $result[0]; - # remove the component namespace prefix - $short =~ s/.*?(Model|Controller|View):://; - my $shortmess = Carp::shortmess(''); - if ($shortmess =~ m#Catalyst/Plugin#) { - $msg .= " You probably need to set '$short' instead of '${name}' in this " . - "plugin's config"; - } elsif ($shortmess =~ m#Catalyst/lib/(View|Controller)#) { - $msg .= " You probably need to set '$short' instead of '${name}' in this " . - "component's config"; - } else { - $msg .= " You probably meant \$c->${warn_for}('$short') instead of \$c->${warn_for}('${name}'), " . - "but if you really wanted to search, pass in a regexp as the argument " . - "like so: \$c->${warn_for}(qr/${name}/)"; - } - $c->log->warn( "${msg}$shortmess" ); - } - - return @result; -} - -# Find possible names for a prefix -sub _comp_names { - my ( $c, @prefixes ) = @_; - my $appclass = ref $c || $c; - - my $filter = "^${appclass}::(" . join( '|', @prefixes ) . ')::'; - - my @names = map { s{$filter}{}; $_; } - $c->_comp_names_search_prefixes( undef, @prefixes ); - - return @names; -} - -# Filter a component before returning by calling ACCEPT_CONTEXT if available -sub _filter_component { - my ( $c, $comp, @args ) = @_; - - if ( eval { $comp->can('ACCEPT_CONTEXT'); } ) { - return $comp->ACCEPT_CONTEXT( $c, @args ); - } - - return $comp; -} - =head2 COMPONENT ACCESSORS =head2 $c->controller($name) @@ -636,17 +557,15 @@ If you want to search for controllers, pass in a regexp as the argument. sub controller { my ( $c, $name, @args ) = @_; + my $container = $c->container->get_sub_container('controller'); + unshift @args, $c; - my $appclass = ref($c) || $c; if( $name ) { - unless ( ref($name) ) { # Direct component hash lookup to avoid costly regexps - my $comps = $c->components; - my $check = $appclass."::Controller::".$name; - return $c->_filter_component( $comps->{$check}, @args ) if exists $comps->{$check}; - } - my @result = $c->_comp_search_prefixes( $name, qw/Controller C/ ); - return map { $c->_filter_component( $_, @args ) } @result if ref $name; - return $c->_filter_component( $result[ 0 ], @args ); + # Direct component hash lookup to avoid costly regexps + return $container->get_component($name, \@args) + if $container->has_service($name) && !ref $name; + + return $container->get_component_regexp( $c, $name, \@args ); } return $c->component( $c->action->class ); @@ -676,15 +595,15 @@ If you want to search for models, pass in a regexp as the argument. sub model { my ( $c, $name, @args ) = @_; my $appclass = ref($c) || $c; + my $container = $c->container->get_sub_container('model'); + unshift @args, $c; + if( $name ) { - unless ( ref($name) ) { # Direct component hash lookup to avoid costly regexps - my $comps = $c->components; - my $check = $appclass."::Model::".$name; - return $c->_filter_component( $comps->{$check}, @args ) if exists $comps->{$check}; - } - my @result = $c->_comp_search_prefixes( $name, qw/Model M/ ); - return map { $c->_filter_component( $_, @args ) } @result if ref $name; - return $c->_filter_component( $result[ 0 ], @args ); + # Direct component hash lookup to avoid costly regexps + return $container->get_component($name, \@args) + if $container->has_service($name) && !ref $name; + + return $container->get_component_regexp( $c, $name, \@args ); } if (ref $c) { @@ -696,7 +615,8 @@ sub model { return $c->model( $appclass->config->{default_model} ) if $appclass->config->{default_model}; - my( $comp, $rest ) = $c->_comp_search_prefixes( undef, qw/Model M/); +# FIXME: will this still be mantained? + my( $comp, $rest ) = $container->get_service_list; if( $rest ) { $c->log->warn( Carp::shortmess('Calling $c->model() will return a random model unless you specify one of:') ); @@ -706,7 +626,7 @@ sub model { $c->log->warn( 'NB: in version 5.81, the "random" behavior will not work at all.' ); } - return $c->_filter_component( $comp ); + return $container->get_component( $comp, \@args ); } @@ -733,17 +653,18 @@ If you want to search for views, pass in a regexp as the argument. sub view { my ( $c, $name, @args ) = @_; - my $appclass = ref($c) || $c; + my $container = $c->container->get_sub_container('view'); + unshift @args, $c; + if( $name ) { - unless ( ref($name) ) { # Direct component hash lookup to avoid costly regexps - my $comps = $c->components; - my $check = $appclass."::View::".$name; - return $c->_filter_component( $comps->{$check}, @args ) if exists $comps->{$check}; - } - my @result = $c->_comp_search_prefixes( $name, qw/View V/ ); - return map { $c->_filter_component( $_, @args ) } @result if ref $name; - return $c->_filter_component( $result[ 0 ], @args ); + # Direct component hash lookup to avoid costly regexps + return $container->get_component($name, \@args) + if !ref $name && $container->has_service($name); + + $c->log->warn( "Attempted to use view '$name', but does not exist" ); + + return $container->get_component_regexp( $c, $name, \@args ); } if (ref $c) { @@ -755,7 +676,7 @@ sub view { return $c->view( $appclass->config->{default_view} ) if $appclass->config->{default_view}; - my( $comp, $rest ) = $c->_comp_search_prefixes( undef, qw/View V/); + my( $comp, $rest ) = $container->get_service_list; if( $rest ) { $c->log->warn( 'Calling $c->view() will return a random view unless you specify one of:' ); @@ -765,7 +686,7 @@ sub view { $c->log->warn( 'NB: in version 5.81, the "random" behavior will not work at all.' ); } - return $c->_filter_component( $comp ); + return $container->get_component( $comp, \@args ); } =head2 $c->controllers @@ -776,7 +697,7 @@ Returns the available names which can be passed to $c->controller sub controllers { my ( $c ) = @_; - return $c->_comp_names(qw/Controller C/); + return $c->container->get_sub_container('controller')->get_service_list; } =head2 $c->models @@ -787,7 +708,7 @@ Returns the available names which can be passed to $c->model sub models { my ( $c ) = @_; - return $c->_comp_names(qw/Model M/); + return $c->container->get_sub_container('model')->get_service_list; } @@ -799,7 +720,7 @@ Returns the available names which can be passed to $c->view sub views { my ( $c ) = @_; - return $c->_comp_names(qw/View V/); + return $c->container->get_sub_container('view')->get_service_list; } =head2 $c->comp($name) @@ -823,37 +744,43 @@ disable_component_resolution_regex_fallback to a true value. =cut sub component { - my ( $c, $name, @args ) = @_; + my ( $c, $component, @args ) = @_; + unshift @args, $c; - if( $name ) { - my $comps = $c->components; + if ( $component ) { + my ($type, $name) = _get_component_type_name($component); - if( !ref $name ) { - # is it the exact name? - return $c->_filter_component( $comps->{ $name }, @args ) - if exists $comps->{ $name }; + if ($type && $c->container->has_sub_container($type)) { + my $container = $c->container->get_sub_container($type); - # perhaps we just omitted "MyApp"? - my $composed = ( ref $c || $c ) . "::${name}"; - return $c->_filter_component( $comps->{ $composed }, @args ) - if exists $comps->{ $composed }; + if( !ref $component && $container->has_service($name) ) { + return $container->get_component( $name, \@args ); + } - # search all of the models, views and controllers - my( $comp ) = $c->_comp_search_prefixes( $name, qw/Model M Controller C View V/ ); - return $c->_filter_component( $comp, @args ) if $comp; + return $container->get_component_regexp( $c, $name, \@args ); } + return + if $c->config->{disable_component_resolution_regex_fallback} && !ref $component; + # This is here so $c->comp( '::M::' ) works - my $query = ref $name ? $name : qr{$name}i; + my $query = ref $component ? $component : qr{$component}i; + + for my $subcontainer_name (qw/model view controller/) { + my $subcontainer = $c->container->get_sub_container($subcontainer_name); + my @components = $subcontainer->get_service_list; + my @result = grep { m{$query} } @components; - my @result = grep { m{$query} } keys %{ $c->components }; - return map { $c->_filter_component( $_, @args ) } @result if ref $name; + if (@result) { + return map { $subcontainer->get_component( $_, \@args ) } @result + if ref $component; - if( $result[ 0 ] ) { - $c->log->warn( Carp::shortmess(qq(Found results for "${name}" using regexp fallback)) ); - $c->log->warn( 'Relying on the regexp fallback behavior for component resolution' ); - $c->log->warn( 'is unreliable and unsafe. You have been warned' ); - return $c->_filter_component( $result[ 0 ], @args ); + $c->log->warn( Carp::shortmess(qq(Found results for "${component}" using regexp fallback)) ); + $c->log->warn( 'Relying on the regexp fallback behavior for component resolution' ); + $c->log->warn( 'is unreliable and unsafe. You have been warned' ); + + return $subcontainer->get_component( $result[0], \@args ); + } } # I would expect to return an empty list here, but that breaks back-compat @@ -890,7 +817,7 @@ component is constructed. For example: MyApp->config({ 'Model::Foo' => { bar => 'baz', overrides => 'me' } }); - MyApp::Model::Foo->config({ quux => 'frob', 'overrides => 'this' }); + MyApp::Model::Foo->config({ quux => 'frob', overrides => 'this' }); will mean that C receives the following data when constructed: @@ -901,6 +828,27 @@ constructed: overrides => 'me', }); +It's common practice to use a Moose attribute +on the receiving component to access the config value. + + package MyApp::Model::Foo; + + use Moose; + + # this attr will receive 'baz' at construction time + has 'bar' => ( + is => 'rw', + isa => 'Str', + ); + +You can then get the value 'baz' by calling $c->model('Foo')->bar +(or $self->bar inside code in the model). + +B you MUST NOT call C<< $self->config >> or C<< __PACKAGE__->config >> +as a way of reading config within your code, as this B give you the +correctly merged config back. You B take the config values supplied to +the constructor and use those instead. + =cut around config => sub { @@ -1070,6 +1018,7 @@ sub setup { } } + $class->setup_config(); $class->setup_home( delete $flags->{home} ); $class->setup_log( delete $flags->{log} ); @@ -1202,7 +1151,7 @@ EOF A hook to attach modifiers to. This method does not do anything except set the C accessor. -Applying method modifiers to the C method doesn't work, because of quirky thingsdone for plugin setup. +Applying method modifiers to the C method doesn't work, because of quirky things done for plugin setup. Example: @@ -1225,7 +1174,9 @@ sub setup_finalize { Constructs an absolute L object based on the application root, the provided path, and the additional arguments and query parameters provided. -When used as a string, provides a textual URI. +When used as a string, provides a textual URI. If you need more flexibility +than this (i.e. the option to provide relative URIs etc.) see +L. If no arguments are provided, the URI for the current action is returned. To return the current action and also provide @args, use @@ -1279,13 +1230,11 @@ sub uri_for { carp "uri_for called with undef argument" if grep { ! defined $_ } @args; foreach my $arg (@args) { utf8::encode($arg) if utf8::is_utf8($arg); - } - s/([^$URI::uric])/$URI::Escape::escapes{$1}/go for @args; - if (blessed $path) { # Action object only. - s|/|%2F|g for @args; + $arg =~ s/([^$URI::uric])/$URI::Escape::escapes{$1}/go; } if ( blessed($path) ) { # action object + s|/|%2F|g for @args; my $captures = [ map { s|/|%2F|g; $_; } ( scalar @args && ref $args[0] eq 'ARRAY' ? @{ shift(@args) } @@ -1306,8 +1255,6 @@ sub uri_for { $path = '/' if $path eq ''; } - undef($path) if (defined $path && $path eq ''); - unshift(@args, $path); unless (defined $path && $path =~ s!^/!!) { # in-place strip @@ -1552,6 +1499,36 @@ These methods are not meant to be used by end users. Returns a hash of components. +=cut + +around components => sub { + my $orig = shift; + my $class = shift; + my $comps = shift; + + return $class->$orig if ( !$comps ); + +# FIXME: should this ugly kludge exist? + $class->setup_config unless defined $class->container; + +# FIXME: should there be a warning here, not to use this accessor to create the components? + my $components = {}; + + my $containers; + $containers->{$_} = $class->container->get_sub_container($_) for qw(model view controller); + + for my $component ( keys %$comps ) { + $components->{ $component } = $comps->{$component}; + + my ($type, $name) = _get_component_type_name($component); + +# FIXME: shouldn't the service name be $name? + $containers->{$type}->add_service(Catalyst::BlockInjection->new( name => $name, block => sub { return $class->setup_component($component) } )); + } + + return $class->$orig($components); +}; + =head2 $c->context_class Returns or sets the context class. @@ -1623,7 +1600,9 @@ sub execute { push( @{ $c->stack }, $code ); no warnings 'recursion'; - eval { $c->state( $code->execute( $class, $c, @{ $c->req->args } ) || 0 ) }; + # N.B. This used to be combined, but I have seen $c get clobbered if so, and + # I have no idea how, ergo $ret (which appears to fix the issue) + eval { my $ret = $code->execute( $class, $c, @{ $c->req->args } ) || 0; $c->state( $ret ) }; $c->_stats_finish_execute( $stats_info ) if $c->use_stats and $stats_info; @@ -1645,8 +1624,8 @@ sub execute { $error = qq/Caught exception in $class->$name "$error"/; } $c->error($error); - $c->state(0); } + $c->state(0); } return $c->state; } @@ -1686,7 +1665,7 @@ sub _stats_start_execute { my $parent = $c->stack->[-1]; # forward, locate the caller - if ( exists $c->counter->{"$parent"} ) { + if ( defined $parent && exists $c->counter->{"$parent"} ) { $c->stats->profile( begin => $action, parent => "$parent" . $c->counter->{"$parent"}, @@ -1820,10 +1799,10 @@ sub finalize_headers { } # Content-Length - if ( $response->body && !$response->content_length ) { + if ( defined $response->body && length $response->body && !$response->content_length ) { # get the length from a filehandle - if ( blessed( $response->body ) && $response->body->can('read') ) + if ( blessed( $response->body ) && $response->body->can('read') || ref( $response->body ) eq 'GLOB' ) { my $stat = stat $response->body; if ( $stat && $stat->size > 0 ) { @@ -2135,7 +2114,7 @@ sub log_request { $c->log->debug("Query keywords are: $keywords"); } - $c->log_request_parameters( query => $request->query_parameters, body => $request->body_parameters ); + $c->log_request_parameters( query => $request->query_parameters, $request->_has_body ? (body => $request->body_parameters) : () ); $c->log_request_uploads($request); } @@ -2325,11 +2304,11 @@ sub prepare_write { my $c = shift; $c->engine->prepare_write( $c, @_ ) } =head2 $c->request_class -Returns or sets the request class. +Returns or sets the request class. Defaults to L. =head2 $c->response_class -Returns or sets the response class. +Returns or sets the response class. Defaults to L. =head2 $c->read( [$maxlength] ) @@ -2372,6 +2351,34 @@ Sets up actions for a component. sub setup_actions { my $c = shift; $c->dispatcher->setup_actions( $c, @_ ) } +=head2 $c->setup_config + +=cut + +sub setup_config { + my $class = shift; + + my %args = %{ $class->config || {} }; + + my @container_classes = ( "${class}::Container", 'Catalyst::Container'); + unshift @container_classes, delete $args{container_class} if exists $args{container_class}; + + my $container_class = Class::MOP::load_first_existing_class(@container_classes); + + my $container = $container_class->new( %args, name => "$class" ); + $class->container($container); + + my $config = $container->resolve(service => 'config'); + $class->config($config); + $class->finalize_config; # back-compat +} + +=head $c->finalize_config + +=cut + +sub finalize_config { } + =head2 $c->setup_components This method is called internally to set up the application's components. @@ -2392,8 +2399,7 @@ sub setup_components { my $config = $class->config->{ setup_components }; - my @comps = sort { length $a <=> length $b } - $class->locate_components($config); + my @comps = $class->locate_components($config); my %comps = map { $_ => 1 } @comps; my $deprecatedcatalyst_component_names = grep { /::[CMV]::/ } @comps; @@ -2408,25 +2414,52 @@ sub setup_components { # we know M::P::O found a file on disk so this is safe Catalyst::Utils::ensure_class_loaded( $component, { ignore_loaded => 1 } ); - - # Needs to be done as soon as the component is loaded, as loading a sub-component - # (next time round the loop) can cause us to get the wrong metaclass.. - $class->_controller_init_base_classes($component); } + my $containers; + $containers->{$_} = $class->container->get_sub_container($_) for qw(model view controller); + for my $component (@comps) { my $instance = $class->components->{ $component } = $class->setup_component($component); + if ( my ($type, $name) = _get_component_type_name($component) ) { + $containers->{$type}->add_service(Catalyst::BlockInjection->new( name => $name, block => sub { return $instance } )); + } my @expanded_components = $instance->can('expand_modules') ? $instance->expand_modules( $component, $config ) : $class->expand_component_module( $component, $config ); for my $component (@expanded_components) { next if $comps{$component}; - $class->_controller_init_base_classes($component); # Also cover inner packages + + $deprecatedcatalyst_component_names = grep { /::[CMV]::/ } @expanded_components; + $class->log->warn(qq{Your application is using the deprecated ::[MVC]:: type naming scheme.\n}. + qq{Please switch your class names to ::Model::, ::View:: and ::Controller: as appropriate.\n} + ) if $deprecatedcatalyst_component_names; + + if (my ($type, $name) = _get_component_type_name($component)) { + $containers->{$type}->add_service(Catalyst::BlockInjection->new( name => $name, block => sub { return $class->setup_component($component) } )); + } + $class->components->{ $component } = $class->setup_component($component); } } } +sub _get_component_type_name { + my $component = shift; + my @parts = split /::/, $component; + + while (my $type = shift @parts) { + return ('controller', join '::', @parts) + if $type =~ /^(c|controller)$/i; + + return ('model', join '::', @parts) + if $type =~ /^(m|model)$/i; + + return ('view', join '::', @parts) + if $type =~ /^(v|view)$/i; + } +} + =head2 $c->locate_components( $setup_component_config ) This method is meant to provide a list of component modules that should be @@ -2453,7 +2486,8 @@ sub locate_components { %$config ); - my @comps = $locator->plugins; + # XXX think about ditching this sort entirely + my @comps = sort { length $a <=> length $b } $locator->plugins; return @comps; } @@ -2474,19 +2508,6 @@ sub expand_component_module { =cut -# FIXME - Ugly, ugly hack to ensure the we force initialize non-moose base classes -# nearest to Catalyst::Controller first, no matter what order stuff happens -# to be loaded. There are TODO tests in Moose for this, see -# f2391d17574eff81d911b97be15ea51080500003 -sub _controller_init_base_classes { - my ($app_class, $component) = @_; - return unless $component->isa('Catalyst::Controller'); - foreach my $class ( reverse @{ mro::get_linear_isa($component) } ) { - Moose::Meta::Class->initialize( $class ) - unless find_meta($class); - } -} - sub setup_component { my( $class, $component ) = @_; @@ -2509,8 +2530,7 @@ sub setup_component { message => qq/Couldn't instantiate component "$component", "$error"/ ); } - - unless (blessed $instance) { + elsif (!blessed $instance) { my $metaclass = Moose::Util::find_meta($component); my $method_meta = $metaclass->find_method_by_name('COMPONENT'); my $component_method_from = $method_meta->associated_metaclass->name; @@ -2520,6 +2540,7 @@ sub setup_component { qq/Couldn't instantiate component "$component", COMPONENT() method (from $component_method_from) didn't return an object-like value (value was $value)./ ); } + return $instance; } @@ -2783,7 +2804,7 @@ the plugin name does not begin with C. my $class = ref $proto || $proto; Class::MOP::load_class( $plugin ); - $class->log->warn( "$plugin inherits from 'Catalyst::Component' - this is decated and will not work in 5.81" ) + $class->log->warn( "$plugin inherits from 'Catalyst::Component' - this is deprecated and will not work in 5.81" ) if $plugin->isa( 'Catalyst::Component' ); $proto->_plugins->{$plugin} = 1; unless ($instant) { @@ -2797,22 +2818,29 @@ the plugin name does not begin with C. my ( $class, $plugins ) = @_; $class->_plugins( {} ) unless $class->_plugins; - $plugins ||= []; + $plugins = Data::OptList::mkopt($plugins || []); - my @plugins = Catalyst::Utils::resolve_namespace($class . '::Plugin', 'Catalyst::Plugin', @$plugins); + my @plugins = map { + [ Catalyst::Utils::resolve_namespace( + $class . '::Plugin', + 'Catalyst::Plugin', $_->[0] + ), + $_->[1], + ] + } @{ $plugins }; for my $plugin ( reverse @plugins ) { - Class::MOP::load_class($plugin); - my $meta = find_meta($plugin); + Class::MOP::load_class($plugin->[0], $plugin->[1]); + my $meta = find_meta($plugin->[0]); next if $meta && $meta->isa('Moose::Meta::Role'); - $class->_register_plugin($plugin); + $class->_register_plugin($plugin->[0]); } my @roles = - map { $_->name } - grep { $_ && blessed($_) && $_->isa('Moose::Meta::Role') } - map { find_meta($_) } + map { $_->[0]->name, $_->[1] } + grep { blessed($_->[0]) && $_->[0]->isa('Moose::Meta::Role') } + map { [find_meta($_->[0]), $_->[1]] } @plugins; Moose::Util::apply_all_roles( @@ -2826,15 +2854,24 @@ the plugin name does not begin with C. Returns an arrayref of the internal execution stack (actions that are currently executing). +=head2 $c->stats + +Returns the current timing statistics object. By default Catalyst uses +L, but can be set otherwise with +L<< stats_class|/"$c->stats_class" >>. + +Even if L<< -Stats|/"-Stats" >> is not enabled, the stats object is still +available. By enabling it with C< $c->stats->enabled(1) >, it can be used to +profile explicitly, although MyApp.pm still won't profile nor output anything +by itself. + =head2 $c->stats_class -Returns or sets the stats (timing statistics) class. +Returns or sets the stats (timing statistics) class. L is used by default. =head2 $c->use_stats -Returns 1 when stats collection is enabled. Stats collection is enabled -when the -Stats options is set, debug is on or when the _STATS -environment variable is set. +Returns 1 when L<< stats collection|/"-Stats" >> is enabled. Note that this is a static method, not an accessor and should be overridden by declaring C in your MyApp.pm, not by calling C<< $c->use_stats(1) >>. @@ -2932,6 +2969,12 @@ to be shown in hit debug tables in the test server. =item * +C - Controlls if the C or C environment +variable should be used for determining the request path. See L +for more information. + +=item * + C - See L. =back @@ -3161,6 +3204,8 @@ random: Roland Lammel Robert Sedlacek C<< >> +SpiceMan: Marcel Montes + sky: Arthur Bergman szbalint: Balint Szilakszi @@ -3175,8 +3220,18 @@ Will Hawes C willert: Sebastian Willert +wreis: Wallace Reis + Yuval Kogman, C +rainboxx: Matthias Dietrich, C + +dd070: Dhaval Dhanani + +=head1 COPYRIGHT + +Copyright (c) 2005, the above named PROJECT FOUNDER and CONTRIBUTORS. + =head1 LICENSE This library is free software. You can redistribute it and/or modify it under