Enable hooking parameters into req/res construction. Useful if you are dynamically...
[catagits/Catalyst-Runtime.git] / lib / Catalyst.pm
index 475ba75..b959d7c 100644 (file)
@@ -4,7 +4,7 @@ use Moose;
 use Moose::Meta::Class ();
 extends 'Catalyst::Component';
 use Moose::Util qw/find_meta/;
-use B::Hooks::EndOfScope ();
+use namespace::clean -except => 'meta';
 use Catalyst::Exception;
 use Catalyst::Exception::Detach;
 use Catalyst::Exception::Go;
@@ -33,9 +33,11 @@ use Catalyst::EngineLoader;
 use utf8;
 use Carp qw/croak carp shortmess/;
 use Try::Tiny;
+use Safe::Isa;
 use Plack::Middleware::Conditional;
 use Plack::Middleware::ReverseProxy;
 use Plack::Middleware::IIS6ScriptNameFix;
+use Plack::Middleware::IIS7KeepAliveFix;
 use Plack::Middleware::LighttpdScriptNameFix;
 
 BEGIN { require 5.008003; }
@@ -50,20 +52,30 @@ has request => (
     is => 'rw',
     default => sub {
         my $self = shift;
-        my %p = ( _log => $self->log );
-        $p{_uploadtmp} = $self->_uploadtmp if $self->_has_uploadtmp;
-        $self->request_class->new(\%p);
+        $self->request_class->new($self->_build_request_class_construction_parameters);
     },
     lazy => 1,
 );
+sub _build_request_class_construction_parameters {
+    my $self = shift;
+    my %p = ( _log => $self->log );
+    $p{_uploadtmp} = $self->_uploadtmp if $self->_has_uploadtmp;
+    \%p;
+}
+
 has response => (
     is => 'rw',
     default => sub {
         my $self = shift;
-        $self->response_class->new({ _log => $self->log });
+        $self->response_class->new($self->_build_response_class_construction_parameters);
     },
     lazy => 1,
 );
+sub _build_response_class_construction_parameters {
+    my $self = shift;
+    { _log => $self->log };
+}
+
 has namespace => (is => 'rw');
 
 sub depth { scalar @{ shift->stack || [] }; }
@@ -100,7 +112,7 @@ __PACKAGE__->stats_class('Catalyst::Stats');
 
 # Remember to update this in Catalyst::Runtime as well!
 
-our $VERSION = '5.90009';
+our $VERSION = '5.90016';
 
 sub import {
     my ( $class, @arguments ) = @_;
@@ -135,6 +147,8 @@ sub import {
 
 sub _application { $_[0] }
 
+=encoding UTF-8
+
 =head1 NAME
 
 Catalyst - The Elegant MVC Web Application Framework
@@ -544,13 +558,13 @@ sub _comp_names_search_prefixes {
     # undef for a name will return all
     return keys %eligible if !defined $name;
 
-    my $query  = ref $name ? $name : qr/^$name$/i;
+    my $query  = $name->$_isa('Regexp') ? $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;
+    return if $name->$_isa('Regexp');
 
     # skip regexp fallback if configured
     return
@@ -641,7 +655,7 @@ sub controller {
 
     my $appclass = ref($c) || $c;
     if( $name ) {
-        unless ( ref($name) ) { # Direct component hash lookup to avoid costly regexps
+        unless ( $name->$_isa('Regexp') ) { # 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};
@@ -679,7 +693,7 @@ sub model {
     my ( $c, $name, @args ) = @_;
     my $appclass = ref($c) || $c;
     if( $name ) {
-        unless ( ref($name) ) { # Direct component hash lookup to avoid costly regexps
+        unless ( $name->$_isa('Regexp') ) { # 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};
@@ -738,7 +752,7 @@ sub view {
 
     my $appclass = ref($c) || $c;
     if( $name ) {
-        unless ( ref($name) ) { # Direct component hash lookup to avoid costly regexps
+        unless ( $name->$_isa('Regexp') ) { # Direct component hash lookup to avoid costly regexps
             my $comps = $c->components;
             my $check = $appclass."::View::".$name;
             if( exists $comps->{$check} ) {
@@ -1184,29 +1198,6 @@ EOF
         $class->log->info("$name powered by Catalyst $Catalyst::VERSION");
     }
 
-    # Make sure that the application class becomes immutable at this point,
-    B::Hooks::EndOfScope::on_scope_end {
-        return if $@;
-        my $meta = Class::MOP::get_metaclass_by_name($class);
-        if (
-            $meta->is_immutable
-            && ! { $meta->immutable_options }->{replace_constructor}
-            && (
-                   $class->isa('Class::Accessor::Fast')
-                || $class->isa('Class::Accessor')
-            )
-        ) {
-            warn "You made your application class ($class) immutable, "
-                . "but did not inline the\nconstructor. "
-                . "This will break catalyst, as your app \@ISA "
-                . "Class::Accessor(::Fast)?\nPlease pass "
-                . "(replace_constructor => 1)\nwhen making your class immutable.\n";
-        }
-        $meta->make_immutable(
-            replace_constructor => 1,
-        ) unless $meta->is_immutable;
-    };
-
     if ($class->config->{case_sensitive}) {
         $class->log->warn($class . "->config->{case_sensitive} is set.");
         $class->log->warn("This setting is deprecated and planned to be removed in Catalyst 5.81.");
@@ -1289,7 +1280,7 @@ path, use C<< $c->uri_for_action >> instead.
 sub uri_for {
     my ( $c, $path, @args ) = @_;
 
-    if (blessed($path) && $path->isa('Catalyst::Controller')) {
+    if ( $path->$_isa('Catalyst::Controller') ) {
         $path = $path->path_prefix;
         $path =~ s{/+\z}{};
         $path .= '/';
@@ -1306,7 +1297,7 @@ sub uri_for {
         $arg =~ s/([^$URI::uric])/$URI::Escape::escapes{$1}/go;
     }
 
-    if ( blessed($path) ) { # action object
+    if ( $path->$_isa('Catalyst::Action') ) { # action object
         s|/|%2F|g for @args;
         my $captures = [ map { s|/|%2F|g; $_; }
                         ( scalar @args && ref $args[0] eq 'ARRAY'
@@ -1811,7 +1802,7 @@ sub finalize {
             $c->finalize_error;
         }
 
-        $c->finalize_headers;
+        $c->finalize_headers unless $c->response->finalized_headers;
 
         # HEAD request
         if ( $c->request->method eq 'HEAD' ) {
@@ -1921,7 +1912,7 @@ EOF
 
     $c->finalize_cookies;
 
-    $c->engine->finalize_headers( $c, @_ );
+    $c->response->finalize_headers();
 
     # Done
     $response->finalized_headers(1);
@@ -2023,6 +2014,8 @@ sub prepare {
     my $uploadtmp = $class->config->{uploadtmp};
     my $c = $class->context_class->new({ $uploadtmp ? (_uploadtmp => $uploadtmp) : ()});
 
+    $c->response->_context($c);
+
     #surely this is not the most efficient way to do things...
     $c->stats($class->stats_class->new)->enable($c->use_stats);
     if ( $c->debug || $c->config->{enable_catalyst_header} ) {
@@ -2446,11 +2439,35 @@ Starts the engine.
 
 sub run {
   my $app = shift;
+  $app->_make_immutable_if_needed;
   $app->engine_loader->needs_psgi_engine_compat_hack ?
     $app->engine->run($app, @_) :
       $app->engine->run( $app, $app->_finalized_psgi_app, @_ );
 }
 
+sub _make_immutable_if_needed {
+    my $class = shift;
+    my $meta = Class::MOP::get_metaclass_by_name($class);
+    my $isa_ca = $class->isa('Class::Accessor::Fast') || $class->isa('Class::Accessor');
+    if (
+        $meta->is_immutable
+        && ! { $meta->immutable_options }->{replace_constructor}
+        && $isa_ca
+    ) {
+        warn("You made your application class ($class) immutable, "
+            . "but did not inline the\nconstructor. "
+            . "This will break catalyst, as your app \@ISA "
+            . "Class::Accessor(::Fast)?\nPlease pass "
+            . "(replace_constructor => 1)\nwhen making your class immutable.\n");
+    }
+    unless ($meta->is_immutable) {
+        # XXX - FIXME warning here as you should make your app immutable yourself.
+        $meta->make_immutable(
+            replace_constructor => 1,
+        );
+    }
+}
+
 =head2 $c->set_action( $action, $code, $namespace, $attrs )
 
 Sets an action in a given namespace.
@@ -2790,6 +2807,16 @@ sub apply_default_middlewares {
     # IIS versions
     $psgi_app = Plack::Middleware::IIS6ScriptNameFix->wrap($psgi_app);
 
+    # And another IIS issue, this time with IIS7.
+    $psgi_app = Plack::Middleware::Conditional->wrap(
+        $psgi_app,
+        builder => sub { Plack::Middleware::IIS7KeepAliveFix->wrap($_[0]) },
+        condition => sub {
+            my ($env) = @_;
+            return $env->{SERVER_SOFTWARE} && $env->{SERVER_SOFTWARE} =~ m!IIS/7\.[0-9]!;
+        },
+    );
+
     return $psgi_app;
 }
 
@@ -2928,11 +2955,16 @@ the plugin name does not begin with C<Catalyst::Plugin::>.
         Class::MOP::load_class( $plugin );
         $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) {
+        my $plugin_meta = Moose::Meta::Class->create($plugin);
+        if (!$plugin_meta->has_method('new')
+            && ( $plugin->isa('Class::Accessor::Fast') || $plugin->isa('Class::Accessor') ) ) {
+            $plugin_meta->add_method('new', Moose::Object->meta->get_method('new'))
+        }
+        if (!$instant && !$proto->_plugins->{$plugin}) {
             my $meta = Class::MOP::get_metaclass_by_name($class);
             $meta->superclasses($plugin, $meta->superclasses);
         }
+        $proto->_plugins->{$plugin} = 1;
         return $class;
     }