Merge branch 'master' into gsoc_breadboard
André Walker [Fri, 3 Feb 2012 18:22:09 +0000 (16:22 -0200)]
1  2 
lib/Catalyst.pm
t/author/spelling.t

diff --combined lib/Catalyst.pm
@@@ -15,7 -15,8 +15,7 @@@ use Catalyst::Response
  use Catalyst::Utils;
  use Catalyst::Controller;
  use Data::OptList;
 -use Devel::InnerPackage ();
 -use Module::Pluggable::Object ();
 +use File::stat;
  use Text::SimpleTable ();
  use Path::Class::Dir ();
  use Path::Class::File ();
@@@ -45,8 -46,24 +45,24 @@@ has state => (is => 'rw', default => 0)
  has stats => (is => 'rw');
  has action => (is => 'rw');
  has counter => (is => 'rw', default => sub { {} });
- has request => (is => 'rw', default => sub { $_[0]->request_class->new({}) }, required => 1, lazy => 1);
- has response => (is => 'rw', default => sub { $_[0]->response_class->new({}) }, required => 1, lazy => 1);
+ 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);
+     },
+     lazy => 1,
+ );
+ has response => (
+     is => 'rw',
+     default => sub {
+         my $self = shift;
+         $self->response_class->new({ _log => $self->log });
+     },
+     lazy => 1,
+ );
  has namespace => (is => 'rw');
  
  sub depth { scalar @{ shift->stack || [] }; }
@@@ -72,7 -89,7 +88,7 @@@ our $GO        = Catalyst::Exception::G
  #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 arguments dispatcher engine log dispatcher_class
    engine_loader context_class request_class response_class stats_class
    setup_finished _psgi_app loading_psgi_file run_options/;
  
@@@ -96,12 -113,10 +112,12 @@@ sub import 
      return if $caller eq 'main';
  
      my $meta = Moose::Meta::Class->initialize($caller);
 -    unless ( $caller->isa('Catalyst') ) {
 -        my @superclasses = ($meta->superclasses, $class, 'Catalyst::Controller');
 -        $meta->superclasses(@superclasses);
 -    }
 +
 +    unless ( $caller->isa('Catalyst') ) { # XXX - Remove!
 +        my @superclasses = ($meta->superclasses, $class, 'Catalyst::Component'); # XXX - Remove!
 +        $meta->superclasses(@superclasses); # XXX - Remove!
 +    } # XXX - Remove!
 +
      # Avoid possible C3 issues if 'Moose::Object' is already on RHS of MyApp
      $meta->superclasses(grep { $_ ne 'Moose::Object' } $meta->superclasses);
  
      $caller->setup_home;
  }
  
 +sub MODIFY_CODE_ATTRIBUTES {
 +    Catalyst::Exception->throw(
 +        "Catalyst applications (aka MyApp) cannot be controllers anymore. " .
 +        "That has been deprecated and removed. You should create a " .
 +        "controller class called Root.pm, and move relevant code to that class."
 +    );
 +}
 +
 +
  sub _application { $_[0] }
  
  =head1 NAME
@@@ -366,8 -372,12 +382,12 @@@ When called with no arguments it escape
  
  sub detach { my $c = shift; $c->dispatcher->detach( $c, @_ ) }
  
+ =head2 $c->visit( $action [, \@arguments ] )
  =head2 $c->visit( $action [, \@captures, \@arguments ] )
  
+ =head2 $c->visit( $class, $method, [, \@arguments ] )
  =head2 $c->visit( $class, $method, [, \@captures, \@arguments ] )
  
  Almost the same as L<< forward|/"$c->forward( $action [, \@arguments ] )" >>,
@@@ -396,8 -406,12 +416,12 @@@ transfer control to another action as i
  
  sub visit { my $c = shift; $c->dispatcher->visit( $c, @_ ) }
  
+ =head2 $c->go( $action [, \@arguments ] )
  =head2 $c->go( $action [, \@captures, \@arguments ] )
  
+ =head2 $c->go( $class, $method, [, \@arguments ] )
  =head2 $c->go( $class, $method, [, \@captures, \@arguments ] )
  
  The relationship between C<go> and
@@@ -511,6 -525,98 +535,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)
@@@ -530,7 -636,23 +554,7 @@@ If you want to search for controllers, 
  
  =cut
  
 -sub controller {
 -    my ( $c, $name, @args ) = @_;
 -
 -    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 );
 -    }
 -
 -    return $c->component( $c->action->class );
 -}
 +sub controller { shift->_lookup_mvc('controller', @_) }
  
  =head2 $c->model($name)
  
@@@ -553,7 -675,42 +577,7 @@@ If you want to search for models, pass 
  
  =cut
  
 -sub model {
 -    my ( $c, $name, @args ) = @_;
 -    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."::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 );
 -    }
 -
 -    if (ref $c) {
 -        return $c->stash->{current_model_instance}
 -          if $c->stash->{current_model_instance};
 -        return $c->model( $c->stash->{current_model} )
 -          if $c->stash->{current_model};
 -    }
 -    return $c->model( $appclass->config->{default_model} )
 -      if $appclass->config->{default_model};
 -
 -    my( $comp, $rest ) = $c->_comp_search_prefixes( undef, qw/Model M/);
 -
 -    if( $rest ) {
 -        $c->log->warn( Carp::shortmess('Calling $c->model() will return a random model unless you specify one of:') );
 -        $c->log->warn( '* $c->config(default_model => "the name of the default model to use")' );
 -        $c->log->warn( '* $c->stash->{current_model} # the name of the model to use for this request' );
 -        $c->log->warn( '* $c->stash->{current_model_instance} # the instance of the model to use for this request' );
 -        $c->log->warn( 'NB: in version 5.81, the "random" behavior will not work at all.' );
 -    }
 -
 -    return $c->_filter_component( $comp );
 -}
 -
 +sub model { shift->_lookup_mvc('model', @_) }
  
  =head2 $c->view($name)
  
@@@ -576,23 -733,46 +600,23 @@@ If you want to search for views, pass i
  
  =cut
  
 -sub view {
 -    my ( $c, $name, @args ) = @_;
 +sub view { shift->_lookup_mvc('view', @_) }
  
 -    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."::View::".$name;
 -            if( exists $comps->{$check} ) {
 -                return $c->_filter_component( $comps->{$check}, @args );
 -            }
 -            else {
 -                $c->log->warn( "Attempted to use view '$check', but does not exist" );
 -            }
 -        }
 -        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 );
 -    }
 -
 -    if (ref $c) {
 -        return $c->stash->{current_view_instance}
 -          if $c->stash->{current_view_instance};
 -        return $c->view( $c->stash->{current_view} )
 -          if $c->stash->{current_view};
 -    }
 -    return $c->view( $appclass->config->{default_view} )
 -      if $appclass->config->{default_view};
 +sub _lookup_mvc {
 +    my ( $c, $type, $name, @args ) = @_;
  
 -    my( $comp, $rest ) = $c->_comp_search_prefixes( undef, qw/View V/);
 +    if (ref $c && !$name) {
 +        my $current_instance = $c->stash->{"current_${type}_instance"};
 +        return $current_instance
 +            if $current_instance && $type ne 'controller';
  
 -    if( $rest ) {
 -        $c->log->warn( 'Calling $c->view() will return a random view unless you specify one of:' );
 -        $c->log->warn( '* $c->config(default_view => "the name of the default view to use")' );
 -        $c->log->warn( '* $c->stash->{current_view} # the name of the view to use for this request' );
 -        $c->log->warn( '* $c->stash->{current_view_instance} # the instance of the view to use for this request' );
 -        $c->log->warn( 'NB: in version 5.81, the "random" behavior will not work at all.' );
 +        $name = $type eq 'controller'
 +              ? Catalyst::Utils::class2classshortsuffix($c->action->class)
 +              : $c->stash->{"current_${type}"}
 +              ;
      }
  
 -    return $c->_filter_component( $comp );
 +    return $c->container->get_component_from_sub_container($type, $name, $c, @args);
  }
  
  =head2 $c->controllers
@@@ -603,7 -783,7 +627,7 @@@ Returns the available names which can b
  
  sub controllers {
      my ( $c ) = @_;
 -    return $c->_comp_names(qw/Controller C/);
 +    return $c->container->get_sub_container('controller')->get_service_list;
  }
  
  =head2 $c->models
@@@ -614,7 -794,7 +638,7 @@@ Returns the available names which can b
  
  sub models {
      my ( $c ) = @_;
 -    return $c->_comp_names(qw/Model M/);
 +    return $c->container->get_sub_container('model')->get_service_list;
  }
  
  
@@@ -626,7 -806,7 +650,7 @@@ Returns the available names which can b
  
  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)
@@@ -641,50 -821,57 +665,50 @@@ should be used instead
  If C<$name> is a regexp, a list of components matched against the full
  component name will be returned.
  
  =cut
  
  sub component {
 -    my ( $c, $name, @args ) = @_;
 +    my ( $c, $component, @args ) = @_;
  
 -    if( $name ) {
 -        my $comps = $c->components;
 +    unless ($component) {
 +        $c->log->warn('Calling $c->component with no args is deprecated and ');
 +        $c->log->warn('will be removed in a future release.');
 +        $c->log->warn('Use $c->component_list instead.');
 +        return $c->component_list;
 +    }
  
 -        if( !ref $name ) {
 -            # is it the exact name?
 -            return $c->_filter_component( $comps->{ $name }, @args )
 -                       if exists $comps->{ $name };
 +    my @result = $c->container->find_component( $component, $c, @args );
  
 -            # perhaps we just omitted "MyApp"?
 -            my $composed = ( ref $c || $c ) . "::${name}";
 -            return $c->_filter_component( $comps->{ $composed }, @args )
 -                       if exists $comps->{ $composed };
 +    # list context for regexp searches
 +    return @result if ref $component;
  
 -            # 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;
 -        }
 +    # only one component (if it's found) for string searches
 +    return shift @result if @result;
  
 -        return
 -            if $c->config->{disable_component_resolution_regex_fallback};
 +    if (ref $c eq $component) {
 +        $c->log->warn('You are calling $c->comp("MyApp"). This behaviour is');
 +        $c->log->warn('deprecated, and will be removed in a future release.');
 +        return $c;
 +    }
  
 -        # This is here so $c->comp( '::M::' ) works
 -        my $query = ref $name ? $name : qr{$name}i;
 +    $c->log->warn("Looking for '$component', but nothing was found.");
  
 -        my @result = grep { m{$query} } keys %{ $c->components };
 -        return map { $c->_filter_component( $_, @args ) } @result if ref $name;
 +    # I would expect to return an empty list here, but that breaks back-compat
 +    $c->log->warn('Component not found, returning the list of existing');
 +    $c->log->warn('components. This behavior is deprecated and will be');
 +    $c->log->warn('removed in a future release. Use $c->component_list');
 +    $c->log->warn('instead.');
  
 -        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 );
 -        }
 +    return $c->component_list;
 +}
  
 -        # I would expect to return an empty list here, but that breaks back-compat
 -    }
 +=head2 $c->component_list
  
 -    # fallback
 -    return sort keys %{ $c->components };
 -}
 +Returns the sorted list of the component names of the application.
 +
 +=cut
 +
 +sub component_list { sort keys %{ shift->components } }
  
  =head2 CLASS DATA AND HELPER CLASSES
  
@@@ -835,7 -1022,6 +859,7 @@@ sub path_to 
  sub plugin {
      my ( $class, $name, $plugin, @args ) = @_;
  
 +    # See block comment in t/aggregate/unit_core_plugin.t
      # See block comment in t/unit_core_plugin.t
      $class->log->warn(qq/Adding plugin using the ->plugin method is deprecated, and will be removed in a future release/);
  
@@@ -903,7 -1089,6 +927,7 @@@ sub setup 
          }
      }
  
 +    $class->setup_config();
      $class->setup_home( delete $flags->{home} );
  
      $class->setup_log( delete $flags->{log} );
          $class->setup unless $Catalyst::__AM_RESTARTING;
      }
  
 -    # Initialize our data structure
 -    $class->components( {} );
 -
      $class->setup_components;
  
 -    if ( $class->debug ) {
 +    if (
 +        $class->debug and
 +        my $comps = $class->container->get_all_components($class)
 +    ) {
          my $column_width = Catalyst::Utils::term_width() - 8 - 9;
          my $t = Text::SimpleTable->new( [ $column_width, 'Class' ], [ 8, '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 . "\n" )
 -          if ( keys %{ $class->components } );
 -    }
 +        $t->row( $_ => ref($comps->{$_}) ? 'instance' : 'class' ) for keys %$comps;
  
 -    # Add our self to components, since we are also a component
 -    if( $class->isa('Catalyst::Controller') ){
 -      $class->components->{$class} = $class;
 +        $class->log->debug( "Loaded components:\n" . $t->draw . "\n" );
      }
  
      $class->setup_actions;
@@@ -1422,23 -1615,6 +1446,23 @@@ These methods are not meant to be used 
  
  Returns a hash of components.
  
 +=cut
 +
 +sub components {
 +    my ( $class, $comps ) = @_;
 +
 +    # people create components calling this sub directly, before setup
 +    $class->setup_config unless $class->container;
 +
 +    my $container = $class->container;
 +
 +    if ( $comps ) {
 +        $container->add_component( $_ ) for keys %$comps;
 +    }
 +
 +    return $container->get_all_components($class);
 +}
 +
  =head2 $c->context_class
  
  Returns or sets the context class.
@@@ -1831,6 -2007,11 +1855,11 @@@ etc.)
  
  =cut
  
+ has _uploadtmp => (
+     is => 'ro',
+     predicate => '_has_uploadtmp',
+ );
  sub prepare {
      my ( $class, @arguments ) = @_;
  
      # into the application.
      $class->context_class( ref $class || $class ) unless $class->context_class;
  
-     my $c = $class->context_class->new({});
-     # For on-demand data
-     $c->request->_context($c);
-     $c->response->_context($c);
+     my $uploadtmp = $class->config->{uploadtmp};
+     my $c = $class->context_class->new({ $uploadtmp ? (_uploadtmp => $uploadtmp) : ()});
  
      #surely this is not the most efficient way to do things...
      $c->stats($class->stats_class->new)->enable($c->use_stats);
              $c->prepare_request(@arguments);
              $c->prepare_connection;
              $c->prepare_query_parameters;
-             $c->prepare_headers;
-             $c->prepare_cookies;
+             $c->prepare_headers; # Just hooks, no longer needed - they just
+             $c->prepare_cookies; # cause the lazy attribute on req to build
              $c->prepare_path;
  
              # Prepare the body for reading, either by prepare_body
@@@ -1954,24 -2132,28 +1980,28 @@@ Prepares connection
  
  sub prepare_connection {
      my $c = shift;
-     $c->engine->prepare_connection( $c, @_ );
+     # XXX - This is called on the engine (not the request) to maintain
+     #       Engine::PSGI back compat.
+     $c->engine->prepare_connection($c);
  }
  
  =head2 $c->prepare_cookies
  
- Prepares cookies.
+ Prepares cookies by ensuring that the attribute on the request
+ object has been built.
  
  =cut
  
- sub prepare_cookies { my $c = shift; $c->engine->prepare_cookies( $c, @_ ) }
+ sub prepare_cookies { my $c = shift; $c->request->cookies }
  
  =head2 $c->prepare_headers
  
- Prepares headers.
+ Prepares request headers by ensuring that the attribute on the request
+ object has been built.
  
  =cut
  
- sub prepare_headers { my $c = shift; $c->engine->prepare_headers( $c, @_ ) }
+ sub prepare_headers { my $c = shift; $c->request->headers }
  
  =head2 $c->prepare_parameters
  
@@@ -2254,7 -2436,7 +2284,7 @@@ $c->request.  You must handle all body 
  
  =cut
  
- sub read { my $c = shift; return $c->engine->read( $c, @_ ) }
+ sub read { my $c = shift; return $c->request->read( @_ ) }
  
  =head2 $c->run
  
@@@ -2285,67 -2467,137 +2315,67 @@@ Sets up actions for a component
  
  sub setup_actions { my $c = shift; $c->dispatcher->setup_actions( $c, @_ ) }
  
 -=head2 $c->setup_components
 -
 -This method is called internally to set up the application's components.
 -
 -It finds modules by calling the L<locate_components> method, expands them to
 -package names with the L<expand_component_module> method, and then installs
 -each component into the application.
 -
 -The C<setup_components> config option is passed to both of the above methods.
 -
 -Installation of each component is performed by the L<setup_component> method,
 -below.
 +=head2 $c->setup_config
  
  =cut
  
 -sub setup_components {
 +sub setup_config {
      my $class = shift;
  
 -    my $config  = $class->config->{ setup_components };
 -
 -    my @comps = $class->locate_components($config);
 -    my %comps = map { $_ => 1 } @comps;
 -
 -    my $deprecatedcatalyst_component_names = grep { /::[CMV]::/ } @comps;
 -    $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;
 -
 -    for my $component ( @comps ) {
 +    my %args = %{ $class->config || {} };
  
 -        # We pass ignore_loaded here so that overlay files for (e.g.)
 -        # Model::DBI::Schema sub-classes are loaded - if it's in @comps
 -        # we know M::P::O found a file on disk so this is safe
 +    my $container_class;
  
 -        Catalyst::Utils::ensure_class_loaded( $component, { ignore_loaded => 1 } );
 +    if ( exists $args{container_class} ) {
 +        $container_class = delete $args{container_class};
 +        Class::MOP::load_class($container_class);
      }
 -
 -    for my $component (@comps) {
 -        my $instance = $class->components->{ $component } = $class->setup_component($component);
 -        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->components->{ $component } = $class->setup_component($component);
 -        }
 +    else {
 +        $container_class = Class::MOP::load_first_existing_class("${class}::Container", 'Catalyst::IOC::Container');
      }
 -}
  
 -=head2 $c->locate_components( $setup_component_config )
 +    my $container = $container_class->new( %args, application_name => "$class", name => "$class" );
 +    $class->container($container);
  
 -This method is meant to provide a list of component modules that should be
 -setup for the application.  By default, it will use L<Module::Pluggable>.
 +    my $config = $container->resolve( service => 'config' );
 +    $class->config($config);
 +    $class->finalize_config; # back-compat
 +}
  
 -Specify a C<setup_components> config option to pass additional options directly
 -to L<Module::Pluggable>. To add additional search paths, specify a key named
 -C<search_extra> as an array reference. Items in the array beginning with C<::>
 -will have the application class name prepended to them.
 +=head2 $c->finalize_config
  
  =cut
  
 -sub locate_components {
 -    my $class  = shift;
 -    my $config = shift;
 -
 -    my @paths   = qw( ::Controller ::C ::Model ::M ::View ::V );
 -    my $extra   = delete $config->{ search_extra } || [];
 +sub finalize_config { }
  
 -    push @paths, @$extra;
 -
 -    my $locator = Module::Pluggable::Object->new(
 -        search_path => [ map { s/^(?=::)/$class/; $_; } @paths ],
 -        %$config
 -    );
 -
 -    # XXX think about ditching this sort entirely
 -    my @comps = sort { length $a <=> length $b } $locator->plugins;
 +=head2 $c->setup_components
  
 -    return @comps;
 -}
 +This method is called internally to set up the application's components.
  
 -=head2 $c->expand_component_module( $component, $setup_component_config )
 +It finds modules by calling the L<locate_components> method, expands them to
 +package names with the $container->expand_component_module method, and then
 +installs each component into the application.
  
 -Components found by C<locate_components> will be passed to this method, which
 -is expected to return a list of component (package) names to be set up.
 +The C<setup_components> config option is passed to both of the above methods.
  
  =cut
  
 -sub expand_component_module {
 -    my ($class, $module) = @_;
 -    return Devel::InnerPackage::list_packages( $module );
 -}
 +sub setup_components { shift->container->setup_components }
  
 -=head2 $c->setup_component
 +=head2 locate_components
  
  =cut
  
 -sub setup_component {
 -    my( $class, $component ) = @_;
 -
 -    unless ( $component->can( 'COMPONENT' ) ) {
 -        return $component;
 -    }
 -
 -    my $suffix = Catalyst::Utils::class2classsuffix( $component );
 -    my $config = $class->config->{ $suffix } || {};
 -    # Stash catalyst_component_name in the config here, so that custom COMPONENT
 -    # methods also pass it. local to avoid pointlessly shitting in config
 -    # for the debug screen, as $component is already the key name.
 -    local $config->{catalyst_component_name} = $component;
 +sub locate_components {
 +    my $class = shift;
  
 -    my $instance = eval { $component->COMPONENT( $class, $config ); };
 +    $class->log->warn('The locate_components method has been deprecated.');
 +    $class->log->warn('Please read Catalyst::IOC::Container documentation to');
 +    $class->log->warn('update your application.');
  
 -    if ( my $error = $@ ) {
 -        chomp $error;
 -        Catalyst::Exception->throw(
 -            message => qq/Couldn't instantiate component "$component", "$error"/
 -        );
 -    }
 -
 -    unless (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;
 -        my $value = defined($instance) ? $instance : 'undef';
 -        Catalyst::Exception->throw(
 -            message =>
 -            qq/Couldn't instantiate component "$component", COMPONENT() method (from $component_method_from) didn't return an object-like value (value was $value)./
 -        );
 -    }
 -    return $instance;
 +    # XXX think about ditching this sort entirely
 +    return sort { length $a <=> length $b }
 +        @{ $class->container->resolve( service => 'locate_components' ) };
  }
  
  =head2 $c->setup_dispatcher
@@@ -2762,10 -3014,10 +2792,10 @@@ your output data, if known
  sub write {
      my $c = shift;
  
-     # Finalize headers if someone manually writes output
+     # Finalize headers if someone manually writes output (for compat)
      $c->finalize_headers;
  
-     return $c->engine->write( $c, @_ );
+     return $c->response->write( @_ );
  }
  
  =head2 version
@@@ -2793,6 -3045,14 +2823,6 @@@ C<default_view> - The default view to b
  
  =item *
  
 -C<disable_component_resolution_regex_fallback> - Turns
 -off the deprecated component resolution functionality so
 -that if any of the component methods (e.g. C<< $c->controller('Foo') >>)
 -are called then regex search will not be attempted on string values and
 -instead C<undef> will be returned.
 -
 -=item *
 -
  C<home> - The application home directory. In an uninstalled application,
  this is the top level application directory. In an installed application,
  this will be the directory containing C<< MyApp.pm >>.
@@@ -2820,6 -3080,12 +2850,6 @@@ templates to a different directory
  
  =item *
  
 -C<search_extra> - Array reference passed to Module::Pluggable to for additional
 -namespaces from which components will be loaded (and constructed and stored in
 -C<< $c->components >>).
 -
 -=item *
 -
  C<show_internal_actions> - If true, causes internal actions such as C<< _DISPATCH >>
  to be shown in hit debug tables in the test server.
  
@@@ -2999,8 -3265,6 +3029,6 @@@ Wiki
  
  =head2 L<Catalyst::Test> - The test suite.
  
- =begin stopwords
  =head1 PROJECT FOUNDER
  
  sri: Sebastian Riedel <sri@cpan.org>
@@@ -3019,8 -3283,6 +3047,8 @@@ Andrew Ford E<lt>A.Ford@ford-mason.co.u
  
  Andrew Ruthven
  
 +André Walker
 +
  andyg: Andy Grundman <andy@hybridized.org>
  
  audreyt: Audrey Tang
@@@ -3145,8 -3407,6 +3173,6 @@@ rainboxx: Matthias Dietrich, C<perl@rai
  
  dd070: Dhaval Dhanani <dhaval070@gmail.com>
  
- =end stopwords
  =head1 COPYRIGHT
  
  Copyright (c) 2005, the above named PROJECT FOUNDER and CONTRIBUTORS.
diff --combined t/author/spelling.t
@@@ -6,8 -6,7 +6,8 @@@ use Test::Spelling
  add_stopwords(qw(
      API CGI MVC PSGI Plack README SSI Starman XXXX URI htaccess middleware
      mixins namespace psgi startup Deprecations catamoose cataplack linearize
 -    subclasses subdirectories refactoring adaptors
 +    subclasses subdirectories refactoring adaptors ConfigLoader json xml
 +    IOC conf myapp customised
      undef env regex unary rethrow rethrows stringifies CPAN STDERR SIGCHLD baz
      roadmap wishlist refactor refactored Runtime pluggable pluggability hoc apis
      fastcgi nginx Lighttpd IIS middlewares backend IRC
      filename tempname request's subdirectory ini uninstalled uppercased
      wiki bitmask uri url urls dir hostname proxied http https IP SSL
      inline INLINE plugins
+     Andreas
+     Ashton
+     Axel
+     Balint
+     Belka
+     Brocard
+     Caelum
+     Cassidy
+     Dagfinn
+     Danijel
+     Dhanani
+     Dhaval
+     Diment
+     Doran
+     Edvinsson
+     Florian
+     Geoff
+     Grundman
+     Hartmaier
+     Hawes
+     Ilmari
+     Johan
+     Kamholz
+     Kiefer
+     Kieren
+     Kitover
+     Kogman
+     Kostyuk
+     Kubb
+     Lammel
+     Lindstrom
+     Mannsåker
+     Marienborg
+     Marrandi
+     McWhirter
+     Milicevic
+     Miyagawa
+     Montes
+     Naughton
+     Oleg
+     Ragwitz
+     Ramberg
+     Rasnita
+     Reis
+     Riedel
+     Rockway
+     Roditi
+     Rodland
+     Ruthven
+     Sascha
+     Schutz
+     Sedlacek
+     Sheidlower
+     SpiceMan
+     Szilakszi
+     Tatsuhiko
+     Ulf
+     Vilain
+     Viljo
+     Wardley
+     Westermann
+     Willert
+     Yuval
+     abraxxa
+     abw
+     andyg
+     audreyt
+     bricas
+     chansen
+     dhoss
+     dkubb
+     dwc
+     esskar
+     fREW
+     fireartist
+     frew
+     gabb
+     groditi
+     hobbs
+     ilmari
+     jcamacho
+     jhannah
+     jon
+     konobi
+     marcus
+     miyagawa
+     mst
+     naughton
+     ningu
+     nothingmuch
+     numa
+     obra
+     phaylon
+     rafl
+     rainboxx
+     sri
+     szbalint
+     willert
+     wreis
  ));
  set_spell_cmd('aspell list -l en');
  all_pod_files_spelling_ok();