Merge up from 5.70 trunk:
Tomas Doran [Tue, 13 Jan 2009 23:38:45 +0000 (23:38 +0000)]
r9031 | jhannah | 2009-01-07 19:51:06 +0000 (Wed, 07 Jan 2009) | 5 lines

Far more verbose error messages. Does great at making the problem in my
Catalyst/Plugin/Session/Store/DBIC.pm configuration super obvious.
Hopefully this also makes other mistakes more obvious. I'm not sure it's
perfect, but I think it's better than it was.    --jay@jays.net

1  2 
Changes
lib/Catalyst.pm

diff --combined Changes
+++ b/Changes
  # This file documents the revision history for Perl extension Catalyst.
  
 +5.8000_05
++        - Improve the clarity and verbosity of the warning when component
++          resolution uses regex fallback. (jhannah)
 +        - Handle leading CRLF in HTTP requests sometimes sent by IE6 in 
 +          keep-alive requests. (andyg)
 +        - Fixes for FastCGI with IIS 6.0 (janus)
 +        - Passing request method exported by Catalyst::Test an extra
 +          parameter used to be ignored, but started breaking if the parameter
 +          was not a hash in 5.8000_04. Extra parameter is now ignored if
 +          it isn't a hashref (t0m)
 +        - Fix request argumentss getting corrupted if you override the 
 +          dispatcher and call an action which detaches (for 
 +          Catalyst::Plugin::Authorization::ACL) (t0m)
 +        - Fix calling use Catalyst::Test 'MyApp' 'foo' which used to work,
 +          but stopped as the 2nd parameter can be an options hash now (t0m)
 +        - Bump Moose dependency to fix make_immutable bug (t0m)
 +        - Use compile time extends in Catalyst::Controller (t0m)
 +        - Make Catalyst::Request::uploads attribute non-lazy, to fix
 +          test for Catalyst-Engine-Apache (t0m)
 +        - Bump version of MooseX::Emulate::Class::Accessor::Fast (t0m)
 +        - Stop using MooseX::Adopt::Class::Accessor::Fast by default, to stop
 +          breaking other packages which use Class::Accessor::Fast
 +        - Remove unused action_container_class attribute from 
 +          Catalyst::Dispatcher (t0m)
 +        - Replace {_body} instance access with calls to _body accessors (t0m)
 +        - Add backwards compatibility alias methods for private attributes on 
 +          Catalyst::Dispatcher which used to be public. Needed by 
 +          Catalyst::Plugin::Server and  Catalyst::Plugin::Authorization::ACL 
 +          (t0m)
 +        - Fix return value of $c->req->body, which delegates to the body
 +          method on the requests HTTP::Body instance (t0m)
 +          - Test for this (t0m)
 +        - Fix calling $c->req->body from inside an overridden prepare_action
 +          method in a plugin, as used by Catalyst::Plugin::Server (t0m)
 +          - Test for this (t0m)
 +        - Fix assignment to Catalyst::Dispatcher's preload_dispatch_types and
 +          postload_dispatch_types attributes - assigning a list should later 
 +          return a listref. Fixes Catalyst::Plugin::Server. (t0m)
 +          - Tests for this (t0m)
 +        - Change streaming test to serve itself rather than 01use.t, making 
 +          test sync for engines easier (t0m)
 +        - Refactor capturing of $app from Catalyst::Controller into
 +          Catalyst::Component::ApplicationAttribute for easier reuse in other
 +          components (Florian Ragwitz)
 +        - Make the test suites YAML dependency optional (Florian Ragwitz)
 +        - Make debug output show class name for the engine and dispatcher
 +          rather than the stringified ref. (t0m)
 +        - Make MyApp immutable at the end of the scope after the setup
 +          method is called, fixing issues with plugins which have their 
 +          own new methods by inlining a constructor on MyApp (t0m)
 +          - Test for this and method modifiers in MyApp (t0m)
 +        - Fix bug causing Catalyst::Request::Upload's basename method
 +          to return undef (t0m)
 +          - Test for this (Carl Franks)
 +        - Fix loading of classes which do not define any symbols to not
 +          die, as it didn't in 5.70 (t0m)
 +          - Test for this (t0m)
 +        - Bump MooseX::Emulate::Class::Accessor::Fast dependency
 +          to force new version which fixes a lot of plugins (t0m)
 +        - Make log levels additive, and add documentation and tests
 +          for the setup_log method, which previously had none.
 +          Sewn together by t0m from two patches provided by David E. Wheeler
 +        - Switch an around 'new' in Catalyst::Controller to a BUILDARGS
 +          method as it's much neater and more obvious what is going on (t0m)
 +        - Add a clearer method on request and response _context 
 +          attributes, and use if from ::Engine rather than deleting
 +          the key from the instance hash (t0m)
 +        - Use handles on tree attribute of Catalyst::Stats to replace
 +          trivial delegation methods (t0m)
 +        - Change the following direct hash accesses into attributes:
 +          Catalyst::Engine: _prepared_write
 +          Catalyst::Engine::CGI: _header_buf
 +          Catalyst::Engine::HTTP: options, _keepalive, _write_error
 +          Catalyst::Request: _path
 +          Catalyst::Stats: tree
 +          (t0m)
 +        - Fix issues in Catalyst::Controller::WrapCGI 
 +          and any other components which import (or define) their 
 +          own meta method by always explicitly calling
 +          Class::MOP::Object->meta inside Catalyst (t0m)
 +          - Add test for this (t0m)
 +        - Add test case for the bug which is causing the 
 +          Catalyst::Plugin::Authentication tests to fail (t0m)
 +        - Fix a bug in uri_for which could cause it to generate paths
 +          with multiple slashes in them. (t0m)
 +          - Add test for this (t0m)
 +        - Fix SKIP block name in t/optional_http-server-restart.t,
 +          stopping 'Label not found for "last SKIP"' error from 
 +          Test::More (t0m)
 +        - Workaround max_redirect 0 bug in LWP (andyg)
 +        - Move live_engine_response_print into aggregate (andyg)
 +        - Fix dependency bug, s/parent/base/ in new test (rafl)
 +        - Fix optional tests to run the live tests in the aggregate 
 +          dir (andyg)
 +        - Fix Catalyst->go error in remote tests (andyg)
 +        - Fix upload test to work with remote servers, don't check for 
 +          deleted files (andyg)
 +        - Fix engine_request_uri tests to work on remote server with 
 +          different URI (andyg)
 +
 +5.8000_04  2008-12-05 12:15:00
 +        - Silence Class::C3::Adopt::NEXT warnings in the test suite (rafl)
 +        - Fix loads of 'used once, possible typo' warnings (rafl)
 +        - Additional tests to ensure upload temp files are deleted (andyg)
 +        - Remove use of NEXT from the test suite, except for one case
 +          which tests if Class::C3::Adopt::NEXT is working (t0m)
 +        - Use a predicate to avoid recursion in cases where the uri
 +          method is overridden by a plugin, and calls the base method,
 +          for example Catalyst::Plugin::SmartURI (t0m)
 +          - Test for this (caelum)
 +        - Compose the MooseX::Emulate::Class::Accessor::Fast role to 
 +          Catalyst::Action, Catalyst::Request, and all other modules which 
 +          inherit from Class::Accessor::Fast in 5.70.
 +          This fixes:
 +            - Catalyst::Controller::HTML::FormFu (zamolxes)
 +            - Catalyst::Request::REST (t0m)
 +          - Test for this (t0m)
 +        - Make hostname resolution lazy (Marc Mims)
 +        - Support mocking virtualhosts in test suite (Jason Gottshall)
 +        - Add README (marcus)
 +        - Fix TODO list (t0m)
 +        - Use Class::C3::Adopt::NEXT (rafl)
 +        - Ignore C3 warnings on 5.10 when testing ensure_class_loaded (rafl)
 +        - Add TODO test for chained bug (gbjk)
 +        - Fix list address in documentation (zarquon)
 +        - Fix ACCEPT_CONTEXT on MyApp, called as a class method (marcus)
 +           - Test for this (marcus)
 +        - Bump MooseX::Emulate::Class::Accessor::Fast version requirement to 
 +          get more back compatibility (t0m)
 +        - Improve documentation for $req->captures (caelum)
 +        - Fix a bug in Catalyst::Stats, stopping garbage being inserted into
 +          the stats if a user calls begin => but no end => (jhannah)
 +           - Test for this (jhannah)
 +        - Trim lines sooner in stats to avoid ugly Text::SimpleTable wrapping
 +          (jhannah)
 +        - Change Catalyst::ClassData to tweak the symbol table inline for
 +          performance after profiling (mst)
 +        - Fix POD typo in finalize_error (jhannah)
 +        - Add tests to ensure that we delete the temp files created by 
 +          HTTP::Body's OctetStream parser (t0m)
 +
 +5.8000_03 2008-10-14 14:13:00
 +        - Fix forwarding to Catalyst::Action objects (Rafael Kitover).
 +        - Fix links to the mailing lists (RT #39754 and Florian Ragwitz).
 +        - Use Class::MOP instead of Class::Inspector (Florian Ragwitz).
 +        - Change Catalyst::Test to use Sub::Exporter (Florian Ragwitz).
 +        - Fixed typo in Engine::HTTP::Restarter::Watcher causing -r to complain.
 +
 +5.8000_02 2008-10-14 07:59:00
 +       - Fix manifest
 +
 +5.8000_01 2008-10-13 22:52:00
 +        - Port to Moose
 +        - Added test for action stringify
 +        - Added test for component instances getting $self->{value} from config.
 +        - Add Catalyst::Response->print() method (ilmari)
 +        - Optionally aggregate tests using Test::Aggregate (Florian Ragwitz).
 +        - Additional docs for uri_for to mention how to use $c->action and 
 +          $c->req->captures (jhannah)
 +        - List unattached chained actions in Debug mode (Florian Ragwitz).
 +        - Pod formatting fix for Engine::FastCGI (Oleg Kostyuk).
 +        - Add visit, a returning ->go
 +
  5.7XXXXXX XXXX
 -        - Add environment hack for FastCGI under IIS (Simon Bertrang)
 -          - Test for this and preexisting Lighty hack (Simon Bertrang)
 -        - Change streaming test to serve itself rather than 01use.t, making test
 -          sync for engines easier (t0m)
          - Workaround change in LWP that broke a cookie test (RT #40037)
          - Back out go() since that feature's been pushed to 5.80
          - Fix some Win32 test failures
          - Add pt translation of error message (wreis)
          - Make :Chained('../action') work (Florian Ragwitz)
 -        - Handle leading CRLF in HTTP requests sometimes sent by IE6 in keep-alive requests.
 +        - Add test actions
 +        - Chained doc improvements (rev 8326-8328)
  
  5.7099_03 2008-07-20 10:10:00
          - Fix regressions for regexp fallback in model(), view() and controller()
diff --combined lib/Catalyst.pm
@@@ -1,13 -1,8 +1,13 @@@
  package Catalyst;
  
 -use strict;
 -use base 'Catalyst::Component';
 +# we don't need really need this, but if we load it before MRO::Compat gets
 +# loaded (via Moose and Class::MOP), we can avoid some nasty warnings
 +use Class::C3;
 +
 +use Moose;
 +extends 'Catalyst::Component';
  use bytes;
 +use Scope::Upper ();
  use Catalyst::Exception;
  use Catalyst::Log;
  use Catalyst::Request;
@@@ -18,6 -13,7 +18,6 @@@ use Catalyst::Controller
  use Devel::InnerPackage ();
  use File::stat;
  use Module::Pluggable::Object ();
 -use NEXT;
  use Text::SimpleTable ();
  use Path::Class::Dir ();
  use Path::Class::File ();
@@@ -30,44 -26,30 +30,44 @@@ use Tree::Simple qw/use_weak_refs/
  use Tree::Simple::Visitor::FindByUID;
  use attributes;
  use utf8;
- use Carp qw/croak carp/;
+ use Carp qw/croak carp shortmess/;
  
  BEGIN { require 5.008001; }
  
 -__PACKAGE__->mk_accessors(
 -    qw/counter request response state action stack namespace stats/
 -);
 +has stack => (is => 'ro', default => sub { [] });
 +has stash => (is => 'rw', default => sub { {} });
 +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 namespace => (is => 'rw');
  
  sub depth { scalar @{ shift->stack || [] }; }
 +sub comp { shift->component(@_) }
  
 -# Laziness++
 -*comp = \&component;
 -*req  = \&request;
 -*res  = \&response;
 +sub req {
 +    # carp "the use of req() is deprecated in favour of request()";
 +    my $self = shift; return $self->request(@_);
 +}
 +sub res {
 +    # carp "the use of res() is deprecated in favour of response()";
 +    my $self = shift; return $self->response(@_);
 +}
  
  # For backwards compatibility
 -*finalize_output = \&finalize_body;
 +sub finalize_output { shift->finalize_body(@_) };
  
  # For statistics
  our $COUNT     = 1;
  our $START     = time;
  our $RECURSION = 1000;
  our $DETACH    = "catalyst_detach\n";
 +our $GO        = "catalyst_go\n";
  
 +#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
    engine_class context_class request_class response_class stats_class 
@@@ -81,7 -63,7 +81,7 @@@ __PACKAGE__->stats_class('Catalyst::Sta
  
  # Remember to update this in Catalyst::Runtime as well!
  
 -our $VERSION = '5.7099_03';
 +our $VERSION = '5.8000_05';
  
  sub import {
      my ( $class, @arguments ) = @_;
      # callers @ISA.
      return unless $class eq 'Catalyst';
  
 -    my $caller = caller(0);
 +    my $caller = caller();
 +    return if $caller eq 'main';
 +    my $meta = Moose::Meta::Class->initialize($caller);
 +    #Moose->import({ into => $caller }); #do we want to do this?
  
      unless ( $caller->isa('Catalyst') ) {
 -        no strict 'refs';
 -        push @{"$caller\::ISA"}, $class, 'Catalyst::Controller';
 +        my @superclasses = ($meta->superclasses, $class, 'Catalyst::Controller');
 +        $meta->superclasses(@superclasses);
 +    }
 +    unless( $meta->has_method('meta') ){
 +        $meta->add_method(meta => sub { Moose::Meta::Class->initialize("${caller}") } );
      }
  
      $caller->arguments( [@arguments] );
@@@ -262,9 -238,7 +262,9 @@@ MYAPP_WEB_HOME. If both variables are s
  
  =head2 -Log
  
 -Specifies log level.
 +    use Catalyst '-Log=warn,fatal,error';
 + 
 +Specifies a comma-delimited list of log levels.
  
  =head2 -Stats
  
@@@ -336,7 -310,7 +336,7 @@@ your code like this
  
  =cut
  
 -sub forward { my $c = shift; $c->dispatcher->forward( $c, @_ ) }
 +sub forward { my $c = shift; no warnings 'recursion'; $c->dispatcher->forward( $c, @_ ) }
  
  =head2 $c->detach( $action [, \@arguments ] )
  
@@@ -353,40 -327,6 +353,40 @@@ When called with no arguments it escape
  
  sub detach { my $c = shift; $c->dispatcher->detach( $c, @_ ) }
  
 +=head2 $c->visit( $action [, \@arguments ] )
 +
 +=head2 $c->visit( $class, $method, [, \@arguments ] )
 +
 +Almost the same as C<forward>, but does a full dispatch, instead of just
 +calling the new C<$action> / C<$class-E<gt>$method>. This means that C<begin>,
 +C<auto> and the method you go to are called, just like a new request.
 +
 +C<$c-E<gt>stash> is kept unchanged.
 +
 +In effect, C<visit> allows you to "wrap" another action, just as it
 +would have been called by dispatching from a URL, while the analogous
 +C<go> allows you to transfer control to another action as if it had
 +been reached directly from a URL.
 +
 +=cut
 +
 +sub visit { my $c = shift; $c->dispatcher->visit( $c, @_ ) }
 +
 +=head2 $c->go( $action [, \@arguments ] )
 +
 +=head2 $c->go( $class, $method, [, \@arguments ] )
 +
 +Almost the same as C<detach>, but does a full dispatch like C<visit>,
 +instead of just calling the new C<$action> /
 +C<$class-E<gt>$method>. This means that C<begin>, C<auto> and the
 +method you visit are called, just like a new request.
 +
 +C<$c-E<gt>stash> is kept unchanged.
 +
 +=cut
 +
 +sub go { my $c = shift; $c->dispatcher->go( $c, @_ ) }
 +
  =head2 $c->response
  
  =head2 $c->res
@@@ -412,21 -352,17 +412,21 @@@ Catalyst)
  
  =cut
  
 -sub stash {
 +around stash => sub {
 +    my $orig = shift;
      my $c = shift;
 +    my $stash = $orig->($c);
      if (@_) {
 -        my $stash = @_ > 1 ? {@_} : $_[0];
 -        croak('stash takes a hash or hashref') unless ref $stash;
 -        foreach my $key ( keys %$stash ) {
 -            $c->{stash}->{$key} = $stash->{$key};
 +        my $new_stash = @_ > 1 ? {@_} : $_[0];
 +        croak('stash takes a hash or hashref') unless ref $new_stash;
 +        foreach my $key ( keys %$new_stash ) {
 +          $stash->{$key} = $new_stash->{$key};
          }
      }
 -    return $c->{stash};
 -}
 +
 +    return $stash;
 +};
 +
  
  =head2 $c->error
  
@@@ -510,9 -446,24 +510,24 @@@ sub _comp_search_prefixes 
  
      # don't warn if we didn't find any results, it just might not exist
      if( @result ) {
-         $c->log->warn( qq(Found results for "${name}" using regexp fallback.) );
-         $c->log->warn( 'Relying on the regexp fallback behavior for component resolution is unreliable and unsafe.' );
-         $c->log->warn( 'If you really want to search, pass in a regexp as the argument.' );
+         my $msg = "Used regexp fallback for \$c->model('${name}'), which found '" .
+            (join '", "', @result) . "'. Relying on regexp fallback behavior for " .
+            "component resolution is unreliable and unsafe.";
+         my $short = $result[0];
+         $short =~ s/.*?Model:://;
+         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->model('$short') instead of \$c->model{'${name}'}, " .
+               "but if you really wanted to search, pass in a regexp as the argument " .
+               "like so: \$c->model(qr/${name}/)";
+         }
+         $c->log->warn( "${msg}$shortmess" );
      }
  
      return @result;
@@@ -613,11 -564,11 +628,11 @@@ sub model 
      my( $comp, $rest ) = $c->_comp_search_prefixes( undef, qw/Model M/);
  
      if( $rest ) {
-         $c->log->warn( 'Calling $c->model() will return a random model unless you specify one of:' );
+         $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.80, the "random" behavior will not work at all.' );
 +        $c->log->warn( 'NB: in version 5.81, the "random" behavior will not work at all.' );
      }
  
      return $c->_filter_component( $comp );
@@@ -670,7 -621,7 +685,7 @@@ sub view 
          $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.80, the "random" behavior will not work at all.' );
 +        $c->log->warn( 'NB: in version 5.81, the "random" behavior will not work at all.' );
      }
  
      return $c->_filter_component( $comp );
@@@ -752,7 -703,7 +767,7 @@@ sub component 
          return map { $c->_filter_component( $_, @args ) } @result if ref $name;
  
          if( $result[ 0 ] ) {
-             $c->log->warn( qq(Found results for "${name}" using regexp fallback.) );
+             $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 );
@@@ -783,15 -734,14 +798,15 @@@ L<Catalyst::Plugin::ConfigLoader>
  
  =cut
  
 -sub config {
 +around config => sub {
 +    my $orig = shift;
      my $c = shift;
  
      $c->log->warn("Setting config after setup has been run is not a good idea.")
        if ( @_ and $c->setup_finished );
  
 -    $c->NEXT::config(@_);
 -}
 +    $c->$orig(@_);
 +};
  
  =head2 $c->log
  
@@@ -861,19 -811,11 +876,19 @@@ loads and instantiates the given class
      MyApp->plugin( 'prototype', 'HTML::Prototype' );
  
      $c->prototype->define_javascript_functions;
 +    
 +B<Note:> This method of adding plugins is deprecated. The ability
 +to add plugins like this B<will be removed> in a Catalyst 5.9.
 +Please do not use this functionality in new code.
  
  =cut
  
  sub plugin {
      my ( $class, $name, $plugin, @args ) = @_;
 +
 +    # See block comment in t/unit_core_plugin.t    
 +    $class->log->debug(qq/Adding plugin using the ->plugin method is deprecated, and will be removed in Catalyst 5.9/);
 +    
      $class->_register_plugin( $plugin, 1 );
  
      eval { $plugin->import };
@@@ -905,6 -847,7 +920,6 @@@ Catalyst> line
  
  sub setup {
      my ( $class, @arguments ) = @_;
 -
      $class->log->warn("Running setup twice is not a good idea.")
        if ( $class->setup_finished );
  
@@@ -980,8 -923,8 +995,8 @@@ EO
          my $engine     = $class->engine;
          my $home       = $class->config->{home};
  
 -        $class->log->debug(qq/Loaded dispatcher "$dispatcher"/);
 -        $class->log->debug(qq/Loaded engine "$engine"/);
 +        $class->log->debug(sprintf(q/Loaded dispatcher "%s"/, blessed($dispatcher)));
 +        $class->log->debug(sprintf(q/Loaded engine "%s"/, blessed($engine)));
  
          $home
            ? ( -d $home )
            : $class->log->debug(q/Couldn't find home/);
      }
  
 -    # Call plugins setup
 +    # Call plugins setup, this is stupid and evil.
      {
          no warnings qw/redefine/;
          local *setup = sub { };
      }
  
      # Add our self to components, since we are also a component
 -    $class->components->{$class} = $class;
 +    if( $class->isa('Catalyst::Controller') ){
 +      $class->components->{$class} = $class;
 +    }
  
      $class->setup_actions;
  
      }
      $class->log->_flush() if $class->log->can('_flush');
  
 +    # Make sure that the application class becomes immutable at this point, 
 +    # which ensures that it gets an inlined constructor. This means that it 
 +    # works even if the user has added a plugin which contains a new method.
 +    # Note however that we have to do the work on scope end, so that method
 +    # modifiers work correctly in MyApp (as you have to call setup _before_ 
 +    # applying modifiers).
 +    Scope::Upper::reap(sub {
 +        my $meta = Class::MOP::get_metaclass_by_name($class);
 +        $meta->make_immutable unless $meta->is_immutable;
 +    }, 1);
 +
      $class->setup_finished(1);
  }
  
@@@ -1053,17 -983,62 +1068,17 @@@ use C<< $c->action('someactionname') >>
  controller, fetch the controller using C<< $c->controller() >>, then
  call C<action_for> on it.
  
 -This method must be used to create URIs for
 -L<Catalyst::DispatchType::Chained> actions.
 +You can maintain the arguments captured by an action (e.g.: Regex, Chained)
 +using C<< $c->req->captures >>. 
  
 -=item $path
 -
 -The actual path you wish to create a URI for, this is a public path,
 -not a private action path.
 -
 -=item \@captures
 -
 -If provided, this argument is used to insert values into a I<Chained>
 -action in the parts where the definitions contain I<CaptureArgs>. If
 -not needed, leave out this argument.
 -
 -=item @args
 -
 -If provided, this is used as a list of further path sections to append
 -to the URI. In a I<Chained> action these are the equivalent to the
 -endpoint L<Args>.
 -
 -=item \%query_values
 -
 -If provided, the query_values hashref is used to add query parameters
 -to the URI, with the keys as the names, and the values as the values.
 +  # For the current action
 +  $c->uri_for($c->action, $c->req->captures);
 +  
 +  # For the Foo action in the Bar controller
 +  $c->uri_for($c->controller->('Bar')->action_for('Foo'), $c->req->captures);
  
  =back
  
 -Returns a L<URI> object.
 -
 -  ## Ex 1: a path with args and a query parameter
 -  $c->uri_for('user/list', 'short', { page => 2});
 -  ## -> ($c->req->base is 'http://localhost:3000/'
 -  URI->new('http://localhost:3000/user/list/short?page=2)
 -
 -  ## Ex 2: a chained view action that captures the user id
 -  ## In controller:
 -  sub user : Chained('/'): PathPart('myuser'): CaptureArgs(1) {}
 -  sub viewuser : Chained('user'): PathPart('view') {}
 -
 -  ## In uri creating code:
 -  my $uaction = $c->controller('Users')->action_for('viewuser');
 -  $c->uri_for($uaction, [ 42 ]);
 -  ## outputs:
 -  URI->new('http://localhost:3000/myuser/42/view')
 -
 -Creates a URI object using C<< $c->request->base >> and a path. If an
 -Action object is given instead of a path, the path is constructed
 -using C<< $c->dispatcher->uri_for_action >> and passing it the
 -@captures array, if supplied.
 -
 -If any query parameters are passed they are added to the end of the
 -URI in the usual way.
 -
 -Note that uri_for is destructive to the passed query values hashref.
 -Subsequent calls with the same hashref may have unintended results.
 -
  =cut
  
  sub uri_for {
      # join args with '/', or a blank string
      my $args = join('/', grep { defined($_) } @args);
      $args =~ s/\?/%3F/g; # STUPID STUPID SPECIAL CASE
 -    $args =~ s!^/!!;
 +    $args =~ s!^/+!!;
      my $base = $c->req->base;
      my $class = ref($base);
      $base =~ s{(?<!/)$}{/};
@@@ -1259,7 -1234,7 +1274,7 @@@ sub welcome_message 
                           <a href="http://dev.catalyst.perl.org">Wiki</a>
                       </li>
                       <li>
 -                         <a href="http://lists.rawmode.org/mailman/listinfo/catalyst">Mailing-List</a>
 +                         <a href="http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst">Mailing-List</a>
                       </li>
                       <li>
                           <a href="irc://irc.perl.org/catalyst">IRC channel #catalyst on irc.perl.org</a>
@@@ -1341,9 -1316,9 +1356,9 @@@ sub execute 
      $c->state(0);
  
      if ( $c->depth >= $RECURSION ) {
 -        my $action = "$code";
 +        my $action = $code->reverse();
          $action = "/$action" unless $action =~ /->/;
 -        my $error = qq/Deep recursion detected calling "$action"/;
 +        my $error = qq/Deep recursion detected calling "${action}"/;
          $c->log->error($error);
          $c->error($error);
          $c->state(0);
  
      push( @{ $c->stack }, $code );
      
 -    eval { $c->state( &$code( $class, $c, @{ $c->req->args } ) || 0 ) };
 +    eval { $c->state( $code->execute( $class, $c, @{ $c->req->args } ) || 0 ) };
  
      $c->_stats_finish_execute( $stats_info ) if $c->use_stats and $stats_info;
      
          if ( !ref($error) and $error eq $DETACH ) {
              die $DETACH if($c->depth > 1);
          }
 +        elsif ( !ref($error) and $error eq $GO ) {
 +            die $GO if($c->depth > 0);
 +        }
          else {
              unless ( ref $error ) {
                  no warnings 'uninitialized';
@@@ -1388,10 -1360,9 +1403,10 @@@ sub _stats_start_execute 
      return if ( ( $code->name =~ /^_.*/ )
          && ( !$c->config->{show_internal_actions} ) );
  
 -    $c->counter->{"$code"}++;
 +    my $action_name = $code->reverse();
 +    $c->counter->{$action_name}++;
  
 -    my $action = "$code";
 +    my $action = $action_name;
      $action = "/$action" unless $action =~ /->/;
  
      # determine if the call was the result of a forward
          }
      }
  
 -    my $uid = "$code" . $c->counter->{"$code"};
 +    my $uid = $action_name . $c->counter->{$action_name};
  
      # is this a root-level call or a forwarded call?
      if ( $callsub =~ /forward$/ ) {
@@@ -1453,8 -1424,6 +1468,8 @@@ sub _stats_finish_execute 
  
  =cut
  
 +#Why does this exist? This is no longer safe and WILL NOT WORK.
 +# it doesnt seem to be used anywhere. can we remove it?
  sub _localize_fields {
      my ( $c, $localized, $code ) = ( @_ );
  
@@@ -1482,9 -1451,8 +1497,9 @@@ sub finalize 
      }
  
      # Allow engine to handle finalize flow (for POE)
 -    if ( $c->engine->can('finalize') ) {
 -        $c->engine->finalize($c);
 +    my $engine = $c->engine;
 +    if ( my $code = $engine->can('finalize') ) {
 +        $engine->$code($c);
      }
      else {
  
@@@ -1548,33 -1516,31 +1563,33 @@@ Finalizes headers
  sub finalize_headers {
      my $c = shift;
  
 +    my $response = $c->response; #accessor calls can add up?
 +
      # Check if we already finalized headers
 -    return if $c->response->{_finalized_headers};
 +    return if $response->finalized_headers;
  
      # Handle redirects
 -    if ( my $location = $c->response->redirect ) {
 +    if ( my $location = $response->redirect ) {
          $c->log->debug(qq/Redirecting to "$location"/) if $c->debug;
 -        $c->response->header( Location => $location );
 -        
 -        if ( !$c->response->body ) {
 +        $response->header( Location => $location );
 +
 +        if ( !$response->has_body ) {
              # Add a default body if none is already present
 -            $c->response->body(
 +            $response->body(
                  qq{<html><body><p>This item has moved <a href="$location">here</a>.</p></body></html>}
              );
          }
      }
  
      # Content-Length
 -    if ( $c->response->body && !$c->response->content_length ) {
 +    if ( $response->body && !$response->content_length ) {
  
          # get the length from a filehandle
 -        if ( blessed( $c->response->body ) && $c->response->body->can('read') )
 +        if ( blessed( $response->body ) && $response->body->can('read') )
          {
 -            my $stat = stat $c->response->body;
 +            my $stat = stat $response->body;
              if ( $stat && $stat->size > 0 ) {
 -                $c->response->content_length( $stat->size );
 +                $response->content_length( $stat->size );
              }
              else {
                  $c->log->warn('Serving filehandle without a content-length');
          }
          else {
              # everything should be bytes at this point, but just in case
 -            $c->response->content_length( bytes::length( $c->response->body ) );
 +            $response->content_length( bytes::length( $response->body ) );
          }
      }
  
      # Errors
 -    if ( $c->response->status =~ /^(1\d\d|[23]04)$/ ) {
 -        $c->response->headers->remove_header("Content-Length");
 -        $c->response->body('');
 +    if ( $response->status =~ /^(1\d\d|[23]04)$/ ) {
 +        $response->headers->remove_header("Content-Length");
 +        $response->body('');
      }
  
      $c->finalize_cookies;
      $c->engine->finalize_headers( $c, @_ );
  
      # Done
 -    $c->response->{_finalized_headers} = 1;
 +    $response->finalized_headers(1);
  }
  
  =head2 $c->finalize_output
@@@ -1667,10 -1633,7 +1682,10 @@@ sub handle_request 
      }
  
      $COUNT++;
 -    $class->log->_flush() if $class->log->can('_flush');
 +    
 +    if(my $coderef = $class->log->can('_flush')){
 +        $class->log->$coderef();
 +    }
      return $status;
  }
  
@@@ -1684,24 -1647,48 +1699,24 @@@ etc.)
  sub prepare {
      my ( $class, @arguments ) = @_;
  
 +    # XXX
 +    # After the app/ctxt split, this should become an attribute based on something passed
 +    # into the application.
      $class->context_class( ref $class || $class ) unless $class->context_class;
 -    my $c = $class->context_class->new(
 -        {
 -            counter => {},
 -            stack   => [],
 -            request => $class->request_class->new(
 -                {
 -                    arguments        => [],
 -                    body_parameters  => {},
 -                    cookies          => {},
 -                    headers          => HTTP::Headers->new,
 -                    parameters       => {},
 -                    query_parameters => {},
 -                    secure           => 0,
 -                    captures         => [],
 -                    uploads          => {}
 -                }
 -            ),
 -            response => $class->response_class->new(
 -                {
 -                    body    => '',
 -                    cookies => {},
 -                    headers => HTTP::Headers->new(),
 -                    status  => 200
 -                }
 -            ),
 -            stash => {},
 -            state => 0
 -        }
 -    );
 +   
 +    my $c = $class->context_class->new({});
 +
 +    # For on-demand data
 +    $c->request->_context($c);
 +    $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->res->headers->header( 'X-Catalyst' => $Catalyst::VERSION );            
      }
  
 -    # For on-demand data
 -    $c->request->{_context}  = $c;
 -    $c->response->{_context} = $c;
 -    weaken( $c->request->{_context} );
 -    weaken( $c->response->{_context} );
 -
 +    #XXX reuse coderef from can
      # Allow engine to direct the prepare flow (for POE)
      if ( $c->engine->can('prepare') ) {
          $c->engine->prepare( $c, @arguments );
@@@ -1754,7 -1741,8 +1769,7 @@@ Prepares message body
  sub prepare_body {
      my $c = shift;
  
 -    # Do we run for the first time?
 -    return if defined $c->request->{_body};
 +    return if $c->request->_has_body;
  
      # Initialize on-demand data
      $c->engine->prepare_body( $c, @_ );
@@@ -2007,7 -1995,6 +2022,7 @@@ 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 } );
 +        #Class::MOP::load_class($component);
  
          my $module  = $class->setup_component( $component );
          my %modules = (
@@@ -2051,7 -2038,7 +2066,7 @@@ sub setup_component 
      Catalyst::Exception->throw(
          message =>
          qq/Couldn't instantiate component "$component", "COMPONENT() didn't return an object-like value"/
 -    ) unless eval { $instance->can( 'can' ) };
 +    ) unless blessed($instance);
  
      return $instance;
  }
@@@ -2077,7 -2064,9 +2092,7 @@@ sub setup_dispatcher 
          $dispatcher = $class->dispatcher_class;
      }
  
 -    unless (Class::Inspector->loaded($dispatcher)) {
 -        require Class::Inspector->filename($dispatcher);
 -    }
 +    Class::MOP::load_class($dispatcher);
  
      # dispatcher instance
      $class->dispatcher( $dispatcher->new );
@@@ -2101,10 -2090,12 +2116,10 @@@ sub setup_engine 
      }
  
      if ( $ENV{MOD_PERL} ) {
 -
 +        my $meta = Class::MOP::get_metaclass_by_name($class);
 +        
          # create the apache method
 -        {
 -            no strict 'refs';
 -            *{"$class\::apache"} = sub { shift->engine->apache };
 -        }
 +        $meta->add_method('apache' => sub { shift->engine->apache });
  
          my ( $software, $version ) =
            $ENV{MOD_PERL} =~ /^(\S+)\/(\d+(?:[\.\_]\d+)+)/;
          $engine = $class->engine_class;
      }
  
 -    unless (Class::Inspector->loaded($engine)) {
 -        require Class::Inspector->filename($engine);
 -    }
 +    Class::MOP::load_class($engine);
  
      # check for old engines that are no longer compatible
      my $old_engine;
@@@ -2212,10 -2205,11 +2227,10 @@@ sub setup_home 
          $home = $env;
      }
  
 -    unless ($home) {
 -        $home = Catalyst::Utils::home($class);
 -    }
 +    $home ||= Catalyst::Utils::home($class);
  
      if ($home) {
 +        #I remember recently being scolded for assigning config values like this
          $class->config->{home} ||= $home;
          $class->config->{root} ||= Path::Class::Dir->new($home)->subdir('root');
      }
  
  =head2 $c->setup_log
  
 -Sets up log.
 +Sets up log by instantiating a L<Catalyst::Log|Catalyst::Log> object and
 +passing it to C<log()>. Pass in a comma-delimited list of levels to set the
 +log to.
 + 
 +This method also installs a C<debug> method that returns a true value into the
 +catalyst subclass if the "debug" level is passed in the comma-delimited list,
 +or if the C<$CATALYST_DEBUG> environment variable is set to a true value.
 +
 +Note that if the log has already been setup, by either a previous call to
 +C<setup_log> or by a call such as C<< __PACKAGE__->log( MyLogger->new ) >>,
 +that this method won't actually set up the log object.
  
  =cut
  
  sub setup_log {
 -    my ( $class, $debug ) = @_;
 +    my ( $class, $levels ) = @_;
  
 +    $levels ||= '';
 +    $levels =~ s/^\s+//;
 +    $levels =~ s/\s+$//;
 +    my %levels = map { $_ => 1 } split /\s*,\s*/, $levels || '';
 +    
      unless ( $class->log ) {
 -        $class->log( Catalyst::Log->new );
 +        $class->log( Catalyst::Log->new(keys %levels) );
      }
  
      my $env_debug = Catalyst::Utils::env_value( $class, 'DEBUG' );
 -    if ( defined($env_debug) ? $env_debug : $debug ) {
 -        no strict 'refs';
 -        *{"$class\::debug"} = sub { 1 };
 +    if ( defined($env_debug) or $levels{debug} ) {
 +        Class::MOP::get_metaclass_by_name($class)->add_method('debug' => sub { 1 });
          $class->log->debug('Debug messages enabled');
      }
  }
@@@ -2275,7 -2255,8 +2290,7 @@@ sub setup_stats 
  
      my $env = Catalyst::Utils::env_value( $class, 'STATS' );
      if ( defined($env) ? $env : ($stats || $class->debug ) ) {
 -        no strict 'refs';
 -        *{"$class\::use_stats"} = sub { 1 };
 +        Class::MOP::get_metaclass_by_name($class)->add_method('use_stats' => sub { 1 });
          $class->log->debug('Statistics enabled');
      }
  }
@@@ -2313,17 -2294,12 +2328,17 @@@ the plugin name does not begin with C<C
          # no ignore_loaded here, the plugin may already have been
          # defined in memory and we don't want to error on "no file" if so
  
 -        Catalyst::Utils::ensure_class_loaded( $plugin );
 +        Class::MOP::load_class( $plugin );
  
          $proto->_plugins->{$plugin} = 1;
          unless ($instant) {
              no strict 'refs';
 -            unshift @{"$class\::ISA"}, $plugin;
 +            if ( my $meta = Class::MOP::get_metaclass_by_name($class) ) {
 +              my @superclasses = ($plugin, $meta->superclasses );
 +              $meta->superclasses(@superclasses);
 +            } else {
 +              unshift @{"$class\::ISA"}, $plugin;
 +            }
          }
          return $class;
      }
@@@ -2469,8 -2445,8 +2484,8 @@@ IRC
  
  Mailing Lists:
  
 -    http://lists.rawmode.org/mailman/listinfo/catalyst
 -    http://lists.rawmode.org/mailman/listinfo/catalyst-dev
 +    http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
 +    http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst-dev
  
  Web:
  
@@@ -2520,14 -2496,10 +2535,14 @@@ audreyt: Audrey Tan
  
  bricas: Brian Cassidy <bricas@cpan.org>
  
 +Caelum: Rafael Kitover <rkitover@io.com>
 +
  chansen: Christian Hansen
  
  chicks: Christopher Hicks
  
 +David E. Wheeler
 +
  dkubb: Dan Kubb <dan.kubb-cpan@onautopilot.com>
  
  Drew Taylor
@@@ -2542,10 -2514,10 +2557,12 @@@ Gary Ashton Jone
  
  Geoff Richards
  
 +ilmari: Dagfinn Ilmari MannsÃ¥ker <ilmari@ilmari.org>
 +
  jcamacho: Juan Camacho
  
+ jhannah: Jay Hannah <jay@jays.net>
  Jody Belka
  
  Johan Lindstrom
@@@ -2574,8 -2546,6 +2591,8 @@@ omega: Andreas Marienbor
  
  phaylon: Robert Sedlacek <phaylon@dunkelheit.at>
  
 +rafl: Florian Ragwitz <rafl@debian.org>
 +
  sky: Arthur Bergman
  
  the_jester: Jesse Sheidlower
@@@ -2591,8 -2561,4 +2608,8 @@@ the same terms as Perl itself
  
  =cut
  
 +no Moose;
 +
 +__PACKAGE__->meta->make_immutable;
 +
  1;