Merge branch 'master' into exception_interface
Florian Ragwitz [Tue, 15 Sep 2009 19:17:41 +0000 (19:17 +0000)]
master: (112 commits)
The warning about a class having mutable ancestors has been removed (and was never in a non-dev Moose release)
Work with old and new Moose
Preserve immutable_options when temporarily making a class mutable
Rework the C<< $c->go >> documentation a little, hopefully it's more clear.
Blargh. Merge branch deprecate_appclass_actions manually, with svn merge http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-Runtime/5.80/trunk http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-Runtime/5.80/branches/deprecate_appclass_actions . after I forgot -l on svk push, but ctrl-C after the first rev meant svk had already committed a merge mark and re-merging did nothing, and removing it didn't do the right thing. Fail cake..
Eat the merge mark, svk hates me.

Fix warnings in upcoming moose
add myself to contributors
Prepare for release
un-TODO passing TODO tests
Fix duplicate results from get_action_methods. Q. Why didn't I just do that first time round? A: Am idiot.
AGH. Too tired to be doing this, fucked it up again
I'm an idiot, that totally doesn't work. remove.
Test for r11331 + fix to only report each action name once from get_action_methods
Fix hash key name back to what it used to be for compat, keeping renamed accessor where it was. Tests for this breakage to follow
Changelogging
Changes tweaks
Bump versions back to 5.8.4
Changelog
...

88 files changed:
Changes
MANIFEST.SKIP
Makefile.PL
TODO
lib/Catalyst.pm
lib/Catalyst/Action.pm
lib/Catalyst/ClassData.pm
lib/Catalyst/Component.pm
lib/Catalyst/Controller.pm
lib/Catalyst/DispatchType/Chained.pm
lib/Catalyst/DispatchType/Path.pm
lib/Catalyst/DispatchType/Regex.pm
lib/Catalyst/Dispatcher.pm
lib/Catalyst/Engine.pm
lib/Catalyst/Engine/CGI.pm
lib/Catalyst/Engine/FastCGI.pm
lib/Catalyst/Engine/HTTP.pm
lib/Catalyst/Engine/HTTP/Restarter.pm [deleted file]
lib/Catalyst/Engine/HTTP/Restarter/Watcher.pm [deleted file]
lib/Catalyst/Request.pm
lib/Catalyst/Response.pm
lib/Catalyst/Runtime.pm
lib/Catalyst/Stats.pm
lib/Catalyst/Test.pm
t/aggregate/live_component_controller_action_auto.t
t/aggregate/live_component_controller_action_begin.t
t/aggregate/live_component_controller_action_chained.t
t/aggregate/live_component_controller_action_default.t
t/aggregate/live_component_controller_action_detach.t
t/aggregate/live_component_controller_action_forward.t
t/aggregate/live_component_controller_action_go.t
t/aggregate/live_component_controller_action_index.t
t/aggregate/live_component_controller_action_index_or_default.t
t/aggregate/live_component_controller_action_path_matchsingle.t
t/aggregate/live_component_controller_action_regexp.t
t/aggregate/live_component_controller_action_streaming.t
t/aggregate/live_component_controller_action_visit.t
t/aggregate/live_component_controller_anon.t [new file with mode: 0644]
t/aggregate/live_component_controller_attributes.t [moved from t/aggregate/live_component_controller_atttributes.t with 100% similarity]
t/aggregate/live_component_view_single.t
t/aggregate/live_engine_request_body.t
t/aggregate/live_engine_request_escaped_path.t
t/aggregate/live_engine_request_headers.t
t/aggregate/live_engine_request_remote_user.t
t/aggregate/unit_core_action_for.t
t/aggregate/unit_core_uri_for_action.t
t/author/optional_http-server.t [moved from t/optional_http-server.t with 61% similarity]
t/caf_backcompat.t
t/cdi_backcompat_plugin_accessor_override.t [deleted file]
t/custom_exception_class_simple.t [new file with mode: 0644]
t/custom_live_component_controller_action_auto_doublebug.t
t/deprecated.t
t/deprecated_appclass_action_warnings.t [new file with mode: 0644]
t/lib/ACLTestApp.pm [new file with mode: 0644]
t/lib/ACLTestApp/Controller/Root.pm [new file with mode: 0644]
t/lib/Catalyst/Plugin/Test/Plugin.pm
t/lib/DeprecatedActionsInAppClassTestApp.pm [new file with mode: 0644]
t/lib/PluginTestApp.pm
t/lib/PluginTestApp/Controller/Root.pm [new file with mode: 0644]
t/lib/TestApp.pm
t/lib/TestApp/Action/TestMyAction.pm
t/lib/TestApp/Controller/Action/Streaming.pm
t/lib/TestApp/Controller/Anon.pm [new file with mode: 0644]
t/lib/TestApp/Controller/Root.pm
t/lib/TestAppClassExceptionSimpleTest.pm [new file with mode: 0644]
t/lib/TestAppDoubleAutoBug.pm
t/lib/TestAppDoubleAutoBug/Controller/Root.pm [new file with mode: 0644]
t/lib/TestAppNonMooseController.pm [new file with mode: 0644]
t/lib/TestAppNonMooseController/Controller/Foo.pm [new file with mode: 0644]
t/lib/TestAppNonMooseController/ControllerBase.pm [new file with mode: 0644]
t/lib/TestAppPathBug.pm
t/lib/TestAppPluginWithConstructor.pm
t/lib/TestAppPluginWithConstructor/Controller/Root.pm [new file with mode: 0644]
t/lib/TestAppStats.pm
t/lib/TestAppStats/Controller/Root.pm [new file with mode: 0644]
t/lib/TestPluginWithConstructor.pm
t/optional_http-server-restart.t
t/unit_controller_actions.t [new file with mode: 0644]
t/unit_core_action.t [new file with mode: 0644]
t/unit_core_classdata.t
t/unit_core_component_loading.t
t/unit_core_plugin.t
t/unit_core_setup.t
t/unit_core_setup_log.t
t/unit_core_setup_stats.t
t/unit_dispatcher_requestargs_restore.t
t/unit_metaclass_compat_non_moose_controller.t
t/unit_stats.t

diff --git a/Changes b/Changes
index 23532c2..bba5e3b 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,8 +1,108 @@
 # This file documents the revision history for Perl extension Catalyst.
+#
+
+    - Add allow_mutable_ancestors option when force inlining a constructor onto
+      applications with plugins defining their own (usually Class::Accessor::Fast)
+      new methods, to avoid warnings generated by upcoming Moose releases
+      as we can make a class (MyApp) immutable when not all of it's superclasses
+      (e.g. plugins not fully Moose converted, but using
+       MooseX::Emulate::Class::Accessor::Fast) are not immutable.
+
+5.80012 2009-09-09 19:09:09
+
+  Bug fixes:
+     - Fix t/optional_http-server.t test.
+     - Fix t/optional_http-server-restart.t test.
+     - Fix duplicate components being loaded at setup time, each component is
+       now loaded at most once + tests.
+     - Fix backward compatibility - hash key configured actions are stored in
+       is returned to 'actions'.
+     - Fix get_action_methods returning duplicate methods when a method is both
+       decorated with method attributes and set as an action in config.
+
+  Refactoring / cleanups:
+     - Reduce minimum supported perl version from 5.8.6 to 5.8.4 as there are
+       many people still running/testing this version with no known issues.
+
+  Tests:
+     - Make the optional_http_server.t test an author only test which must be
+       run by authors to stop it being broken again.
+     - Fix recursion warnings in the test suites.
+
+5.80011 2009-08-23 13:48:15
+
+  Bug fixes:
+      - Remove leftovers of the restarter engine. The removed code caused test
+        failures, which weren't apparent for anyone still having an old version
+        installed in @INC.
+
+5.80010 2009-08-21 23:32:15
+
+  Bug fixes:
+      - Fix and add tests for a regression introduced by 5.80008.
+        Catalyst::Engine is now able to send out data from filehandles larger
+        than the default chunksize of 64k again.
+
+5.80009 2009-08-21 22:21:08
+
+  Bug fixes:
+      - Fix and add tests for generating inner packages inside the COMPONENT
+        method, and those packages being correctly registered as components.
+        This fixes Catalyst::Model::DBIC among others.
+
+5.80008 2009-08-21 17:47:30
 
   Bug fixes:
        - Fix replace_constructor warning to actually work if you make your
          application class immutable without that option.
+       - Depend on Module::Pluggable 3.9 to prevent a bug wherein components
+         in inner packages might not be registered. This especially affected
+         tests.
+       - Catalyst::Engine::FastCGI - relax the check for versions of Microsoft
+         IIS. Provides compatibility with Windows 2008 R2 as well as
+         (hopefully) future versions.
+       - In tests which depend on the values of environment variables,
+         localise the environment, then delete only relevant environment
+         variables (RT#48555)
+       - Fix issue with Engine::HTTP not sending headers properly in some cases
+         (RT#48623)
+       - Make Catalyst::Engine write at least once when finalizing the response
+         body from a filehandle, even if the write is empty. This avoids fail
+         when trying to send out an empty response body from a filehandle.
+       - Catalyst::Engine::HTTP - Accept a fully qualified absolute URI in the
+         Request-URI of the Request-Line
+
+  Refactoring / cleanups:
+       - Deleted the Restarter engine and its Watcher code. Use the
+         new Catalyst::Restarter in a recent Catalyst::Devel instead.
+       - New unit test for Catalyst::Action 'unit_core_action.t'
+       - Bump minimum supported perl version from 5.8.1 to 5.8.6 as there are
+         known issues with 5.8.3.
+       - Debug output uses dynamic column sizing to create more readable output
+         when using a larger $ENV{COLUMNS} setting. (groditi)
+
+  New features:
+       - Added private_path method for Catalyst::Action
+       - Allow uri_for($controller_instance) which will produce a URI
+         for the controller namespace
+       - Break setup_components into two more parts: locate_components and
+         expand_component_module (rjbs)
+       - Allow Components to return anon classed from their COMPONENT method
+         correctly, and have action registration work on Controllers returned
+         as such by adding a catalyst_component_name accessor for all components
+         which returns the component instance's name to be used when building
+         actions etc.
+       - Adding X-Forwarded-Port to allow the frontend proxy to dictate the
+         frontend port (jshirley)
+       - Added Catalyst::Stats->created accessor for the time at the start of
+         the request.
+
+  Documentation:
+       - Fix POD to refer to ->config(key => $val), rather than
+         ->config->{key} = $val, as the latter form is deprecated.
+       - Clearer docs for the 'uri_for' method.
+       - Fix POD refering to CGI::Cookie. We're using CGI::Simple::Cookie.
+         (Forrest Cahoon)
 
 5.80007 2009-06-30 23:54:34
 
         - Add Catalyst::Component::ContextClosure as an easy way to create code
           references, that close over the context, without creating leaks.
 
-   Refactoring / cleanups:
+  Refactoring / cleanups:
         - Clean namespaces in Catalyst::Exception*.
         - Turn Catalyst::Exception into an actual class and make the throw
           method create instances of it. They can still be used as normal
index 24b316c..d9fcc96 100644 (file)
@@ -1 +1 @@
-^(?!script/\w+\.pl$|TODO$|lib/.+(?<!ROADMAP)\.p(m|od)$|inc/|t/aggregate/.*\.t$|t/.*\.(gif|yml|pl|t)$|t/lib/.*\.pm$|t/something/(Makefile.PL|script/foo/bar/for_dist)$|t/conf/extra.conf.in$|Makefile.PL$|README$|MANIFEST$|Changes$|META.yml$)
+^(?!script/\w+\.pl$|TODO$|lib/.+(?<!ROADMAP)\.p(m|od)$|inc/|t/a(uthor|ggregate)/.*\.t$|t/.*\.(gif|yml|pl|t)$|t/lib/.*\.pm$|t/something/(Makefile.PL|script/foo/bar/for_dist)$|t/conf/extra.conf.in$|Makefile.PL$|README$|MANIFEST$|Changes$|META.yml$)
index 3cec6d5..6fae99a 100644 (file)
@@ -1,22 +1,30 @@
+use strict;
+use warnings;
 use inc::Module::Install 0.87;
-
-perl_version '5.008001';
+BEGIN { # Make it easy for newbies
+    if ($Module::Install::AUTHOR) {
+        require Module::Install::AuthorRequires;
+        require Module::Install::CheckConflicts;
+        require Module::Install::AuthorTests;
+    }
+}
+perl_version '5.008004';
 
 name 'Catalyst-Runtime';
 all_from 'lib/Catalyst/Runtime.pm';
 
+requires 'List::MoreUtils';
 requires 'namespace::autoclean';
 requires 'namespace::clean';
 requires 'B::Hooks::EndOfScope' => '0.08';
 requires 'MooseX::Emulate::Class::Accessor::Fast' => '0.00801';
 requires 'Class::MOP' => '0.83';
 requires 'Moose' => '0.78';
-requires 'MooseX::MethodAttributes::Inheritable' => '0.12';
+requires 'MooseX::MethodAttributes::Inheritable' => '0.15';
 requires 'Carp';
 requires 'Class::C3::Adopt::NEXT' => '0.07';
 requires 'CGI::Simple::Cookie';
 requires 'Data::Dump';
-requires 'File::Modified';
 requires 'HTML::Entities';
 requires 'HTTP::Body'    => '1.04'; # makes uploadtmp work
 requires 'HTTP::Headers' => '1.64';
@@ -24,7 +32,7 @@ requires 'HTTP::Request';
 requires 'HTTP::Response';
 requires 'HTTP::Request::AsCGI' => '0.8';
 requires 'LWP::UserAgent';
-requires 'Module::Pluggable' => '3.01';
+requires 'Module::Pluggable' => '3.9';
 requires 'Path::Class' => '0.09';
 requires 'Scalar::Util';
 requires 'Sub::Exporter';
@@ -54,6 +62,7 @@ else {
         map  { glob } qw[t/*.t t/aggregate/*.t];
 }
 
+author_tests 't/author';
 author_requires(map {; $_ => 0 } qw(
   Test::NoTabs
   Test::Pod
@@ -112,7 +121,7 @@ my %conflicts = (
     'Catalyst::Plugin::Upload::Image::Magick' => '0.03',
     'Catalyst::Plugin::ConfigLoader'   => '0.22', # Older versions work but
                                                   # throw Data::Visitor warns
-    'Catalyst::Devel'                  => '0.09',
+    'Catalyst::Devel'                  => '1.19',
     'Catalyst::Plugin::SmartURI'       => '0.032',
     'CatalystX::CRUD'                  => '0.37',
     'Catalyst::Action::RenderView'     => '0.07',
@@ -123,6 +132,7 @@ my %conflicts = (
     'Catalyst::Action::REST'           => '0.67',
     'CatalystX::CRUD'                  => '0.42',
     'CatalystX::CRUD::Model::RDBO'     => '0.20',
+    'Catalyst::View::Mason'            => '0.17',
 );
 check_conflicts(%conflicts);
 
@@ -135,7 +145,8 @@ sub darwin_check_no_resource_forks {
 
         # TAR on 10.4 wants COPY_EXTENDED_ATTRIBUTES_DISABLE
         # On 10.5 (Leopard) it wants COPYFILE_DISABLE
-        my $attr = $osx_ver eq '10.5' ? 'COPYFILE_DISABLE' : 'COPY_EXTENDED_ATTRIBUTES_DISABLE';
+        die("Oh, you got Snow Lepoard, snazzy. Please read the man page for tar to find out if Apple renamed COPYFILE_DISABLE again and fix this Makefile.PL please?\n") if $osx_ver =~ /^10.6/;
+        my $attr = $osx_ver =~ /^10.5/ ? 'COPYFILE_DISABLE' : 'COPY_EXTENDED_ATTRIBUTES_DISABLE';
 
         makemaker_args(dist => { PREOP => qq{\@if [ "\$\$$attr" != "true" ]; then}.
                                           qq{ echo "You must set the ENV variable $attr to true,"; }.
diff --git a/TODO b/TODO
index 7d34863..4a2b319 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,36 +1,62 @@
-Known Bugs:
+# Known Bugs:
 
    - Bug ->go or ->visit causes actions which have Args or CaptureArgs called
      twice when called via ->go or ->visit.
 
      Test app: http://github.com/bobtfish/catalyst-app-bug-go_chain/tree/master
 
-Compatibility warnings to add:
+   - Bricas' Exception blog post
 
-   - $self->config should warn as config should only ever be called as a
-     class method.
+     http://bricas.vox.com/library/post/catalyst-exceptionclass.html
 
-Proposed functionality / feature additions:
+     Broken by recent exception refactoring
 
-    - Log setup needs to be less lame, so Catalyst::Plugin::Log::* can die
-      in a fire. Having $c->log_class would be a good start. kane volunteered
-      to do some of this.
+# Compatibility warnings to add:
 
-      Simple example: Catalyst::Plugin::Log::Colorful should just be a
-      subclass of Catalyst::Log, no ::Plugin:: needed.
+  - $self->config should warn as config should only ever be called as a
+    class method (TESTS).
 
-      See also: Catalyst::Plugin::Log::Dispatch and
-      http://github.com/willert/catalyst-plugin-log4perl-simple/tree
+# Proposed functionality / feature additions:
 
-TODO for brach namespace_handling_refactor:
+## Log setup needs to be less lame
 
-- refactor code in
-  * Catalyst::Dispatcher::get_containers           # No Idea
-  * Catalyst::Dispatcher::dispatch_type            # DONE
+So Catalyst::Plugin::Log::* can die
+in a fire. Having $c->log_class would be a good start. kane volunteered
+to do some of this.
 
-  * Catalyst::Controller::_parse_ActionClass_attr  # DONE
-  * Catalyst::Dispatcher::_load_dispatch_types     # DONE
-  * Catalyst::setup_plugins                        # DONE
-  to use the same namespacing method
+Simple example: Catalyst::Plugin::Log::Colorful should just be a
+subclass of Catalyst::Log, no ::Plugin:: needed.
 
-- Ok, so can you add tests for ->config(actions => { foo => { ActionClass => '+Bar' }});
+See also: Catalyst::Plugin::Log::Dispatch and
+http://github.com/willert/catalyst-plugin-log4perl-simple/tree
+
+# REFACTORING
+
+##  The horrible hack for plugin setup - replacing it:
+
+ * Have a look at the Devel::REPL BEFORE_PLUGIN stuff
+   I wonder if what we need is that combined with plugins-as-roles
+
+## App / ctx split:
+
+  NOTE - these are notes that t0m thought up after doing back compat for
+         catalyst_component_class, may be inaccurate, wrong or missing things
+         bug mst (at least) to correct before trying more than the first 2
+         steps. Please knock yourself out on the first two however :)
+
+  - Eliminate actions in MyApp from the main test suite
+  - Uncomment warning in C::C::register_action_methods, add tests it works
+    by mocking out the logging..
+  - Remove MyApp @ISA controller (ask metaclass if it has attributes, and if
+                                  so you need back compat :/)
+  - Make Catalyst::Context, move the per request stuff in there, handles from
+    main app class to delegate
+  - Make an instance of the app class which is a global variable
+  - Make new instance of the context class, not the app class per-request
+  - Remove the components as class data, move to instance data on the app
+    class (you probably have to do this for _all_ the class data, good luck!)
+  - Make it possible for users to spin up different instances of the app class
+    (with different config etc each)
+  - Profit! (Things like changing the complete app config per vhost, i.e.
+    writing a config loader / app class role which dispatches per vhost to
+    differently configured apps is piss easy)
index 133c657..0f4f0ff 100644 (file)
@@ -27,11 +27,12 @@ use URI::https;
 use Tree::Simple qw/use_weak_refs/;
 use Tree::Simple::Visitor::FindByUID;
 use Class::C3::Adopt::NEXT;
+use List::MoreUtils qw/uniq/;
 use attributes;
 use utf8;
 use Carp qw/croak carp shortmess/;
 
-BEGIN { require 5.008001; }
+BEGIN { require 5.008004; }
 
 has stack => (is => 'ro', default => sub { [] });
 has stash => (is => 'rw', default => sub { {} });
@@ -78,7 +79,7 @@ __PACKAGE__->stats_class('Catalyst::Stats');
 
 # Remember to update this in Catalyst::Runtime as well!
 
-our $VERSION = '5.80007';
+our $VERSION = '5.80012';
 
 {
     my $dev_version = $VERSION =~ /_\d{2}$/;
@@ -335,9 +336,11 @@ call to forward.
     $c->forward(qw/MyApp::Model::DBIC::Foo do_stuff/);
     $c->forward('MyApp::View::TT');
 
-Note that forward implies an C<<eval { }>> around the call (actually
-C<execute> does), thus de-fatalizing all 'dies' within the called
-action. If you want C<die> to propagate you need to do something like:
+Note that L<< forward|/"$c->forward( $action [, \@arguments ] )" >> implies
+an C<< eval { } >> around the call (actually
+L<< execute|/"$c->execute( $class, $coderef )" >> does), thus de-fatalizing
+all 'dies' within the called action. If you want C<die> to propagate you
+need to do something like:
 
     $c->forward('foo');
     die $c->error if $c->error;
@@ -357,8 +360,8 @@ sub forward { my $c = shift; no warnings 'recursion'; $c->dispatcher->forward( $
 
 =head2 $c->detach()
 
-The same as C<forward>, but doesn't return to the previous action when
-processing is finished.
+The same as L<< forward|/"$c->forward( $action [, \@arguments ] )" >>, but
+doesn't return to the previous action when processing is finished.
 
 When called with no arguments it escapes the processing chain entirely.
 
@@ -370,23 +373,27 @@ sub detach { my $c = shift; $c->dispatcher->detach( $c, @_ ) }
 
 =head2 $c->visit( $class, $method, [, \@captures, \@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.
+Almost the same as L<< forward|/"$c->forward( $action [, \@arguments ] )" >>,
+but does a full dispatch, instead of just calling the new C<$action> /
+C<< $class->$method >>. This means that C<begin>, C<auto> and the method
+you go to are called, just like a new request.
 
 In addition both C<< $c->action >> and C<< $c->namespace >> are localized.
-This means, for example, that $c->action methods such as C<name>, C<class> and
-C<reverse> return information for the visited action when they are invoked
-within the visited action.  This is different from the behavior of C<forward>
-which continues to use the $c->action object from the caller action even when
+This means, for example, that C<< $c->action >> methods such as
+L<name|Catalyst::Action/name>, L<class|Catalyst::Action/class> and
+L<reverse|Catalyst::Action/reverse> return information for the visited action
+when they are invoked within the visited action.  This is different from the
+behavior of L<< forward|/"$c->forward( $action [, \@arguments ] )" >>, which
+continues to use the $c->action object from the caller action even when
 invoked from the callee.
 
-C<$c-E<gt>stash> is kept unchanged.
+C<< $c->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.
+In effect, L<< visit|/"$c->visit( $action [, \@captures, \@arguments ] )" >>
+allows you to "wrap" another action, just as it would have been called by
+dispatching from a URL, while the analogous
+L<< go|/"$c->go( $action [, \@captures, \@arguments ] )" >> allows you to
+transfer control to another action as if it had been reached directly from a URL.
 
 =cut
 
@@ -396,12 +403,15 @@ sub visit { my $c = shift; $c->dispatcher->visit( $c, @_ ) }
 
 =head2 $c->go( $class, $method, [, \@captures, \@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.
+The relationship between C<go> and 
+L<< visit|/"$c->visit( $action [, \@captures, \@arguments ] )" >> is the same as
+the relationship between 
+L<< forward|/"$c->forward( $class, $method, [, \@arguments ] )" >> and
+L<< detach|/"$c->detach( $action [, \@arguments ] )" >>. Like C<< $c->visit >>,
+C<< $c->go >> will perform a full dispatch on the specified action or method,
+with localized C<< $c->action >> and C<< $c->namespace >>. Like C<detach>,
+C<go> escapes the processing of the current request chain on completion, and
+does not return to its caller.
 
 =cut
 
@@ -639,7 +649,7 @@ 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;
     if( $name ) {
         my @result = $c->_comp_search_prefixes( $name, qw/Model M/ );
         return map { $c->_filter_component( $_, @args ) } @result if ref $name;
@@ -652,14 +662,14 @@ sub model {
         return $c->model( $c->stash->{current_model} )
           if $c->stash->{current_model};
     }
-    return $c->model( $c->config->{default_model} )
-      if $c->config->{default_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->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.' );
@@ -693,6 +703,7 @@ 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;
     if( $name ) {
         my @result = $c->_comp_search_prefixes( $name, qw/View V/ );
         return map { $c->_filter_component( $_, @args ) } @result if ref $name;
@@ -705,14 +716,14 @@ sub view {
         return $c->view( $c->stash->{current_view} )
           if $c->stash->{current_view};
     }
-    return $c->view( $c->config->{default_view} )
-      if $c->config->{default_view};
+    return $c->view( $appclass->config->{default_view} )
+      if $appclass->config->{default_view};
 
     my( $comp, $rest ) = $c->_comp_search_prefixes( undef, qw/View V/);
 
     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->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.' );
@@ -818,11 +829,11 @@ Returns or takes a hashref containing the application's configuration.
 
     __PACKAGE__->config( { db => 'dsn:SQLite:foo.db' } );
 
-You can also use a C<YAML>, C<XML> or C<Config::General> config file
-like myapp.conf in your applications home directory. See
+You can also use a C<YAML>, C<XML> or L<Config::General> config file
+like C<myapp.conf> in your applications home directory. See
 L<Catalyst::Plugin::ConfigLoader>.
 
-=head3 Cascading configuration.
+=head3 Cascading configuration
 
 The config method is present on all Catalyst components, and configuration
 will be merged when an application is started. Configuration loaded with
@@ -918,7 +929,7 @@ Returns the engine instance. See L<Catalyst::Engine>.
 Merges C<@path> with C<< $c->config->{home} >> and returns a
 L<Path::Class::Dir> object. Note you can usually use this object as
 a filename, but sometimes you will have to explicitly stringify it
-yourself by calling the C<<->stringify>> method.
+yourself by calling the C<< ->stringify >> method.
 
 For example:
 
@@ -1126,8 +1137,9 @@ EOF
                 . "Class::Accessor(::Fast)?\nPlease pass "
                 . "(replace_constructor => 1)\nwhen making your class immutable.\n";
         }
-        $meta->make_immutable(replace_constructor => 1)
-            unless $meta->is_immutable;
+        $meta->make_immutable(
+            replace_constructor => 1,
+        ) unless $meta->is_immutable;
     };
 
     $class->setup_finalize;
@@ -1158,36 +1170,54 @@ sub setup_finalize {
     $class->setup_finished(1);
 }
 
-=head2 $c->uri_for( $action, \@captures?, @args?, \%query_values? )
-
 =head2 $c->uri_for( $path, @args?, \%query_values? )
 
-=over
-
-=item $action
-
-A Catalyst::Action object representing the Catalyst action you want to
-create a URI for. To get one for an action in the current controller,
-use C<< $c->action('someactionname') >>. To get one from different
-controller, fetch the controller using C<< $c->controller() >>, then
-call C<action_for> on it.
-
-You can maintain the arguments captured by an action (e.g.: Regex, Chained)
-using C<< $c->req->captures >>.
+=head2 $c->uri_for( $action, \@captures?, @args?, \%query_values? )
 
-  # For the current action
-  $c->uri_for($c->action, $c->req->captures);
+Constructs an absolute L<URI> 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.
+
+If the first argument is a string, it is taken as a public URI path relative
+to C<< $c->namespace >> (if it doesn't begin with a forward slash) or
+relative to the application root (if it does). It is then merged with
+C<< $c->request->base >>; any C<@args> are appended as additional path
+components; and any C<%query_values> are appended as C<?foo=bar> parameters.
+
+If the first argument is a L<Catalyst::Action> it represents an action which
+will have its path resolved using C<< $c->dispatcher->uri_for_action >>. The
+optional C<\@captures> argument (an arrayref) allows passing the captured
+variables that are needed to fill in the paths of Chained and Regex actions;
+once the path is resolved, C<uri_for> continues as though a path was
+provided, appending any arguments or parameters and creating an absolute
+URI.
+
+The captures for the current request can be found in
+C<< $c->request->captures >>, and actions can be resolved using
+C<< Catalyst::Controller->action_for($name) >>. If you have a private action
+path, use C<< $c->uri_for_action >> instead.
+
+  # Equivalent to $c->req->uri
+  $c->uri_for($c->action, $c->req->captures,
+      @{ $c->req->args }, $c->req->params);
 
   # For the Foo action in the Bar controller
-  $c->uri_for($c->controller('Bar')->action_for('Foo'), $c->req->captures);
+  $c->uri_for($c->controller('Bar')->action_for('Foo'));
 
-=back
+  # Path to a static resource
+  $c->uri_for('/static/images/logo.png');
 
 =cut
 
 sub uri_for {
     my ( $c, $path, @args ) = @_;
 
+    if (blessed($path) && $path->isa('Catalyst::Controller')) {
+        $path = $path->path_prefix;
+        $path =~ s{/+\z}{};
+        $path .= '/';
+    }
+
     if ( blessed($path) ) { # action object
         my $captures = ( scalar @args && ref $args[0] eq 'ARRAY'
                          ? shift(@args)
@@ -1541,9 +1571,9 @@ sub execute {
 
 sub _stats_start_execute {
     my ( $c, $code ) = @_;
-
+    my $appclass = ref($c) || $c;
     return if ( ( $code->name =~ /^_.*/ )
-        && ( !$c->config->{show_internal_actions} ) );
+        && ( !$appclass->config->{show_internal_actions} ) );
 
     my $action_name = $code->reverse();
     $c->counter->{$action_name}++;
@@ -1606,25 +1636,6 @@ sub _stats_finish_execute {
     $c->stats->profile( end => $info );
 }
 
-=head2 $c->_localize_fields( sub { }, \%keys );
-
-=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 ) = ( @_ );
-
-    my $request = delete $localized->{request} || {};
-    my $response = delete $localized->{response} || {};
-
-    local @{ $c }{ keys %$localized } = values %$localized;
-    local @{ $c->request }{ keys %$request } = values %$request;
-    local @{ $c->response }{ keys %$response } = values %$response;
-
-    $code->();
-}
-
 =head2 $c->finalize
 
 Finalizes the request.
@@ -1876,7 +1887,7 @@ sub prepare {
         $c->prepare_read;
 
         # Parse the body unless the user wants it on-demand
-        unless ( $c->config->{parse_on_demand} ) {
+        unless ( ref($c)->config->{parse_on_demand} ) {
             $c->prepare_body;
         }
     }
@@ -2090,7 +2101,7 @@ Reads a chunk of data from the request body. This method is designed to
 be used in a while loop, reading C<$maxlength> bytes on every call.
 C<$maxlength> defaults to the size of the request if not specified.
 
-You have to set C<< MyApp->config->{parse_on_demand} >> to use this
+You have to set C<< MyApp->config(parse_on_demand => 1) >> to use this
 directly.
 
 Warning: If you use read(), Catalyst will not process the body,
@@ -2127,40 +2138,32 @@ sub setup_actions { my $c = shift; $c->dispatcher->setup_actions( $c, @_ ) }
 
 =head2 $c->setup_components
 
-Sets up components. 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.
+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.
 
-All components found will also have any
-L<Devel::InnerPackage|inner packages> loaded and set up as components.
-Note, that modules which are B<not> an I<inner package> of the main
-file namespace loaded will not be instantiated as components.
+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.
 
 =cut
 
 sub setup_components {
     my $class = shift;
 
-    my @paths   = qw( ::Controller ::C ::Model ::M ::View ::V );
     my $config  = $class->config->{ setup_components };
-    my $extra   = delete $config->{ search_extra } || [];
 
-    push @paths, @$extra;
-
-    my $locator = Module::Pluggable::Object->new(
-        search_path => [ map { s/^(?=::)/$class/; $_; } @paths ],
-        %$config
-    );
-
-    my @comps = sort { length $a <=> length $b } $locator->plugins;
+    my @comps = sort { length $a <=> length $b }
+                $class->locate_components($config);
     my %comps = map { $_ => 1 } @comps;
 
-    my $deprecated_component_names = grep { /::[CMV]::/ } @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 $deprecated_component_names;
+    ) if $deprecatedcatalyst_component_names;
 
     for my $component ( @comps ) {
 
@@ -2169,30 +2172,76 @@ 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 = (
-            $component => $module,
-            map {
-                $_ => $class->setup_component( $_ )
-            } grep {
-              not exists $comps{$_}
-            } Devel::InnerPackage::list_packages( $component )
-        );
 
-        for my $key ( keys %modules ) {
-            $class->components->{ $key } = $modules{ $key };
+        # 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);
+    }
+
+    for my $component (@comps) {
+        $class->components->{ $component } = $class->setup_component($component);
+        for my $component ($class->expand_component_module( $component, $config )) {
+            next if $comps{$component};
+            $class->_controller_init_base_classes($component); # Also cover inner packages
+            $class->components->{ $component } = $class->setup_component($component);
         }
     }
 }
 
+=head2 $c->locate_components( $setup_component_config )
+
+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>.
+
+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.
+
+=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 } || [];
+
+    push @paths, @$extra;
+
+    my $locator = Module::Pluggable::Object->new(
+        search_path => [ map { s/^(?=::)/$class/; $_; } @paths ],
+        %$config
+    );
+
+    my @comps = $locator->plugins;
+
+    return @comps;
+}
+
+=head2 $c->expand_component_module( $component, $setup_component_config )
+
+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.
+
+=cut
+
+sub expand_component_module {
+    my ($class, $module) = @_;
+    return Devel::InnerPackage::list_packages( $module );
+}
+
 =head2 $c->setup_component
 
 =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);
@@ -2206,16 +2255,12 @@ sub setup_component {
         return $component;
     }
 
-    # 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
-    if ($component->isa('Catalyst::Controller')) {
-        $class->_controller_init_base_classes($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;
 
     my $instance = eval { $component->COMPONENT( $class, $config ); };
 
@@ -2596,7 +2641,7 @@ Catalyst uses internal actions like C<_DISPATCH>, C<_BEGIN>, C<_AUTO>,
 C<_ACTION>, and C<_END>. These are by default not shown in the private
 action table, but you can make them visible with a config parameter.
 
-    MyApp->config->{show_internal_actions} = 1;
+    MyApp->config(show_internal_actions => 1);
 
 =head1 CASE SENSITIVITY
 
@@ -2604,7 +2649,7 @@ By default Catalyst is not case sensitive, so C<MyApp::C::FOO::Bar> is
 mapped to C</foo/bar>. You can activate case sensitivity with a config
 parameter.
 
-    MyApp->config->{case_sensitive} = 1;
+    MyApp->config(case_sensitive => 1);
 
 This causes C<MyApp::C::Foo::Bar> to map to C</Foo/Bar>.
 
@@ -2614,7 +2659,7 @@ The request body is usually parsed at the beginning of a request,
 but if you want to handle input yourself, you can enable on-demand
 parsing with a config parameter.
 
-    MyApp->config->{parse_on_demand} = 1;
+    MyApp->config(parse_on_demand => 1);
 
 =head1 PROXY SUPPORT
 
@@ -2635,6 +2680,18 @@ changes are made to the request.
     The host value for $c->req->base and $c->req->uri is set to the real
     host, as read from the HTTP X-Forwarded-Host header.
 
+Additionally, you may be running your backend application on an insecure
+connection (port 80) while your frontend proxy is running under SSL.  If there
+is a discrepancy in the ports, use the HTTP header C<X-Forwarded-Port> to
+tell Catalyst what port the frontend listens on.  This will allow all URIs to
+be created properly.
+
+In the case of passing in:
+
+    X-Forwarded-Port: 443
+
+All calls to C<uri_for> will result in an https link, as is expected.
+
 Obviously, your web server must support these headers for this to work.
 
 In a more complex server farm environment where you may have your
@@ -2642,11 +2699,11 @@ frontend proxy server(s) on different machines, you will need to set a
 configuration option to tell Catalyst to read the proxied data from the
 headers.
 
-    MyApp->config->{using_frontend_proxy} = 1;
+    MyApp->config(using_frontend_proxy => 1);
 
 If you do not wish to use the proxy support at all, you may set:
 
-    MyApp->config->{ignore_frontend_proxy} = 1;
+    MyApp->config(ignore_frontend_proxy => 1);
 
 =head1 THREAD SAFETY
 
@@ -2683,7 +2740,7 @@ Wiki:
 
 =head2 L<Catalyst::Manual> - The Catalyst Manual
 
-=head2 L<Catalyst::Component>, L<Catalyst::Base> - Base classes for components
+=head2 L<Catalyst::Component>, L<Catalyst::Controller> - Base classes for components
 
 =head2 L<Catalyst::Engine> - Core engine
 
@@ -2707,7 +2764,7 @@ acme: Leon Brocard <leon@astray.com>
 
 Andrew Bramble
 
-Andrew Ford
+Andrew Ford E<lt>A.Ford@ford-mason.co.ukE<gt>
 
 Andrew Ruthven
 
@@ -2723,6 +2780,14 @@ chansen: Christian Hansen
 
 chicks: Christopher Hicks
 
+Chisel Wright C<pause@herlpacker.co.uk>
+
+Danijel Milicevic C<me@danijel.de>
+
+David Kamholz E<lt>dkamholz@cpan.orgE<gt>
+
+David Naughton, C<naughton@umn.edu>
+
 David E. Wheeler
 
 dkubb: Dan Kubb <dan.kubb-cpan@onautopilot.com>
@@ -2735,16 +2800,26 @@ esskar: Sascha Kiefer
 
 fireartist: Carl Franks <cfranks@cpan.org>
 
+frew: Arthur Axel "fREW" Schmidt <frioux@gmail.com>
+
 gabb: Danijel Milicevic
 
 Gary Ashton Jones
 
+Gavin Henry C<ghenry@perl.me.uk>
+
 Geoff Richards
 
+groditi: Guillermo Roditi <groditi@gmail.com>
+
+hobbs: Andrew Rodland <andrew@cleverdomain.org>
+
 ilmari: Dagfinn Ilmari MannsÃ¥ker <ilmari@ilmari.org>
 
 jcamacho: Juan Camacho
 
+jester: Jesse Sheidlower C<jester@panix.com>
+
 jhannah: Jay Hannah <jay@jays.net>
 
 Jody Belka
@@ -2753,6 +2828,12 @@ Johan Lindstrom
 
 jon: Jon Schutz <jjschutz@cpan.org>
 
+Jonathan Rockway C<< <jrockway@cpan.org> >>
+
+Kieren Diment C<kd@totaldatasolution.com>
+
+konobi: Scott McWhirter <konobi@cpan.org>
+
 marcus: Marcus Ramberg <mramberg@cpan.org>
 
 miyagawa: Tatsuhiko Miyagawa <miyagawa@bulknews.net>
@@ -2781,16 +2862,22 @@ rafl: Florian Ragwitz <rafl@debian.org>
 
 random: Roland Lammel <lammel@cpan.org>
 
-sky: Arthur Bergman
+Robert Sedlacek C<< <rs@474.at> >>
 
-the_jester: Jesse Sheidlower
+sky: Arthur Bergman
 
 t0m: Tomas Doran <bobtfish@bobtfish.net>
 
 Ulf Edvinsson
 
+Viljo Marrandi C<vilts@yahoo.com>
+
+Will Hawes C<info@whawes.co.uk>
+
 willert: Sebastian Willert <willert@cpan.org>
 
+Yuval Kogman, C<nothingmuch@woobling.org>
+
 =head1 LICENSE
 
 This library is free software. You can redistribute it and/or modify it under
index cd2d008..87b37fd 100644 (file)
@@ -8,6 +8,8 @@ Catalyst::Action - Catalyst Action
 
     <form action="[%c.uri_for(c.action)%]">
 
+    $c->forward( $action->private_path );
+
 =head1 DESCRIPTION
 
 This class represents a Catalyst Action. You can access the object for the
@@ -28,6 +30,13 @@ has 'reverse' => (is => 'rw');
 has attributes => (is => 'rw');
 has name => (is => 'rw');
 has code => (is => 'rw');
+has private_path => (
+  reader => 'private_path',
+  isa => 'Str',
+  lazy => 1,
+  required => 1,
+  default => sub { '/'.shift->reverse },
+);
 
 use overload (
 
@@ -46,8 +55,6 @@ use overload (
 
 no warnings 'recursion';
 
-#__PACKAGE__->mk_accessors(qw/class namespace reverse attributes name code/);
-
 sub dispatch {    # Execute ourselves against a context
     my ( $self, $c ) = @_;
     return $c->execute( $self->class, $self );
@@ -75,7 +82,7 @@ sub compare {
     my ($a1_args) = @{ $a1->attributes->{Args} || [] };
     my ($a2_args) = @{ $a2->attributes->{Args} || [] };
 
-    $_ = looks_like_number($_) ? $_ : ~0 
+    $_ = looks_like_number($_) ? $_ : ~0
         for $a1_args, $a2_args;
 
     return $a1_args <=> $a2_args;
@@ -96,7 +103,9 @@ and so on. This determines how the action is dispatched to.
 
 =head2 class
 
-Returns the class name where this action is defined.
+Returns the name of the component where this action is defined.
+Derived by calling the L<Catalyst::Component/catalyst_component_name|catalyst_component_name>
+method on each component.
 
 =head2 code
 
@@ -104,7 +113,7 @@ Returns a code reference to this action.
 
 =head2 dispatch( $c )
 
-Dispatch this action against a context
+Dispatch this action against a context.
 
 =head2 execute( $controller, $c, @args )
 
@@ -129,13 +138,18 @@ Returns the private namespace this action lives in.
 
 Returns the private path for this action.
 
+=head2 private_path
+
+Returns absolute private path for this action. Unlike C<reverse>, the
+C<private_path> of an action is always suitable for passing to C<forward>.
+
 =head2 name
 
-returns the sub name of this action.
+Returns the sub name of this action.
 
 =head2 meta
 
-Provided by Moose
+Provided by Moose.
 
 =head1 AUTHORS
 
index f252f05..cd0ad90 100644 (file)
@@ -6,7 +6,7 @@ use Class::MOP;
 use Moose::Util ();
 
 sub mk_classdata {
-  my ($class, $attribute) = @_;
+  my ($class, $attribute, $warn_on_instance) = @_;
   confess("mk_classdata() is a class method, not an object method")
     if blessed $class;
 
@@ -49,13 +49,16 @@ sub mk_classdata {
     unless $meta->isa('Class::MOP::Class');
 
   my $was_immutable = $meta->is_immutable;
+  # Need to save immutable_options if they're available from Moose 0.89_02
+  my %immutable_options = $meta->can('immutable_options') ? $meta->immutable_options : ();
+
   $meta->make_mutable if $was_immutable;
 
   my $alias = "_${attribute}_accessor";
   $meta->add_method($alias, $accessor);
   $meta->add_method($attribute, $accessor);
 
-  $meta->make_immutable if $was_immutable;
+  $meta->make_immutable(%immutable_options) if $was_immutable;
 
   $class->$attribute($_[2]) if(@_ > 2);
   return $accessor;
index f0a6d60..fe0ef6f 100644 (file)
@@ -60,6 +60,18 @@ component loader with config() support and a process() method placeholder.
 __PACKAGE__->mk_classdata('_plugins');
 __PACKAGE__->mk_classdata('_config');
 
+has catalyst_component_name => ( is => 'ro' ); # Cannot be required => 1 as context
+                                       # class @ISA component - HATE
+# Make accessor callable as a class method, as we need to call setup_actions
+# on the application class, which we don't have an instance of, ewwwww
+# Also, naughty modules like Catalyst::View::JSON try to write to _everything_,
+# so spit a warning, ignore that (and try to do the right thing anyway) here..
+around catalyst_component_name => sub {
+    my ($orig, $self) = (shift, shift);
+    Carp::cluck("Tried to write to the catalyst_component_name accessor - is your component broken or just mad? (Write ignored - using default value.)") if scalar @_;
+    blessed($self) ? $self->$orig() || blessed($self) : $self;
+};
+
 sub BUILDARGS {
     my $class = shift;
     my $args = {};
@@ -85,23 +97,24 @@ sub BUILDARGS {
 }
 
 sub COMPONENT {
-    my ( $self, $c ) = @_;
+    my ( $class, $c ) = @_;
 
     # Temporary fix, some components does not pass context to constructor
     my $arguments = ( ref( $_[-1] ) eq 'HASH' ) ? $_[-1] : {};
-    if( my $next = $self->next::can ){
-      my $class = blessed $self || $self;
+    if ( my $next = $class->next::can ) {
       my ($next_package) = Class::MOP::get_code_info($next);
       warn "There is a COMPONENT method resolving after Catalyst::Component in ${next_package}.\n";
       warn "This behavior can no longer be supported, and so your application is probably broken.\n";
       warn "Your linearized isa hierarchy is: " . join(', ', @{ mro::get_linear_isa($class) }) . "\n";
       warn "Please see perldoc Catalyst::Upgrading for more information about this issue.\n";
     }
-    return $self->new($c, $arguments);
+    return $class->new($c, $arguments);
 }
 
 sub config {
     my $self = shift;
+    # Uncomment once sane to do so
+    #Carp::cluck("config method called on instance") if ref $self;
     my $config = $self->_config || {};
     if (@_) {
         my $newconfig = { %{@_ > 1 ? {@_} : $_[0]} };
@@ -157,9 +170,10 @@ If this method is present (as it is on all Catalyst::Component subclasses,
 it is called by Catalyst during setup_components with the application class
 as $c and any config entry on the application for this component (for example,
 in the case of MyApp::Controller::Foo this would be
-MyApp->config->{'Controller::Foo'}). The arguments are expected to be a
-hashref and are merged with the __PACKAGE__->config hashref before calling
-->new to instantiate the component.
+C<< MyApp->config('Controller::Foo' => \%conf >>).
+The arguments are expected to be a hashref and are merged with the
+C<< __PACKAGE__->config >> hashref before calling C<< ->new >>
+to instantiate the component.
 
 You can override it in your components to do custom instantiation, using
 something like this:
index aca0b1c..1d91b3c 100644 (file)
@@ -2,7 +2,7 @@ package Catalyst::Controller;
 
 use Moose;
 use Moose::Util qw/find_meta/;
-
+use List::MoreUtils qw/uniq/;
 use namespace::clean -except => 'meta';
 
 BEGIN { extends qw/Catalyst::Component MooseX::MethodAttributes::Inheritable/; }
@@ -29,9 +29,9 @@ has action_namespace =>
      predicate => 'has_action_namespace',
     );
 
-has _controller_actions =>
+has actions =>
     (
-     is => 'rw',
+     accessor => '_controller_actions',
      isa => 'HashRef',
      init_arg => undef,
     );
@@ -44,6 +44,8 @@ sub BUILD {
     $self->_controller_actions($attr_value);
 }
 
+
+
 =head1 NAME
 
 Catalyst::Controller - Catalyst Controller base class
@@ -135,28 +137,30 @@ around action_namespace => sub {
     my $orig = shift;
     my ( $self, $c ) = @_;
 
+    my $class = ref($self) || $self;
+    my $appclass = ref($c) || $c;
     if( ref($self) ){
         return $self->$orig if $self->has_action_namespace;
     } else {
-        return $self->config->{namespace} if exists $self->config->{namespace};
+        return $class->config->{namespace} if exists $class->config->{namespace};
     }
 
     my $case_s;
     if( $c ){
-        $case_s = $c->config->{case_sensitive};
+        $case_s = $appclass->config->{case_sensitive};
     } else {
         if ($self->isa('Catalyst')) {
-            $case_s = $self->config->{case_sensitive};
+            $case_s = $class->config->{case_sensitive};
         } else {
             if (ref $self) {
-                $case_s = $self->_application->config->{case_sensitive};
+                $case_s = ref($self->_application)->config->{case_sensitive};
             } else {
                 confess("Can't figure out case_sensitive setting");
             }
         }
     }
 
-    my $namespace = Catalyst::Utils::class2prefix(ref($self) || $self, $case_s) || '';
+    my $namespace = Catalyst::Utils::class2prefix($self->catalyst_component_name, $case_s) || '';
     $self->$orig($namespace) if ref($self);
     return $namespace;
 };
@@ -177,8 +181,8 @@ around path_prefix => sub {
 
 sub get_action_methods {
     my $self = shift;
-    my $meta = find_meta($self);
-    confess("Metaclass for "
+    my $meta = find_meta($self) || confess("No metaclass setup for $self");
+    confess("Metaclass "
           . ref($meta) . " for "
           . $meta->name
           . " cannot support register_actions." )
@@ -190,13 +194,13 @@ sub get_action_methods {
         @methods,
         map {
             $meta->find_method_by_name($_)
-              || confess( 'Action "' 
+              || confess( 'Action "'
                   . $_
                   . '" is not available from controller '
                   . ( ref $self ) )
           } keys %{ $self->_controller_actions }
     ) if ( ref $self );
-    return @methods;
+    return uniq @methods;
 }
 
 
@@ -207,10 +211,18 @@ sub register_actions {
 
 sub register_action_methods {
     my ( $self, $c, @methods ) = @_;
-    my $class = ref $self || $self;
+    my $class = $self->catalyst_component_name;
     #this is still not correct for some reason.
     my $namespace = $self->action_namespace($c);
 
+    # FIXME - fugly
+    if (!blessed($self) && $self eq $c && scalar(@methods)) {
+        my @really_bad_methods = grep { ! /^_(DISPATCH|BEGIN|AUTO|ACTION|END)$/ } map { $_->name } @methods;
+        if (scalar(@really_bad_methods)) {
+            $c->log->warn("Action methods (" . join(', ', @really_bad_methods) . ") found defined in your application class, $self. This is deprecated, please move them into a Root controller.");
+        }
+    }
+
     foreach my $method (@methods) {
         my $name = $method->name;
         my $attributes = $method->attributes;
index 890961d..3654a11 100644 (file)
@@ -80,14 +80,16 @@ sub list {
 
     return unless $self->_endpoints;
 
-    my $column_width = Catalyst::Utils::term_width() - 35 - 9;
+    my $avail_width = Catalyst::Utils::term_width() - 9;
+    my $col1_width = ($avail_width * .50) < 35 ? 35 : int($avail_width * .50);
+    my $col2_width = $avail_width - $col1_width;
     my $paths = Text::SimpleTable->new(
-       [ 35, 'Path Spec' ], [ $column_width, 'Private' ],
+        [ $col1_width, 'Path Spec' ], [ $col2_width, 'Private' ],
     );
 
     my $has_unattached_actions;
     my $unattached_actions = Text::SimpleTable->new(
-        [ 35, 'Private' ], [ $column_width, 'Missing parent' ],
+        [ $col1_width, 'Private' ], [ $col2_width, 'Missing parent' ],
     );
 
     ENDPOINT: foreach my $endpoint (
index 95367ac..545e607 100644 (file)
@@ -47,9 +47,11 @@ Debug output for Path dispatch points
 
 sub list {
     my ( $self, $c ) = @_;
-    my $column_width = Catalyst::Utils::term_width() - 35 - 9;
+    my $avail_width = Catalyst::Utils::term_width() - 9;
+    my $col1_width = ($avail_width * .50) < 35 ? 35 : int($avail_width * .50);
+    my $col2_width = $avail_width - $col1_width;
     my $paths = Text::SimpleTable->new(
-       [ 35, 'Path' ], [ $column_width, 'Private' ]
+       [ $col1_width, 'Path' ], [ $col2_width, 'Private' ]
     );
     foreach my $path ( sort keys %{ $self->_paths } ) {
         my $display_path = $path eq '/' ? $path : "/$path";
index 11a9cbf..0d6da04 100644 (file)
@@ -47,8 +47,12 @@ Output a table of all regex actions, and their private equivalent.
 
 sub list {
     my ( $self, $c ) = @_;
-    my $column_width = Catalyst::Utils::term_width() - 35 - 9;
-    my $re = Text::SimpleTable->new( [ 35, 'Regex' ], [ $column_width, 'Private' ] );
+    my $avail_width = Catalyst::Utils::term_width() - 9;
+    my $col1_width = ($avail_width * .50) < 35 ? 35 : int($avail_width * .50);
+    my $col2_width = $avail_width - $col1_width;
+    my $re = Text::SimpleTable->new(
+        [ $col1_width, 'Regex' ], [ $col2_width, 'Private' ]
+    );
     for my $regex ( @{ $self->_compiled } ) {
         my $action = $regex->{action};
         $re->row( $regex->{path}, "/$action" );
index ec62c1f..3d6573b 100644 (file)
@@ -335,7 +335,7 @@ sub _invoke_as_component {
                 reverse   => "$component_class->$method",
                 class     => $component_class,
                 namespace => Catalyst::Utils::class2prefix(
-                    $component_class, $c->config->{case_sensitive}
+                    $component_class, ref($c)->config->{case_sensitive}
                 ),
             }
         );
@@ -615,9 +615,12 @@ sub setup_actions {
 sub _display_action_tables {
     my ($self, $c) = @_;
 
-    my $column_width = Catalyst::Utils::term_width() - 20 - 36 - 12;
+    my $avail_width = Catalyst::Utils::term_width() - 12;
+    my $col1_width = ($avail_width * .25) < 20 ? 20 : int($avail_width * .25);
+    my $col2_width = ($avail_width * .50) < 36 ? 36 : int($avail_width * .50);
+    my $col3_width =  $avail_width - $col1_width - $col2_width;
     my $privates = Text::SimpleTable->new(
-        [ 20, 'Private' ], [ 36, 'Class' ], [ $column_width, 'Method' ]
+        [ $col1_width, 'Private' ], [ $col2_width, 'Class' ], [ $col3_width, 'Method' ]
     );
 
     my $has_private = 0;
@@ -655,7 +658,7 @@ sub _load_dispatch_types {
     for my $type (@types) {
         # first param is undef because we cannot get the appclass
         my $class = Catalyst::Utils::resolve_namespace(undef, 'Catalyst::DispatchType', $type);
-        
+
         eval { Class::MOP::load_class($class) };
         Catalyst::Exception->throw( message => qq/Couldn't load "$class"/ )
           if $@;
@@ -694,10 +697,26 @@ use Moose;
 # Various plugins (e.g. Plugin::Server and Plugin::Authorization::ACL)
 # need the methods here which *should* be private..
 
-# However we can't really take them away until there is a sane API for
-# building actions and configuring / introspecting the dispatcher.
-# In 5.90, we should build that infrastructure, port the plugins which
-# use it, and then take the crap below away.
+# You should be able to use get_actions or get_containers appropriately
+# instead of relying on these methods which expose implementation details
+# of the dispatcher..
+#
+# IRC backlog included below, please come ask if this doesn't work for you.
+#
+# <@t0m> 5.80, the state of. There are things in the dispatcher which have
+#        been deprecated, that we yell at anyone for using, which there isn't
+#        a good alternative for yet..
+# <@mst> er, get_actions/get_containers provides that doesn't it?
+# <@mst> DispatchTypes are loaded on demand anyway
+# <@t0m> I'm thinking of things like _tree which is aliased to 'tree' with
+#        warnings otherwise shit breaks.. We're issuing warnings about the
+#        correct set of things which you shouldn't be calling..
+# <@mst> right
+# <@mst> basically, I don't see there's a need for a replacement for anything
+# <@mst> it was never a good idea to call ->tree
+# <@mst> nothingmuch was the only one who did AFAIK
+# <@mst> and he admitted it was a hack ;)
+
 # See also t/lib/TestApp/Plugin/AddDispatchTypes.pm
 
 # Alias _method_name to method_name, add a before modifier to warn..
index b9ec98a..443975e 100644 (file)
@@ -48,10 +48,12 @@ sub finalize_body {
     my $body = $c->response->body;
     no warnings 'uninitialized';
     if ( blessed($body) && $body->can('read') or ref($body) eq 'GLOB' ) {
-        while ( !eof $body ) {
-            read $body, my ($buffer), $CHUNKSIZE;
-            last unless $self->write( $c, $buffer );
-        }
+        my $got;
+        do {
+            $got = read $body, my ($buffer), $CHUNKSIZE;
+            $got = 0 unless $self->write( $c, $buffer );
+        } while $got > 0;
+
         close $body;
     }
     else {
@@ -110,7 +112,7 @@ sub finalize_error {
     my ( $self, $c ) = @_;
 
     $c->res->content_type('text/html; charset=utf-8');
-    my $name = $c->config->{name} || join(' ', split('::', ref $c));
+    my $name = ref($c)->config->{name} || join(' ', split('::', ref $c));
 
     my ( $title, $error, $infos );
     if ( $c->debug ) {
@@ -315,13 +317,14 @@ sets up the L<Catalyst::Request> object body using L<HTTP::Body>
 sub prepare_body {
     my ( $self, $c ) = @_;
 
+    my $appclass = ref($c) || $c;
     if ( my $length = $self->read_length ) {
         my $request = $c->request;
         unless ( $request->_body ) {
             my $type = $request->header('Content-Type');
             $request->_body(HTTP::Body->new( $type, $length ));
-            $request->_body->tmpdir( $c->config->{uploadtmp} )
-              if exists $c->config->{uploadtmp};
+            $request->_body->tmpdir( $appclass->config->{uploadtmp} )
+              if exists $appclass->config->{uploadtmp};
         }
 
         while ( my $buffer = $self->read($c) ) {
index 48dc201..8416e09 100644 (file)
@@ -57,9 +57,9 @@ sub prepare_connection {
 
   PROXY_CHECK:
     {
-        unless ( $c->config->{using_frontend_proxy} ) {
+        unless ( ref($c)->config->{using_frontend_proxy} ) {
             last PROXY_CHECK if $ENV{REMOTE_ADDR} ne '127.0.0.1';
-            last PROXY_CHECK if $c->config->{ignore_frontend_proxy};
+            last PROXY_CHECK if ref($c)->config->{ignore_frontend_proxy};
         }
         last PROXY_CHECK unless $ENV{HTTP_X_FORWARDED_FOR};
 
@@ -67,6 +67,9 @@ sub prepare_connection {
         # as 127.0.0.1. Select the most recent upstream IP (last in the list)
         my ($ip) = $ENV{HTTP_X_FORWARDED_FOR} =~ /([^,\s]+)$/;
         $request->address($ip);
+        if ( defined $ENV{HTTP_X_FORWARDED_PORT} ) {
+            $ENV{SERVER_PORT} = $ENV{HTTP_X_FORWARDED_PORT};
+        }
     }
 
     $request->hostname( $ENV{REMOTE_HOST} ) if exists $ENV{REMOTE_HOST};
@@ -123,9 +126,9 @@ sub prepare_path {
     # If we are running as a backend proxy, get the true hostname
   PROXY_CHECK:
     {
-        unless ( $c->config->{using_frontend_proxy} ) {
+        unless ( ref($c)->config->{using_frontend_proxy} ) {
             last PROXY_CHECK if $host !~ /localhost|127.0.0.1/;
-            last PROXY_CHECK if $c->config->{ignore_frontend_proxy};
+            last PROXY_CHECK if ref($c)->config->{ignore_frontend_proxy};
         }
         last PROXY_CHECK unless $ENV{HTTP_X_FORWARDED_HOST};
 
@@ -134,6 +137,9 @@ sub prepare_path {
         # backend could be on any port, so
         # assume frontend is on the default port
         $port = $c->request->secure ? 443 : 80;
+        if ( $ENV{HTTP_X_FORWARDED_PORT} ) {
+            $port = $ENV{HTTP_X_FORWARDED_PORT};
+        }
     }
 
     # set the request URI
index 125a762..280fee1 100644 (file)
@@ -235,7 +235,7 @@ sub _fix_env
         $env->{PATH_INFO} ||= delete $env->{SCRIPT_NAME};
     }
     # Fix the environment variables PATH_INFO and SCRIPT_NAME when running under IIS
-    elsif ( $env->{SERVER_SOFTWARE} =~ /IIS\/[67].0/ ) {
+    elsif ( $env->{SERVER_SOFTWARE} =~ /IIS\/[6-9]\.[0-9]/ ) {
         my @script_name = split(m!/!, $env->{PATH_INFO});
         my @path_translated = split(m!/|\\\\?!, $env->{PATH_TRANSLATED});
         my @path_info;
index d58e508..62c5d0b 100644 (file)
@@ -12,10 +12,6 @@ use Socket;
 use IO::Socket::INET ();
 use IO::Select       ();
 
-# For PAR
-require Catalyst::Engine::HTTP::Restarter;
-require Catalyst::Engine::HTTP::Restarter::Watcher;
-
 use constant CHUNKSIZE => 64 * 1024;
 use constant DEBUG     => $ENV{CATALYST_HTTP_DEBUG} || 0;
 
@@ -158,11 +154,16 @@ around write => sub {
 
     # Prepend the headers if they have not yet been sent
     if ( $self->_has_header_buf ) {
-        $buffer = $self->_clear_header_buf . $buffer;
+        $self->_warn_on_write_error(
+            $self->$orig($c, $self->_clear_header_buf)
+        );
     }
 
-    my $ret = $self->$orig($c, $buffer);
+    $self->_warn_on_write_error($self->$orig($c, $buffer));
+};
 
+sub _warn_on_write_error {
+    my ($self, $ret) = @_;
     if ( !defined $ret ) {
         $self->_write_error($!);
         DEBUG && warn "write: Failed to write response ($!)\n";
@@ -170,9 +171,8 @@ around write => sub {
     else {
         DEBUG && warn "write: Wrote response ($ret bytes)\n";
     }
-
     return $ret;
-};
+}
 
 =head2 run
 
@@ -364,6 +364,9 @@ sub _handler {
     while (1) {
         my ( $path, $query_string ) = split /\?/, $uri, 2;
 
+        # URI is not the same as path. Remove scheme, domain name and port from it
+        $path =~ s{^https?://[^/?#]+}{};
+
         # Initialize CGI environment
         local %ENV = (
             PATH_INFO       => $path         || '',
diff --git a/lib/Catalyst/Engine/HTTP/Restarter.pm b/lib/Catalyst/Engine/HTTP/Restarter.pm
deleted file mode 100644 (file)
index dfb414c..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-package Catalyst::Engine::HTTP::Restarter;
-use Moose;
-use Moose::Util qw/find_meta/;
-use namespace::clean -except => 'meta';
-
-extends 'Catalyst::Engine::HTTP';
-
-use Catalyst::Engine::HTTP::Restarter::Watcher;
-
-around run => sub {
-    my $orig = shift;
-    my ( $self, $class, $port, $host, $options ) = @_;
-
-    $options ||= {};
-
-    # Setup restarter
-    unless ( my $restarter = fork ) {
-
-        # Prepare
-        close STDIN;
-        close STDOUT;
-
-        # Avoid "Setting config after setup" error restarting MyApp.pm
-        $class->setup_finished(0);
-        # Best effort if we can't trap compiles..
-        $self->_make_components_mutable($class)
-            if !Catalyst::Engine::HTTP::Restarter::Watcher::DETECT_PACKAGE_COMPILATION;
-
-        my $watcher = Catalyst::Engine::HTTP::Restarter::Watcher->new(
-            directory => (
-                $options->{restart_directory} ||
-                File::Spec->catdir( $FindBin::Bin, '..' )
-            ),
-            follow_symlinks => $options->{follow_symlinks},
-            regex     => $options->{restart_regex},
-            delay     => $options->{restart_delay},
-        );
-
-        $host ||= '127.0.0.1';
-        while (1) {
-
-            # poll for changed files
-            my @changed_files = $watcher->watch();
-
-            # check if our parent process has died
-            exit if $^O ne 'MSWin32' and getppid == 1;
-
-            # Restart if any files have changed
-            if (@changed_files) {
-                my $files = join ', ', @changed_files;
-                print STDERR qq/File(s) "$files" modified, restarting\n\n/;
-
-                require IO::Socket::INET;
-                require HTTP::Headers;
-                require HTTP::Request;
-
-                my $client = IO::Socket::INET->new(
-                    PeerAddr => $host,
-                    PeerPort => $port
-                  )
-                  or die "Can't create client socket (is server running?): ",
-                  $!;
-
-                # build the Kill request
-                my $req =
-                  HTTP::Request->new( 'RESTART', '/',
-                    HTTP::Headers->new( 'Connection' => 'close' ) );
-                $req->protocol('HTTP/1.0');
-
-                $client->send( $req->as_string )
-                  or die "Can't send restart instruction: ", $!;
-                $client->close();
-                exit;
-            }
-        }
-    }
-
-    return $self->$orig( $class, $port, $host, $options );
-};
-
-# Naive way of trying to avoid Moose blowing up when you re-require components
-# which have been made immutable.
-sub _make_components_mutable {
-    my ($self, $class) = @_;
-
-    my @metas = grep { defined($_) }
-                map { find_meta($_) }
-                ($class, map { blessed($_) }
-                values %{ $class->components });
-
-    foreach my $meta (@metas) {
-        # Paranoia unneeded, all component metaclasses should have immutable
-        $meta->make_mutable if $meta->is_immutable;
-    }
-}
-
-1;
-__END__
-
-=head1 NAME
-
-Catalyst::Engine::HTTP::Restarter - Catalyst Auto-Restarting HTTP Engine
-
-=head1 SYNOPSIS
-
-    script/myapp_server.pl -restart
-
-=head1 DESCRIPTION
-
-The Restarter engine will monitor files in your application for changes
-and restart the server when any changes are detected.
-
-=head1 METHODS
-
-=head2 run
-
-=head1 SEE ALSO
-
-L<Catalyst>, L<Catalyst::Engine::HTTP>, L<Catalyst::Engine::CGI>,
-L<Catalyst::Engine>.
-
-=head1 AUTHORS
-
-Catalyst Contributors, see Catalyst.pm
-
-=head1 THANKS
-
-Many parts are ripped out of C<HTTP::Server::Simple> by Jesse Vincent.
-
-=head1 COPYRIGHT
-
-This library is free software. You can redistribute it and/or modify it under
-the same terms as Perl itself.
-
-=cut
diff --git a/lib/Catalyst/Engine/HTTP/Restarter/Watcher.pm b/lib/Catalyst/Engine/HTTP/Restarter/Watcher.pm
deleted file mode 100644 (file)
index 8890646..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-package Catalyst::Engine::HTTP::Restarter::Watcher;
-
-use Moose;
-with 'MooseX::Emulate::Class::Accessor::Fast';
-
-use File::Find;
-use File::Modified;
-use File::Spec;
-use Time::HiRes qw/sleep/;
-use Moose::Util qw/find_meta/;
-use namespace::clean -except => 'meta';
-
-BEGIN {
-    # If we can detect stash changes, then we do magic
-    # to make their metaclass mutable (if they have one)
-    # so that restarting works as expected.
-    eval { require B::Hooks::OP::Check::StashChange; };
-    *DETECT_PACKAGE_COMPILATION = $@
-        ? sub () { 0 }
-        : sub () { 1 }
-}
-
-has delay => (is => 'rw');
-has regex => (is => 'rw');
-has modified => (is => 'rw', builder => '_build_modified', lazy => 1);
-has directory => (is => 'rw');
-has watch_list => (is => 'rw', builder => '_build_watch_list', lazy => 1);
-has follow_symlinks => (is => 'rw');
-
-sub _build_watch_list {
-    my ($self) = @_;
-    return $self->_index_directory;
-}
-
-sub _build_modified {
-    my ($self) = @_;
-    return File::Modified->new(
-        method => 'mtime',
-        files  => [ keys %{ $self->watch_list } ],
-    );
-}
-
-sub watch {
-    my $self = shift;
-
-    my @changes;
-    my @changed_files;
-
-    my $delay = ( defined $self->delay ) ? $self->delay : 1;
-
-    sleep $delay if $delay > 0;
-
-    eval { @changes = $self->modified->changed };
-    if ($@) {
-
-        # File::Modified will die if a file is deleted.
-        my ($deleted_file) = $@ =~ /stat '(.+)'/;
-        push @changed_files, $deleted_file || 'unknown file';
-    }
-
-    if (@changes) {
-
-        # update all mtime information
-        $self->modified->update;
-
-        # check if any files were changed
-        @changed_files = grep { -f $_ } @changes;
-
-        # Check if only directories were changed.  This means
-        # a new file was created.
-        unless (@changed_files) {
-
-            # re-index to find new files
-            my $new_watch = $self->_index_directory;
-
-            # look through the new list for new files
-            my $old_watch = $self->watch_list;
-            @changed_files = grep { !defined $old_watch->{$_} }
-              keys %{$new_watch};
-
-            return unless @changed_files;
-        }
-
-        # Test modified pm's
-        for my $file (@changed_files) {
-            next unless $file =~ /\.pm$/;
-            if ( my $error = $self->_test($file) ) {
-                print STDERR qq/File "$file" modified, not restarting\n\n/;
-                print STDERR '*' x 80, "\n";
-                print STDERR $error;
-                print STDERR '*' x 80, "\n";
-                return;
-            }
-        }
-    }
-
-    return @changed_files;
-}
-
-sub _index_directory {
-    my $self = shift;
-
-    my $dir   = $self->directory;
-    die "No directory specified" if !$dir or ref($dir) && !@{$dir};
-
-    my $regex = $self->regex     || '\.pm$';
-    my %list;
-
-    finddepth(
-        {
-            wanted => sub {
-                my $file = File::Spec->rel2abs($File::Find::name);
-                return unless $file =~ /$regex/;
-                return unless -f $file;
-                $file =~ s{/script/..}{};
-                $list{$file} = 1;
-
-                # also watch the directory for changes
-                my $cur_dir = File::Spec->rel2abs($File::Find::dir);
-                $cur_dir =~ s{/script/..}{};
-                $list{$cur_dir} = 1;
-            },
-            follow_fast => $self->follow_symlinks ? 1 : 0,
-            no_chdir => 1
-        },
-        ref $dir eq 'ARRAY' ? @{$dir} : $dir
-    );
-    return \%list;
-}
-
-sub _test {
-    my ( $self, $file ) = @_;
-
-    my $id;
-    if (DETECT_PACKAGE_COMPILATION) {
-        $id = B::Hooks::OP::Check::StashChange::register(sub {
-            my ($new, $old) = @_;
-            my $meta = find_meta($new);
-            if ($meta) { # A little paranoia here - Moose::Meta::Role has neither of these methods.
-                my $is_immutable = $meta->can('is_immutable');
-                my $make_mutable = $meta->can('make_mutable');
-                $meta->$make_mutable() if $is_immutable && $make_mutable && $meta->$is_immutable();
-                eval { # Do not explode the watcher process if this fails.
-                    my $superclasses = $meta->can('superclasses');
-                    $meta->$superclasses('Moose::Object') if $superclasses;
-                };
-            }
-        });
-    }
-
-    local $Catalyst::__AM_RESTARTING = 1; # Hack to avoid C3 fail
-    delete $INC{$file}; # Remove from %INC so it will reload
-    local $SIG{__WARN__} = sub { };
-
-    open my $olderr, '>&STDERR';
-    open STDERR, '>', File::Spec->devnull;
-    eval "require '$file'";
-    open STDERR, '>&', $olderr;
-
-    B::Hooks::OP::Check::StashChange::unregister($id) if $id;
-
-    return ($@) ? $@ : 0;
-}
-
-1;
-__END__
-
-=head1 NAME
-
-Catalyst::Engine::HTTP::Restarter::Watcher - Watch for changed application
-files
-
-=head1 SYNOPSIS
-
-    my $watcher = Catalyst::Engine::HTTP::Restarter::Watcher->new(
-        directory => '/path/to/MyApp',
-        regex     => '\.yml$|\.yaml$|\.conf|\.pm$',
-        delay     => 1,
-    );
-
-    while (1) {
-        my @changed_files = $watcher->watch();
-    }
-
-=head1 DESCRIPTION
-
-This class monitors a directory of files for changes made to any file
-matching a regular expression.  It correctly handles new files added to the
-application as well as files that are deleted.
-
-=head1 METHODS
-
-=head2 new ( directory => $path [, regex => $regex, delay => $delay ] )
-
-Creates a new Watcher object.
-
-=head2 watch
-
-Returns a list of files that have been added, deleted, or changed since the
-last time watch was called.
-
-=head2 DETECT_PACKAGE_COMPILATION
-
-Returns true if L<B::Hooks::OP::Check::StashChange> is installed and
-can be used to detect when files are compiled. This is used internally
-to make the L<Moose> metaclass of any class being reloaded immutable.
-
-If L<B::Hooks::OP::Check::StashChange> is not installed, then the
-restarter makes all application components immutable. This covers the
-simple case, but is less useful if you're using Moose in components
-outside Catalyst's namespaces, but inside your application directory.
-
-=head1 SEE ALSO
-
-L<Catalyst>, L<Catalyst::Engine::HTTP::Restarter>, L<File::Modified>
-
-=head1 AUTHORS
-
-Catalyst Contributors, see Catalyst.pm
-
-=head1 THANKS
-
-Many parts are ripped out of C<HTTP::Server::Simple> by Jesse Vincent.
-
-=head1 COPYRIGHT
-
-This library is free software. You can redistribute it and/or modify it under
-the same terms as Perl itself.
-
-=cut
index b16e59a..3383fc6 100644 (file)
@@ -223,7 +223,7 @@ Arguments get automatically URI-unescaped for you.
 
 =head2 $req->args
 
-Shortcut for arguments.
+Shortcut for L</arguments>.
 
 =head2 $req->base
 
@@ -237,8 +237,9 @@ C<http://localhost:3000/some/path> then C<base> is C<http://localhost:3000/>.
 
 =head2 $req->body
 
-Returns the message body of the request, unless Content-Type is
-C<application/x-www-form-urlencoded> or C<multipart/form-data>.
+Returns the message body of the request, as returned by L<HTTP::Body>: a string,
+unless Content-Type is C<application/x-www-form-urlencoded>, C<text/xml>, or
+C<multipart/form-data>, in which case a L<File::Temp> object is returned.
 
 =head2 $req->body_parameters
 
@@ -300,7 +301,7 @@ Returns a reference to a hash containing the cookies.
 
     print $c->request->cookies->{mycookie}->value;
 
-The cookies in the hash are indexed by name, and the values are L<CGI::Cookie>
+The cookies in the hash are indexed by name, and the values are L<CGI::Simple::Cookie>
 objects.
 
 =head2 $req->header
@@ -473,7 +474,7 @@ Reads a chunk of data from the request body. This method is intended to be
 used in a while loop, reading $maxlength bytes on every call. $maxlength
 defaults to the size of the request if not specified.
 
-You have to set MyApp->config->{parse_on_demand} to use this directly.
+You have to set MyApp->config(parse_on_demand => 1) to use this directly.
 
 =head2 $req->referer
 
@@ -649,7 +650,7 @@ You may also pass an optional second parameter that puts C<uri_with> into
 append mode:
 
   $req->uri_with( { key => 'value' }, { mode => 'append' } );
-  
+
 See C<mangle_params> for an explanation of this behavior.
 
 =cut
index 595decb..cb73a34 100644 (file)
@@ -102,11 +102,11 @@ it found, while L<Catalyst::View::TT> defaults to C<text/html>.
 
 Returns a reference to a hash containing cookies to be set. The keys of the
 hash are the cookies' names, and their corresponding values are hash
-references used to construct a L<CGI::Cookie> object.
+references used to construct a L<CGI::Simple::Cookie> object.
 
     $c->response->cookies->{foo} = { value => '123' };
 
-The keys of the hash reference on the right correspond to the L<CGI::Cookie>
+The keys of the hash reference on the right correspond to the L<CGI::Simple::Cookie>
 parameters of the same name, except they are used without a leading dash.
 Possible parameters are:
 
index 271d7a5..2cf1bd3 100644 (file)
@@ -3,11 +3,11 @@ package Catalyst::Runtime;
 use strict;
 use warnings;
 
-BEGIN { require 5.008001; }
+BEGIN { require 5.008004; }
 
 # Remember to update this in Catalyst as well!
 
-our $VERSION='5.80007';
+our $VERSION='5.80012';
 
 $VERSION = eval $VERSION;
 
index 46b5ed4..fd6ec8c 100644 (file)
@@ -84,6 +84,10 @@ sub profile {
     return $node->getUID;
 }
 
+sub created {
+    return @{ shift->{tree}->getNodeValue->{t} };
+}
+
 sub elapsed {
     return tv_interval(shift->{tree}->getNodeValue->{t});
 }
@@ -297,6 +301,13 @@ The profiling point will be ignored if the UID has not been previously defined.
 Returns the UID of the current point in the profile tree.  The UID is
 automatically assigned if not explicitly given.
 
+=head2 created
+
+    ($seconds, $microseconds) = $stats->created;
+
+Returns the time the object was created, in C<gettimeofday> format, with
+Unix epoch seconds followed by microseconds.
+
 =head2 elapsed
 
     $elapsed = $stats->elapsed
index 3b319ed..92fe12b 100644 (file)
@@ -156,8 +156,8 @@ L<HTTP::Request::AsCGI> or remotely if you define the CATALYST_SERVER
 environment variable. This module also adds a few Catalyst-specific
 testing methods as displayed in the method section.
 
-The L<get> and L<request> functions take either a URI or an L<HTTP::Request>
-object.
+The L<get|/"$content = get( ... )"> and L<request|/"$res = request( ... );">
+functions take either a URI or an L<HTTP::Request> object.
 
 =head1 INLINE TESTS WILL NO LONGER WORK
 
@@ -187,7 +187,7 @@ Returns the content.
 
 Note that this method doesn't follow redirects, so to test for a
 correctly redirecting page you'll need to use a combination of this
-method and the L<request> method below:
+method and the L<request|/"$res = request( ... );"> method below:
 
     my $res = request('/'); # redirects to /y
     warn $res->header('location');
@@ -208,7 +208,7 @@ header configuration; currently only supports setting 'host' value.
 
 =head2 ($res, $c) = ctx_request( ... );
 
-Works exactly like L<request>, except it also returns the Catalyst context object,
+Works exactly like L<request|/"$res = request( ... );">, except it also returns the Catalyst context object,
 C<$c>. Note that this only works for local requests.
 
 =head2 $res = Catalyst::Test::local_request( $AppClass, $url );
index bf566dc..bb34e13 100644 (file)
@@ -35,7 +35,7 @@ sub run_tests {
           TestApp::Controller::Action::Auto->begin
           TestApp::Controller::Action::Auto->auto
           TestApp::Controller::Action::Auto->one
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
     
         my $expected = join( ", ", @expected );
@@ -52,7 +52,7 @@ sub run_tests {
           TestApp::Controller::Action::Auto->begin
           TestApp::Controller::Action::Auto->auto
           TestApp::Controller::Action::Auto->default
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
     
         my $expected = join( ", ", @expected );
@@ -70,7 +70,7 @@ sub run_tests {
           TestApp::Controller::Action::Auto->auto
           TestApp::Controller::Action::Auto::Deep->auto
           TestApp::Controller::Action::Auto::Deep->one
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
     
         my $expected = join( ", ", @expected );
@@ -88,7 +88,7 @@ sub run_tests {
           TestApp::Controller::Action::Auto->auto
           TestApp::Controller::Action::Auto::Deep->auto
           TestApp::Controller::Action::Auto::Deep->default
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
     
         my $expected = join( ", ", @expected );
index 49b3163..e5b2e0f 100644 (file)
@@ -30,7 +30,7 @@ sub run_tests {
           TestApp::Controller::Action::Begin->begin
           TestApp::Controller::Action::Begin->default
           TestApp::View::Dump::Request->process
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
 
         my $expected = join( ", ", @expected );
index 615289c..3784fe6 100644 (file)
@@ -815,7 +815,7 @@ sub run_tests {
         my @expected = qw[
           TestApp::Controller::Action::Chained::Root->rootsub
           TestApp::Controller::Action::Chained::Root->endpointsub
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
 
         my $expected = join( ", ", @expected );
index 935a326..51940d4 100644 (file)
@@ -29,7 +29,7 @@ sub run_tests {
           TestApp::Controller::Action::Default->begin
           TestApp::Controller::Action::Default->default
           TestApp::View::Dump::Request->process
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
 
         my $expected = join( ", ", @expected );
@@ -76,7 +76,7 @@ sub run_tests {
         my @expected = qw[
           TestApp::Controller::Action->begin
           TestApp::Controller::Action->default
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
         
         my $expected = join( ", ", @expected );
index 5905596..2f43a53 100644 (file)
@@ -30,7 +30,7 @@ sub run_tests {
           TestApp::Controller::Action::Detach->one
           TestApp::Controller::Action::Detach->two
           TestApp::View::Dump::Request->process
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
 
         my $expected = join( ", ", @expected );
@@ -57,7 +57,7 @@ sub run_tests {
           TestApp::Controller::Action::Detach->path
           TestApp::Controller::Action::Detach->two
           TestApp::View::Dump::Request->process
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
 
         my $expected = join( ", ", @expected );
index 3000398..3d838b8 100644 (file)
@@ -33,7 +33,7 @@ sub run_tests {
           TestApp::Controller::Action::Forward->four
           TestApp::Controller::Action::Forward->five
           TestApp::View::Dump::Request->process
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
 
         my $expected = join( ", ", @expected );
@@ -81,7 +81,7 @@ sub run_tests {
           TestApp::Controller::Action::Forward->four
           TestApp::Controller::Action::Forward->five
           TestApp::View::Dump::Request->process
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
 
         my $expected = join( ", ", @expected );
@@ -156,7 +156,7 @@ sub run_tests {
           TestApp::Controller::Action::Forward->four
           TestApp::Controller::Action::Forward->five
           TestApp::View::Dump::Request->process
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
 
         my $expected = join( ", ", @expected );
@@ -191,7 +191,7 @@ sub run_tests {
           TestApp::Controller::Action::Forward->four
           TestApp::Controller::Action::Forward->five
           TestApp::View::Dump::Request->process
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
 
         my $expected = join( ", ", @expected );
index 9966a94..41b09b6 100644 (file)
@@ -43,7 +43,7 @@ sub run_tests {
           TestApp::Controller::Action::Go->four
           TestApp::Controller::Action::Go->five
           TestApp::View::Dump::Request->process
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
 
         @expected = map { /Action/ ? (_begin($_), $_) : ($_) } @expected;
@@ -74,7 +74,7 @@ sub run_tests {
         my @expected = qw[
           TestApp::Controller::Action::Go->go_die
           TestApp::Controller::Action::Go->args
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
 
         @expected = map { /Action/ ? (_begin($_), $_) : ($_) } @expected;
@@ -165,7 +165,7 @@ sub run_tests {
           TestApp::Controller::Action::Go->four
           TestApp::Controller::Action::Go->five
           TestApp::View::Dump::Request->process
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
 
         @expected = map { /Action/ ? (_begin($_), $_) : ($_) } @expected;
@@ -200,7 +200,7 @@ sub run_tests {
           TestApp::Controller::Action::Go->four
           TestApp::Controller::Action::Go->five
           TestApp::View::Dump::Request->process
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
 
         @expected = map { /Action/ ? (_begin($_), $_) : ($_) } @expected;
index 99e9435..7cd24a9 100644 (file)
@@ -27,8 +27,8 @@ sub run_tests {
     # test root index
     {
         my @expected = qw[
-          TestApp->index
-          TestApp->end
+          TestApp::Controller::Root->index
+          TestApp::Controller::Root->end
         ];
     
         my $expected = join( ", ", @expected );
@@ -45,7 +45,7 @@ sub run_tests {
     {
         my @expected = qw[
           TestApp::Controller::Index->index
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
     
         my $expected = join( ", ", @expected );
@@ -66,7 +66,7 @@ sub run_tests {
         my @expected = qw[
           TestApp::Controller::Action::Index->begin
           TestApp::Controller::Action::Index->index
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
     
         my $expected = join( ", ", @expected );
@@ -87,7 +87,7 @@ sub run_tests {
         my @expected = qw[
           TestApp::Controller::Action::Index->begin
           TestApp::Controller::Action::Index->default
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
     
         my $expected = join( ", ", @expected );
index e10d6d2..ea5d2c3 100644 (file)
@@ -10,10 +10,13 @@ our $iters;
 
 BEGIN { $iters = $ENV{CAT_BENCH_ITERS} || 1; }
 
-use Test::More tests => 6*$iters;
-
+use Test::More;
 use Catalyst::Test 'TestAppIndexDefault';
 
+plan 'skip_all' if ( $ENV{CATALYST_SERVER} );
+
+plan tests => 6*$iters;
+
 if ( $ENV{CAT_BENCHMARK} ) {
     require Benchmark;
     Benchmark::timethis( $iters, \&run_tests );
index 34ad404..beced91 100644 (file)
@@ -10,9 +10,13 @@ our $iters;
 
 BEGIN { $iters = $ENV{CAT_BENCH_ITERS} || 1; }
 
-use Test::More tests => 3*$iters;
+use Test::More;
 use Catalyst::Test 'TestAppMatchSingleArg';
 
+plan 'skip_all' if ( $ENV{CATALYST_SERVER} );
+
+plan tests => 3*$iters;
+
 if ( $ENV{CAT_BENCHMARK} ) {
     require Benchmark;
     Benchmark::timethis( $iters, \&run_tests );
index 2697940..36a679e 100644 (file)
@@ -131,8 +131,10 @@ sub run_tests {
             'TestApp::Controller::Action::Regexp',
             'Test Class'
         );
+        my $location = $response->header('location');
+        $location =~ s/localhost(:\d+)?/localhost/;
         is(
-            $response->header('location'),
+            $location,
             $url,
             'Redirect URI is the same as the request URI'
         );
index 156956b..4300744 100644 (file)
@@ -10,7 +10,7 @@ our $iters;
 
 BEGIN { $iters = $ENV{CAT_BENCH_ITERS} || 1; }
 
-use Test::More tests => 10*$iters;
+use Test::More tests => 15*$iters;
 use Catalyst::Test 'TestApp';
 
 if ( $ENV{CAT_BENCHMARK} ) {
@@ -69,4 +69,14 @@ EOF
         is( $response->content_length, -s $file, 'Response Content-Length' );
         is( $response->content, $buffer, 'Content is read from filehandle' );
     }
+
+    {
+        my $size = 128 * 1024; # more than one read with the default chunksize
+
+        ok( my $response = request('http://localhost/action/streaming/body_large'), 'Request' );
+        ok( $response->is_success, 'Response Successful 2xx' );
+        is( $response->content_type, 'text/plain', 'Response Content-Type' );
+        is( $response->content_length, $size, 'Response Content-Length' );
+        is( $response->content, "\0" x $size, 'Content is read from filehandle' );
+    }
 }
index 468496b..4bd246d 100644 (file)
@@ -42,11 +42,11 @@ sub run_tests {
           TestApp::Controller::Action::Visit->four
           TestApp::Controller::Action::Visit->five
           TestApp::View::Dump::Request->process
-          TestApp->end
-          TestApp->end
-          TestApp->end
-          TestApp->end
-          TestApp->end
+          TestApp::Controller::Root->end
+          TestApp::Controller::Root->end
+          TestApp::Controller::Root->end
+          TestApp::Controller::Root->end
+          TestApp::Controller::Root->end
         ];
 
         @expected = map { /Action/ ? (_begin($_), $_) : ($_) } @expected;
@@ -76,8 +76,8 @@ sub run_tests {
         my @expected = qw[
           TestApp::Controller::Action::Visit->visit_die
           TestApp::Controller::Action::Visit->args
-          TestApp->end
-          TestApp->end
+          TestApp::Controller::Root->end
+          TestApp::Controller::Root->end
         ];
 
         @expected = map { /Action/ ? (_begin($_), $_) : ($_) } @expected;
@@ -166,12 +166,12 @@ sub run_tests {
           TestApp::Controller::Action::Visit->four
           TestApp::Controller::Action::Visit->five
           TestApp::View::Dump::Request->process
-          TestApp->end
-          TestApp->end
-          TestApp->end
-          TestApp->end
-          TestApp->end
-          TestApp->end
+          TestApp::Controller::Root->end
+          TestApp::Controller::Root->end
+          TestApp::Controller::Root->end
+          TestApp::Controller::Root->end
+          TestApp::Controller::Root->end
+          TestApp::Controller::Root->end
         ];
 
         @expected = map { /Action/ ? (_begin($_), $_) : ($_) } @expected;
@@ -206,12 +206,12 @@ sub run_tests {
           TestApp::Controller::Action::Visit->four
           TestApp::Controller::Action::Visit->five
           TestApp::View::Dump::Request->process
-          TestApp->end
-          TestApp->end
-          TestApp->end
-          TestApp->end
-          TestApp->end
-          TestApp->end
+          TestApp::Controller::Root->end
+          TestApp::Controller::Root->end
+          TestApp::Controller::Root->end
+          TestApp::Controller::Root->end
+          TestApp::Controller::Root->end
+          TestApp::Controller::Root->end
         ];
 
         @expected = map { /Action/ ? (_begin($_), $_) : ($_) } @expected;
@@ -266,7 +266,7 @@ sub run_tests {
           TestApp::Controller::Action::Chained->foo
           TestApp::Controller::Action::Chained::Foo->spoon
           TestApp::Controller::Action::Chained->end
-          TestApp->end
+          TestApp::Controller::Root->end
         ];
 
         my $expected = join( ", ", @expected );
diff --git a/t/aggregate/live_component_controller_anon.t b/t/aggregate/live_component_controller_anon.t
new file mode 100644 (file)
index 0000000..d7a9a2c
--- /dev/null
@@ -0,0 +1,24 @@
+use strict;
+use warnings;
+
+use FindBin;
+use lib "$FindBin::Bin/../lib";
+
+use Test::More tests => 6;
+use Catalyst::Test 'TestApp';
+
+{
+    my $response = request('http://localhost/anon/test');
+    ok($response->is_success);
+    is($response->header('X-Component-Name-Action'),
+        'TestApp::Controller::Anon', 'Action can see correct catalyst_component_name');
+    isnt($response->header('X-Component-Instance-Name-Action'),
+        'TestApp::Controller::Anon', 'ref($controller) ne catalyst_component_name');
+    is($response->header('X-Component-Name-Controller'),
+        'TestApp::Controller::Anon', 'Controller can see correct catalyst_component_name');
+    is($response->header('X-Class-In-Action'),
+        'TestApp::Controller::Anon', '$action->class is catalyst_component_name');
+    is($response->header('X-Anon-Trait-Applied'),
+        '1', 'Anon controller class has trait applied correctly');
+}
+
index 9396ffb..15924cd 100644 (file)
@@ -10,9 +10,13 @@ our $iters;
 
 BEGIN { $iters = $ENV{CAT_BENCH_ITERS} || 1; }
 
-use Test::More tests => 3*$iters;
+use Test::More;
 use Catalyst::Test 'TestAppOneView';
 
+plan 'skip_all' if ( $ENV{CATALYST_SERVER} );
+
+plan tests => 3*$iters;
+
 if ( $ENV{CAT_BENCHMARK} ) {
     require Benchmark;
     Benchmark::timethis( $iters, \&run_tests );
index c6670da..954291c 100644 (file)
@@ -80,13 +80,13 @@ use HTTP::Request::Common;
 # 5.80 regression, see note in Catalyst::Plugin::Test::Plugin
 {
     my $request = GET(
-        'http://localhost/have_req_body_in_prepare_action',
+        'http://localhost/dump/response',
         'Content-Type' => 'text/plain',
         'Content'      => 'x' x 100_000
     );
 
     ok( my $response = request($request), 'Request' );
     ok( $response->is_success, 'Response Successful 2xx' );
-    like( $response->content, qr/^[1-9]/, 'Has body' );
+    ok( $response->header('X-Have-Request-Body'), 'X-Have-Request-Body set' );
 }
 
index fbc12ba..0512e6a 100644 (file)
@@ -54,8 +54,6 @@ Index: lib/Catalyst/Engine/CGI.pm
 }
 
 # test that request with URL-escaped code works.
-TODO: {
-    local $TODO = 'Actions should match when path parts are url encoded';
     my $request = Catalyst::Utils::request( 'http://localhost/args/param%73/one/two' );
     my $cgi     = HTTP::Request::AsCGI->new( $request, %ENV )->setup;
 
@@ -67,6 +65,8 @@ TODO: {
     TestApp->handle_request( env => \%ENV );
 
     ok( my $response = $cgi->restore->response );
+TODO: {
+    local $TODO = 'Actions should match when path parts are url encoded';
     ok( $response->is_success, 'Response Successful 2xx' );
     is( $response->content, 'onetwo' );
 }
index 551561e..d0ef1f0 100644 (file)
@@ -6,7 +6,7 @@ use warnings;
 use FindBin;
 use lib "$FindBin::Bin/../lib";
 
-use Test::More tests => 17;
+use Test::More tests => 18;
 use Catalyst::Test 'TestApp';
 
 use Catalyst::Request;
@@ -22,6 +22,7 @@ use HTTP::Request::Common;
         'X-Multiple'       => [ 1 .. 5 ],
         'X-Forwarded-Host' => 'frontend.server.com',
         'X-Forwarded-For'  => '192.168.1.1, 1.2.3.4',
+        'X-Forwarded-Port' => 443
     );
  
     ok( my $response = request($request), 'Request' );
@@ -30,6 +31,7 @@ use HTTP::Request::Common;
     like( $response->content, qr/^bless\( .* 'Catalyst::Request' \)$/s, 'Content is a serialized Catalyst::Request' );
     ok( eval '$creq = ' . $response->content, 'Unserialize Catalyst::Request' );
     isa_ok( $creq, 'Catalyst::Request' );
+    ok( $creq->secure, 'Forwarded port sets securet' );
     isa_ok( $creq->headers, 'HTTP::Headers', 'Catalyst::Request->headers' );
     is( $creq->header('X-Whats-Cool'), $request->header('X-Whats-Cool'), 'Catalyst::Request->header X-Whats-Cool' );
     
index 10b071b..7e5cba2 100644 (file)
@@ -37,6 +37,11 @@ use HTTP::Request::Common;
     }
 
     isa_ok( $creq, 'Catalyst::Request' );
-    
-    is( $creq->remote_user, 'dwc', '$c->req->remote_user ok' );
+    SKIP:
+    {
+        if ( $ENV{CATALYST_SERVER} ) {
+            skip 'Using remote server', 1;
+        }
+        is( $creq->remote_user, 'dwc', '$c->req->remote_user ok' );
+    }
 }
index 3e75eaa..c0af9d3 100644 (file)
@@ -12,7 +12,7 @@ plan tests => 4;
 
 use_ok('TestApp');
 
-is(TestApp->action_for('global_action')->code, TestApp->can('global_action'),
+is(TestApp->action_for('global_action')->code, TestApp::Controller::Root->can('global_action'),
    'action_for on appclass ok');
 
 is(TestApp->controller('Args')->action_for('args')->code,
index b8f3944..4431f5a 100644 (file)
@@ -8,7 +8,7 @@ use lib "$FindBin::Bin/../lib";
 
 use Test::More;
 
-plan tests => 29;
+plan tests => 30;
 
 use_ok('TestApp');
 
@@ -97,6 +97,10 @@ my $context = TestApp->new( {
                 namespace => 'yada',
               } );
 
+is($context->uri_for($context->controller('Action')),
+   "http://127.0.0.1/foo/yada/action/",
+   "uri_for a controller");
+
 is($context->uri_for($path_action),
    "http://127.0.0.1/foo/action/relative/relative",
    "uri_for correct for path action");
similarity index 61%
rename from t/optional_http-server.t
rename to t/author/optional_http-server.t
index 60f9259..d4a2183 100644 (file)
@@ -1,26 +1,20 @@
 use strict;
 use warnings;
 
-use Test::More;
-BEGIN {
-    plan skip_all => 'set TEST_HTTP to enable this test' unless $ENV{TEST_HTTP};
-}
+use Test::More tests => 1;
 
 use File::Path;
 use FindBin;
 use IPC::Open3;
 use IO::Socket;
 
-eval "use Catalyst::Devel 1.0";
-plan skip_all => 'Catalyst::Devel required' if $@;
-eval "use File::Copy::Recursive";
-plan skip_all => 'File::Copy::Recursive required' if $@;
-plan tests => 1;
+use Catalyst::Devel 1.0;
+use File::Copy::Recursive;
 
 # Run a single test by providing it as the first arg
 my $single_test = shift;
 
-my $tmpdir = "$FindBin::Bin/../t/tmp";
+my $tmpdir = "$FindBin::Bin/../../t/tmp";
 
 # clean up
 rmtree $tmpdir if -d $tmpdir;
@@ -28,24 +22,28 @@ rmtree $tmpdir if -d $tmpdir;
 # create a TestApp and copy the test libs into it
 mkdir $tmpdir;
 chdir $tmpdir;
-system( $^X, "-I$FindBin::Bin/../lib", "$FindBin::Bin/../script/catalyst.pl", 'TestApp' );
+system( $^X, "-I$FindBin::Bin/../../lib", "$FindBin::Bin/../../script/catalyst.pl", 'TestApp' );
 chdir "$FindBin::Bin/..";
-File::Copy::Recursive::dircopy( 't/lib', 't/tmp/TestApp/lib' );
+File::Copy::Recursive::dircopy( '../t/lib', '../t/tmp/TestApp/lib' ) or die;
 
 # remove TestApp's tests
-rmtree 't/tmp/TestApp/t';
+rmtree '../t/tmp/TestApp/t' or die;
 
 # spawn the standalone HTTP server
 my $port = 30000 + int rand(1 + 10000);
-my $pid = open3( undef, my $server, undef,
-  $^X, "-I$FindBin::Bin/../lib",
-  "$FindBin::Bin/../t/tmp/TestApp/script/testapp_server.pl", '-port', $port )
+my @cmd = ($^X, "-I$FindBin::Bin/../../lib",
+  "$FindBin::Bin/../../t/tmp/TestApp/script/testapp_server.pl", '-port', $port );
+my $pid = open3( undef, my $server, undef, @cmd)
     or die "Unable to spawn standalone HTTP server: $!";
 
 # wait for it to start
 print "Waiting for server to start...\n";
+my $timeout = 30;
+my $count = 0;
 while ( check_port( 'localhost', $port ) != 1 ) {
     sleep 1;
+    die("Server did not start within $timeout seconds: " . join(' ', @cmd))
+        if $count++ > $timeout;
 }
 
 # run the testsuite against the HTTP server
@@ -53,10 +51,10 @@ $ENV{CATALYST_SERVER} = "http://localhost:$port";
 
 my $return;
 if ( $single_test ) {
-    $return = system( "$^X -Ilib/ $single_test" );
+    $return = system( "$^X -I../lib/ $single_test" );
 }
 else {
-    $return = prove( '-r', '-Ilib/', glob('t/aggregate/live_*.t') );
+    $return = prove( '-r', '-I../lib/', glob('../t/aggregate/live_*.t') );
 }
 
 # shut it down
@@ -64,7 +62,7 @@ kill 'INT', $pid;
 close $server;
 
 # clean up
-rmtree "$FindBin::Bin/../t/tmp" if -d "$FindBin::Bin/../t/tmp";
+rmtree "$FindBin::Bin/../../t/tmp" if -d "$FindBin::Bin/../../t/tmp";
 
 is( $return, 0, 'live tests' );
 
index d8c67c2..27d8fa9 100644 (file)
@@ -12,7 +12,6 @@ my @modules = qw/
     Catalyst::Component
     Catalyst::Dispatcher
     Catalyst::DispatchType
-    Catalyst::Engine::HTTP::Restarter::Watcher
     Catalyst::Engine
     Catalyst::Log
     Catalyst::Request::Upload
diff --git a/t/cdi_backcompat_plugin_accessor_override.t b/t/cdi_backcompat_plugin_accessor_override.t
deleted file mode 100644 (file)
index d3efa18..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-use strict;
-use warnings;
-use lib 't/lib';
-
-use Test::More tests => 2;
-use Test::Exception;
-
-# Force a stack trace.
-use Carp;
-$SIG{__DIE__} = \&Carp::confess;
-
-{
-    package CDICompatTestApp;
-    use Catalyst qw/
-           +CDICompatTestPlugin
-    /;
-    # Calling ->config here (before we call setup). With CDI/Cat 5.70 this
-    # causes *CDICompatTestApp::_config to have a class data accessor created.
-    
-    # If this doesn't happen, then later when we've added CDICompatTestPlugin
-    # to @ISA, we fail in the overridden ->setup method when we call ->config
-    # again, as we get the CAF accessor from CDICompatTestPlugin, not the one
-    # created in this package as a side-effect of this call. :-(
-    __PACKAGE__->config;
-}
-
-SKIP: {
-  skip 'Not trying to replicate the nasty CDI hackness', 2;
-  lives_ok {
-      CDICompatTestApp->setup;
-  } 'Setup app with plugins which says use base qw/Class::Accessor::Fast/';
-
-  # And the plugin's setup_finished method should have been run, as accessors
-  # are not created in MyApp until the data is written to.
-  {
-      no warnings 'once';
-      is $CDICompatTestPlugin::Data::HAS_RUN_SETUP_FINISHED, 1, 'Plugin setup_finish run';
-  }
-}
\ No newline at end of file
diff --git a/t/custom_exception_class_simple.t b/t/custom_exception_class_simple.t
new file mode 100644 (file)
index 0000000..e87ed80
--- /dev/null
@@ -0,0 +1,18 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+use FindBin qw/$Bin/;
+use lib "$Bin/lib";
+use Test::More tests => 1;
+use Test::Exception;
+
+TODO: {
+    local $TODO = 'Does not work yet';
+
+lives_ok {
+    require TestAppClassExceptionSimpleTest;
+} 'Can load application';
+
+}
+
index f5960ef..b1417a0 100644 (file)
@@ -32,9 +32,9 @@ sub run_tests {
         
         {
             my @expected = qw[
-                TestAppDoubleAutoBug->auto
-                TestAppDoubleAutoBug->default
-                TestAppDoubleAutoBug->end
+                TestAppDoubleAutoBug::Controller::Root->auto
+                TestAppDoubleAutoBug::Controller::Root->default
+                TestAppDoubleAutoBug::Controller::Root->end
             ];
     
             my $expected = join( ", ", @expected );
index cfb5adf..b30df89 100644 (file)
@@ -16,6 +16,8 @@ my $mvc_warnings;
 BEGIN {
     my $logger = Class::MOP::Class->create_anon_class(
     methods => {
+        debug => sub {0},
+        info  => sub {0},
         warn => sub {
             if ($_[1] =~ /switch your class names/) {
                $mvc_warnings++;
diff --git a/t/deprecated_appclass_action_warnings.t b/t/deprecated_appclass_action_warnings.t
new file mode 100644 (file)
index 0000000..f25d8d5
--- /dev/null
@@ -0,0 +1,18 @@
+use strict;
+use warnings;
+
+use FindBin;
+use lib "$FindBin::Bin/lib";
+
+use Test::More;
+use Catalyst::Test 'DeprecatedActionsInAppClassTestApp';
+
+plan tests => 3;
+
+my $warnings;
+my $logger = DeprecatedActionsInAppClassTestApp::Log->new;
+Catalyst->log($logger);
+
+ok( my $response = request('http://localhost/foo'), 'Request' );
+ok( $response->is_success, 'Response Successful 2xx' );
+is( $DeprecatedActionsInAppClassTestApp::Log::warnings, 1, 'Get the appclass action warning' );
\ No newline at end of file
diff --git a/t/lib/ACLTestApp.pm b/t/lib/ACLTestApp.pm
new file mode 100644 (file)
index 0000000..ec87027
--- /dev/null
@@ -0,0 +1,26 @@
+package ACLTestApp;
+use Test::More;
+
+use strict;
+use warnings;
+use MRO::Compat;
+use Scalar::Util ();
+
+use base qw/Catalyst Catalyst::Controller/;
+use Catalyst qw//;
+
+sub execute {
+    my $c = shift;
+    my ( $class, $action ) = @_;
+
+    if ( Scalar::Util::blessed($action)
+        and $action->name ne "foobar" ) {
+       eval { $c->detach( 'foobar', [$action, 'foo'] ) };
+    }
+
+    $c->next::method( @_ );
+}
+
+__PACKAGE__->setup;
+
+1;
diff --git a/t/lib/ACLTestApp/Controller/Root.pm b/t/lib/ACLTestApp/Controller/Root.pm
new file mode 100644 (file)
index 0000000..a1aa83b
--- /dev/null
@@ -0,0 +1,18 @@
+package ACLTestApp::Controller::Root;
+use Test::More;
+
+use base 'Catalyst::Controller';
+
+__PACKAGE__->config->{namespace} = '';
+
+sub foobar : Private {
+    die $Catalyst::DETACH;
+}
+
+sub gorch : Local {
+    my ( $self, $c, $frozjob ) = @_;
+    is $frozjob, 'wozzle';
+    $c->res->body("gorch");
+}
+
+1;
index b620c5e..16f3f63 100644 (file)
@@ -22,26 +22,14 @@ sub prepare {
     return $c;
 }
 
-# Note: This is horrible, but Catalyst::Plugin::Server forces the body to
+# Note: Catalyst::Plugin::Server forces the body to
 #       be parsed, by calling the $c->req->body method in prepare_action.
 #       We need to test this, as this was broken by 5.80. See also
-#       t/aggregate/live_engine_request_body.t. Better ways to test this
-#       appreciated if you have suggestions :)
-{
-    my $have_req_body = 0;
-    sub prepare_action {
-        my $c = shift;
-        $have_req_body++ if $c->req->body;
-        $c->next::method(@_);
-    }
-    sub have_req_body_in_prepare_action : Local {
-        my ($self, $c) = @_;
-        $c->res->body($have_req_body);
-    }
-}
-
-sub end : Private {
-    my ($self,$c) = @_;
+#       t/aggregate/live_engine_request_body.t.
+sub prepare_action {
+    my $c = shift;
+    $c->res->header('X-Have-Request-Body', 1) if $c->req->body;
+    $c->next::method(@_);
 }
 
 1;
diff --git a/t/lib/DeprecatedActionsInAppClassTestApp.pm b/t/lib/DeprecatedActionsInAppClassTestApp.pm
new file mode 100644 (file)
index 0000000..9c870b0
--- /dev/null
@@ -0,0 +1,30 @@
+package DeprecatedActionsInAppClassTestApp;
+
+use strict;
+use warnings;
+use Catalyst;
+
+our $VERSION = '0.01';
+
+__PACKAGE__->config( name => 'DeprecatedActionsInAppClassTestApp', root => '/some/dir' );
+__PACKAGE__->log(DeprecatedActionsInAppClassTestApp::Log->new);
+__PACKAGE__->setup;
+
+sub foo : Local {
+    my ($self, $c) = @_;
+    $c->res->body('OK');
+}
+
+package DeprecatedActionsInAppClassTestApp::Log;
+use strict;
+use warnings;
+use base qw/Catalyst::Log/;
+
+our $warnings;
+
+sub warn {
+    my ($self, $warning) = @_;
+    $warnings++ if $warning =~ /action methods .+ found defined/i;
+}
+
+1;
index c476736..1031586 100644 (file)
@@ -6,48 +6,6 @@ use Catalyst qw(
         +TestApp::Plugin::FullyQualified
         );
 
-sub compile_time_plugins : Local {
-    my ( $self, $c ) = @_;
-
-    isa_ok $c, 'Catalyst::Plugin::Test::Plugin';
-    isa_ok $c, 'TestApp::Plugin::FullyQualified';
-
-    can_ok $c, 'registered_plugins';
-    $c->_test_plugins;
-
-    $c->res->body("ok");
-}
-
-sub run_time_plugins : Local {
-    my ( $self, $c ) = @_;
-
-    $c->_test_plugins;
-    my $faux_plugin = 'Faux::Plugin';
-
-# Trick perl into thinking the plugin is already loaded
-    $INC{'Faux/Plugin.pm'} = 1;
-
-    __PACKAGE__->plugin( faux => $faux_plugin );
-
-    isa_ok $c, 'Catalyst::Plugin::Test::Plugin';
-    isa_ok $c, 'TestApp::Plugin::FullyQualified';
-    ok !$c->isa($faux_plugin),
-    '... and it should not inherit from the instant plugin';
-    can_ok $c, 'faux';
-    is $c->faux->count, 1, '... and it should behave correctly';
-    is_deeply [ $c->registered_plugins ],
-    [
-        qw/Catalyst::Plugin::Test::Plugin
-        Faux::Plugin
-        TestApp::Plugin::FullyQualified/
-        ],
-    'registered_plugins() should report all plugins';
-    ok $c->registered_plugins('Faux::Plugin'),
-    '... and even the specific instant plugin';
-
-    $c->res->body("ok");
-}
-
 sub _test_plugins {
     my $c = shift;
     is_deeply [ $c->registered_plugins ],
diff --git a/t/lib/PluginTestApp/Controller/Root.pm b/t/lib/PluginTestApp/Controller/Root.pm
new file mode 100644 (file)
index 0000000..5358074
--- /dev/null
@@ -0,0 +1,55 @@
+package PluginTestApp::Controller::Root;
+use Test::More;
+
+use base 'Catalyst::Controller';
+
+#use Catalyst qw(
+#        Test::Plugin
+#        +TestApp::Plugin::FullyQualified
+#        );
+
+__PACKAGE__->config->{namespace} = '';
+
+sub compile_time_plugins : Local {
+    my ( $self, $c ) = @_;
+
+    isa_ok $c, 'Catalyst::Plugin::Test::Plugin';
+    isa_ok $c, 'TestApp::Plugin::FullyQualified';
+
+    can_ok $c, 'registered_plugins';
+    $c->_test_plugins;
+
+    $c->res->body("ok");
+}
+
+sub run_time_plugins : Local {
+    my ( $self, $c ) = @_;
+
+    $c->_test_plugins;
+    my $faux_plugin = 'Faux::Plugin';
+
+# Trick perl into thinking the plugin is already loaded
+    $INC{'Faux/Plugin.pm'} = 1;
+
+    ref($c)->plugin( faux => $faux_plugin );
+
+    isa_ok $c, 'Catalyst::Plugin::Test::Plugin';
+    isa_ok $c, 'TestApp::Plugin::FullyQualified';
+    ok !$c->isa($faux_plugin),
+    '... and it should not inherit from the instant plugin';
+    can_ok $c, 'faux';
+    is $c->faux->count, 1, '... and it should behave correctly';
+    is_deeply [ $c->registered_plugins ],
+    [
+        qw/Catalyst::Plugin::Test::Plugin
+        Faux::Plugin
+        TestApp::Plugin::FullyQualified/
+        ],
+    'registered_plugins() should report all plugins';
+    ok $c->registered_plugins('Faux::Plugin'),
+    '... and even the specific instant plugin';
+
+    $c->res->body("ok");
+}
+
+1;
index e14e3dc..a2fc0b2 100644 (file)
@@ -41,16 +41,6 @@ sub count_leaks {
 
 TestApp->setup;
 
-sub index : Private {
-    my ( $self, $c ) = @_;
-    $c->res->body('root index');
-}
-
-sub global_action : Private {
-    my ( $self, $c ) = @_;
-    $c->forward('TestApp::View::Dump::Request');
-}
-
 sub execute {
     my $c      = shift;
     my $class  = ref( $c->component( $_[0] ) ) || $_[0];
@@ -77,7 +67,7 @@ sub execute {
             @executed
         );
     }
-
+    no warnings 'recursion';
     return $c->SUPER::execute(@_);
 }
 
@@ -92,24 +82,6 @@ sub finalize_error {
     $c->res->body( 'FATAL ERROR: ' . join( ', ', @{ $c->error } ) );
 }
 
-sub class_forward_test_method :Private {
-    my ( $self, $c ) = @_;
-    $c->response->headers->header( 'X-Class-Forward-Test-Method' => 1 );
-}
-
-sub loop_test : Local {
-    my ( $self, $c ) = @_;
-
-    for( 1..1001 ) {
-        $c->forward( 'class_forward_test_method' );
-    }
-}
-
-sub recursion_test : Local {
-    my ( $self, $c ) = @_;
-    $c->forward( 'recursion_test' );
-}
-
 {
     no warnings 'redefine';
     sub Catalyst::Log::error { }
index 5a83aee..1240b0e 100644 (file)
@@ -9,6 +9,9 @@ sub execute {
     my $self = shift;
     my ( $controller, $c, $test ) = @_;
     $c->res->header( 'X-TestAppActionTestMyAction', 'MyAction works' );
+    $c->res->header( 'X-Component-Name-Action', $controller->catalyst_component_name);
+    $c->res->header( 'X-Component-Instance-Name-Action', ref($controller));
+    $c->res->header( 'X-Class-In-Action', $self->class);
     $self->next::method(@_);
 }
 
index 5a757b0..08c7c65 100644 (file)
@@ -16,7 +16,7 @@ EOF
 
 sub body : Local {
     my ( $self, $c ) = @_;
-    
+
     my $file = "$FindBin::Bin/../lib/TestApp/Controller/Action/Streaming.pm";
     my $fh = IO::File->new( $file, 'r' );
     if ( defined $fh ) {
@@ -27,4 +27,16 @@ sub body : Local {
     }
 }
 
+sub body_large : Local {
+    my ($self, $c) = @_;
+
+    # more than one write with the default chunksize
+    my $size = 128 * 1024;
+
+    my $data = "\0" x $size;
+    open my $fh, '<', \$data;
+    $c->res->content_length($size);
+    $c->res->body($fh);
+}
+
 1;
diff --git a/t/lib/TestApp/Controller/Anon.pm b/t/lib/TestApp/Controller/Anon.pm
new file mode 100644 (file)
index 0000000..68b4fd6
--- /dev/null
@@ -0,0 +1,40 @@
+package Anon::Trait;
+use Moose::Role -traits => 'MethodAttributes'; # Needed for role composition to work correctly with anon classes.
+
+after test => sub {
+    my ($self, $c) = @_;
+    $c->res->header('X-Anon-Trait-Applied', 1);
+};
+
+no Moose::Role;
+
+package TestApp::Controller::Anon;
+use Moose;
+use Moose::Util qw/find_meta/;
+use namespace::clean -except => 'meta';
+BEGIN { extends 'Catalyst::Controller' };
+
+sub COMPONENT { # Don't do this yourself, use CatalystX::Component::Traits!
+    my ($class, $app, $args) = @_;
+
+    my $meta = $class->meta->create_anon_class(
+            superclasses => [ $class->meta->name ],
+            roles        => ['Anon::Trait'],
+            cache        => 1,
+    );
+    # Special move as the methodattributes trait has changed our metaclass..
+    $meta = find_meta($meta->name);
+
+    $meta->add_method('meta' => sub { $meta });
+    $class = $meta->name;
+    $class->new($app, $args);
+}
+
+sub test : Local ActionClass('+TestApp::Action::TestMyAction') {
+    my ($self, $c) = @_;
+    $c->res->header('X-Component-Name-Controller', $self->catalyst_component_name);
+    $c->res->body('It works');
+}
+
+__PACKAGE__->meta->make_immutable;
+
index 53d79e2..5aa03dc 100644 (file)
@@ -20,4 +20,36 @@ sub localregex : LocalRegex('^localregex$') {
     $c->forward('TestApp::View::Dump::Request');
 }
 
+sub index : Private {
+    my ( $self, $c ) = @_;
+    $c->res->body('root index');
+}
+
+sub global_action : Private {
+    my ( $self, $c ) = @_;
+    $c->forward('TestApp::View::Dump::Request');
+}
+
+sub class_forward_test_method :Private {
+    my ( $self, $c ) = @_;
+    $c->response->headers->header( 'X-Class-Forward-Test-Method' => 1 );
+}
+
+sub loop_test : Local {
+    my ( $self, $c ) = @_;
+
+    for( 1..1001 ) {
+        $c->forward( 'class_forward_test_method' );
+    }
+}
+
+sub recursion_test : Local {
+    my ( $self, $c ) = @_;
+    $c->forward( 'recursion_test' );
+}
+
+sub end : Private {
+    my ($self,$c) = @_;
+}
+
 1;
diff --git a/t/lib/TestAppClassExceptionSimpleTest.pm b/t/lib/TestAppClassExceptionSimpleTest.pm
new file mode 100644 (file)
index 0000000..aef61be
--- /dev/null
@@ -0,0 +1,19 @@
+package TestAppClassExceptionSimpleTest::Exception;
+use strict;
+use warnings;
+
+sub throw {}
+
+#########
+
+package TestAppClassExceptionSimpleTest;
+use strict;
+use warnings;
+
+BEGIN { $Catalyst::Exception::CATALYST_EXCEPTION_CLASS = 'TestAppClassExceptionSimpleTest::Exception'; }
+
+use Catalyst;
+
+__PACKAGE__->setup;
+
+1;
index 00855cd..82a5e07 100644 (file)
@@ -44,16 +44,3 @@ sub execute {
 
     return $c->SUPER::execute(@_);
 }
-
-
-
-sub auto : Private {
-    my ( $self, $c ) = @_;
-    ++$c->stash->{auto_count};
-    return 1;
-}
-
-sub default : Private {
-    my ( $self, $c ) = @_;
-    $c->res->body( sprintf 'default, auto=%d', $c->stash->{auto_count} );
-}
diff --git a/t/lib/TestAppDoubleAutoBug/Controller/Root.pm b/t/lib/TestAppDoubleAutoBug/Controller/Root.pm
new file mode 100644 (file)
index 0000000..2d0b1a6
--- /dev/null
@@ -0,0 +1,22 @@
+package TestAppDoubleAutoBug::Controller::Root;
+
+use base 'Catalyst::Controller';
+
+__PACKAGE__->config->{namespace} = '';
+
+sub auto : Private {
+    my ( $self, $c ) = @_;
+    ++$c->stash->{auto_count};
+    return 1;
+}
+
+sub default : Private {
+    my ( $self, $c ) = @_;
+    $c->res->body( sprintf 'default, auto=%d', $c->stash->{auto_count} );
+}
+
+sub end : Private {
+    my ($self,$c) = @_;
+}
+
+1;
diff --git a/t/lib/TestAppNonMooseController.pm b/t/lib/TestAppNonMooseController.pm
new file mode 100644 (file)
index 0000000..8507aba
--- /dev/null
@@ -0,0 +1,8 @@
+package TestAppNonMooseController;
+use base qw/Catalyst/;
+use Catalyst;
+
+__PACKAGE__->setup;
+
+1;
+
diff --git a/t/lib/TestAppNonMooseController/Controller/Foo.pm b/t/lib/TestAppNonMooseController/Controller/Foo.pm
new file mode 100644 (file)
index 0000000..36b036c
--- /dev/null
@@ -0,0 +1,5 @@
+package TestAppNonMooseController::Controller::Foo;
+use base qw/TestAppNonMooseController::ControllerBase/;
+
+1;
+
diff --git a/t/lib/TestAppNonMooseController/ControllerBase.pm b/t/lib/TestAppNonMooseController/ControllerBase.pm
new file mode 100644 (file)
index 0000000..406df4b
--- /dev/null
@@ -0,0 +1,5 @@
+package TestAppNonMooseController::ControllerBase;
+use base qw/Catalyst::Controller/;
+
+1;
+
index 3d3b11b..74a2f27 100644 (file)
@@ -2,13 +2,15 @@ use strict;
 use warnings;
 
 package TestAppPathBug;
-
+use strict;
+use warnings;
 use Catalyst;
 
 our $VERSION = '0.01';
 
 __PACKAGE__->config( name => 'TestAppPathBug', root => '/some/dir' );
 
+__PACKAGE__->log(TestAppPathBug::Log->new);
 __PACKAGE__->setup;
 
 sub foo : Path {
@@ -16,4 +18,11 @@ sub foo : Path {
     $c->res->body( 'This is the foo method.' );
 }
 
+package TestAppPathBug::Log;
+use strict;
+use warnings;
+use base qw/Catalyst::Log/;
+
+sub warn {}
+
 1;
index 36d8e16..5b4b8c1 100644 (file)
@@ -6,11 +6,6 @@ use Catalyst qw/+TestPluginWithConstructor/;
 use Moose;
 BEGIN { extends qw/Catalyst Catalyst::Controller/ } # Ewww, FIXME.
 
-sub foo : Local {
-    my ($self, $c) = @_;
-    $c->res->body('foo');
-}
-
 __PACKAGE__->setup;
 our $MODIFIER_FIRED = 0;
 
diff --git a/t/lib/TestAppPluginWithConstructor/Controller/Root.pm b/t/lib/TestAppPluginWithConstructor/Controller/Root.pm
new file mode 100644 (file)
index 0000000..d032fd2
--- /dev/null
@@ -0,0 +1,12 @@
+package TestAppPluginWithConstructor::Controller::Root;
+
+use base 'Catalyst::Controller';
+
+__PACKAGE__->config->{namespace} = '';
+
+sub foo : Local {
+    my ($self, $c) = @_;
+    $c->res->body('foo');
+}
+
+1;
index bfc1340..6e3b320 100644 (file)
@@ -16,16 +16,8 @@ __PACKAGE__->log(TestAppStats::Log->new);
 
 __PACKAGE__->setup;
 
-# Return log messages from previous request
-sub default : Private {
-    my ( $self, $c ) = @_;
-    $c->stats->profile("test");
-    $c->res->body(join("\n", @log_messages));
-    @log_messages = ();
-}
-
 package TestAppStats::Log;
 use base qw/Catalyst::Log/;
 
-sub info { push(@log_messages, @_); }
-sub debug { push(@log_messages, @_); }
+sub info { push(@TestAppStats::log_messages, @_); }
+sub debug { push(@TestAppStats::log_messages, @_); }
diff --git a/t/lib/TestAppStats/Controller/Root.pm b/t/lib/TestAppStats/Controller/Root.pm
new file mode 100644 (file)
index 0000000..a46856a
--- /dev/null
@@ -0,0 +1,16 @@
+package TestAppStats::Controller::Root;
+use strict;
+use warnings;
+use base 'Catalyst::Controller';
+
+__PACKAGE__->config->{namespace} = '';
+
+# Return log messages from previous request
+sub default : Private {
+    my ( $self, $c ) = @_;
+    $c->stats->profile("test");
+    $c->res->body(join("\n", @TestAppStats::log_messages));
+    @TestAppStats::log_messages = ();
+}
+
+1;
index e5bdb1c..e251568 100644 (file)
@@ -1,11 +1,17 @@
 # See t/plugin_new_method_backcompat.t
-package TestPluginWithConstructor;
+package Class::Accessor::Fast;
 use strict;
 use warnings;
+
 sub new {
     my $class = shift;
     return bless $_[0], $class;
 }
 
+package TestPluginWithConstructor;
+use strict;
+use warnings;
+use base qw/Class::Accessor::Fast/;
+
 1;
 
index 39f475a..3d3cb3f 100644 (file)
@@ -45,10 +45,11 @@ rmtree 't/tmp/TestApp/t';
 my $port = 30000 + int rand( 1 + 10000 );
 
 my( $server, $pid );
-$pid = open3( undef, $server, undef,
-  $^X, "-I$FindBin::Bin/../lib",
+my @cmd = ($^X, "-I$FindBin::Bin/../lib", "-I$FindBin::Bin/lib",
   "$FindBin::Bin/../t/tmp/TestApp/script/testapp_server.pl", '-port',
-  $port, '-restart' )
+  $port, '-restart');
+
+$pid = open3( undef, $server, undef, @cmd )
     or die "Unable to spawn standalone HTTP server: $!";
 
 # switch to non-blocking reads so we can fail
@@ -67,11 +68,9 @@ my @files = (
     "$FindBin::Bin/../t/tmp/TestApp/lib/TestApp.pm",
     "$FindBin::Bin/../t/tmp/TestApp/lib/TestApp/Controller/Action/Begin.pm",
     "$FindBin::Bin/../t/tmp/TestApp/lib/TestApp/Controller/Immutable.pm",
+    "$FindBin::Bin/../t/tmp/TestApp/lib/TestApp/Controller/Immutable/HardToReload.pm",
 );
 
-push(@files, "$FindBin::Bin/../t/tmp/TestApp/lib/TestApp/Controller/Immutable/HardToReload.pm")
-    if Catalyst::Engine::HTTP::Restarter::Watcher::DETECT_PACKAGE_COMPILATION();
-
 # change some files and make sure the server restarts itself
 NON_ERROR_RESTART:
 for ( 1 .. 20 ) {
@@ -84,7 +83,6 @@ for ( 1 .. 20 ) {
     # give the server time to notice the change and restart
     my $count = 0;
     my $line;
-
     while ( ( $line || '' ) !~ /can connect/ ) {
         # wait for restart message
         $line = $server->getline;
diff --git a/t/unit_controller_actions.t b/t/unit_controller_actions.t
new file mode 100644 (file)
index 0000000..26e603d
--- /dev/null
@@ -0,0 +1,26 @@
+use strict;
+use warnings;
+use Test::More tests => 4;
+
+use Catalyst ();
+{
+    package TestController;
+    use Moose;
+    BEGIN { extends 'Catalyst::Controller' }
+
+    sub action : Local {}
+
+    sub foo : Path {}
+
+    no Moose;
+}
+
+my $mock_app = Class::MOP::Class->create_anon_class( superclasses => ['Catalyst'] );
+my $app = $mock_app->name->new;
+my $controller = TestController->new($app, {actions => { foo => { Path => '/some/path' }}});
+
+ok $controller->can('_controller_actions');
+is_deeply $controller->_controller_actions => { foo => { Path => '/some/path' }};
+is_deeply $controller->{actions} => { foo => { Path => '/some/path' }}; # Back compat.
+is_deeply [ sort grep { ! /^_/ } map { $_->name } $controller->get_action_methods ], [sort qw/action foo/];
+
diff --git a/t/unit_core_action.t b/t/unit_core_action.t
new file mode 100644 (file)
index 0000000..ca84422
--- /dev/null
@@ -0,0 +1,54 @@
+use Test::More tests => 6;
+use strict;
+use warnings;
+use Moose::Meta::Class;
+#use Moose::Meta::Attribute;
+use Catalyst::Request;
+
+use_ok('Catalyst::Action');
+
+my $action_1 = Catalyst::Action->new(
+  name => 'foo',
+  code => sub { "DUMMY" },
+  reverse => 'bar/foo',
+  namespace => 'bar',
+  attributes => {
+    Args => [ 1 ],
+    attr2 => [ 2 ],
+  },
+);
+
+my $action_2 = Catalyst::Action->new(
+  name => 'foo',
+  code => sub { "DUMMY" },
+  reverse => 'bar/foo',
+  namespace => 'bar',
+  attributes => {
+    Args => [ 2 ],
+    attr2 => [ 2 ],
+  },
+);
+
+is("${action_1}", $action_1->reverse, 'overload string');
+is($action_1->(), 'DUMMY', 'overload code');
+
+my $anon_meta = Moose::Meta::Class->create_anon_class(
+  attributes => [
+    Moose::Meta::Attribute->new(
+      request => (
+        reader => 'request',
+        required => 1,
+        default => sub { Catalyst::Request->new(arguments => [qw/one two/]) },
+      ),
+    ),
+  ],
+  methods => { req => sub { shift->request(@_) } }
+);
+
+my $mock_c = $anon_meta->new_object();
+$mock_c->request;
+
+ok(!$action_1->match($mock_c), 'bad match fails');
+ok($action_2->match($mock_c), 'good match works');
+
+ok($action_2->compare( $action_1 ), 'compare works');
index 6d60a96..d054dc6 100644 (file)
@@ -100,3 +100,7 @@ is(refaddr(ClassDataTest->_hashref), refaddr($hashref3));
 is(refaddr(ClassDataTest->_scalarref), refaddr($scalarref3));
 is(refaddr(ClassDataTest->_coderef), refaddr($coderef3));
 is(ClassDataTest->_scalar, $scalar3);
+
+my $i = bless {}, 'ClassDataTest';
+$i->_scalar('foo');
+
index c8098c6..1944ab6 100644 (file)
@@ -1,7 +1,8 @@
 # 2 initial tests, and 6 per component in the loop below
 # (do not forget to update the number of components in test 3 as well)
 # 5 extra tests for the loading options
-use Test::More tests => 2 + 6 * 24 + 5;
+# One test for components in inner packages
+use Test::More tests => 2 + 6 * 24 + 8 + 1;
 
 use strict;
 use warnings;
@@ -174,6 +175,9 @@ sub COMPONENT {
     my \$self = shift->next::method(\@_);
     no strict 'refs';
     *{\__PACKAGE__ . "::whoami"} = sub { return \__PACKAGE__; };
+    *${appclass}::Model::TopLevel::GENERATED::ACCEPT_CONTEXT = sub {
+        return bless {}, 'FooBarBazQuux';
+    };
     \$self;
 }
 
@@ -189,8 +193,10 @@ write_component_file([$libdir, $appclass, 'Model', 'TopLevel'], 'Nested', <<EOF)
 package ${appclass}::Model::TopLevel::Nested;
 use base 'Catalyst::Model';
 
+my \$called=0;
 no warnings 'redefine';
-sub COMPONENT { return shift->next::method(\@_); }
+sub COMPONENT { \$called++;return shift->next::method(\@_); }
+sub called { return \$called };
 1;
 
 EOF
@@ -198,5 +204,23 @@ EOF
 eval "package $appclass; use Catalyst; __PACKAGE__->setup";
 
 is($@, '', "Didn't load component twice");
+is($appclass->model('TopLevel::Nested')->called,1, 'COMPONENT called once');
+
+ok($appclass->model('TopLevel::Generated'), 'Have generated model');
+is(ref($appclass->model('TopLevel::Generated')), 'FooBarBazQuux',
+    'ACCEPT_CONTEXT in generated inner package fired as expected');
+
+$appclass = "InnerComponent";
+
+{
+  package InnerComponent::Controller::Test;
+  use base 'Catalyst::Controller';
+}
+
+$INC{'InnerComponent/Controller/Test.pm'} = 1;
+
+eval "package $appclass; use Catalyst; __PACKAGE__->setup";
+
+isa_ok($appclass->controller('Test'), 'Catalyst::Controller');
 
 rmtree($libdir);
index 93d08d8..03d16f6 100644 (file)
@@ -21,6 +21,9 @@ my $warnings = 0;
 use PluginTestApp;
 my $logger = Class::MOP::Class->create_anon_class(
     methods => {
+        error => sub {0},
+        debug => sub {0},
+        info => sub {0},
         warn => sub {
             if ($_[1] =~ /plugin method is deprecated/) {
                $warnings++;
@@ -40,6 +43,8 @@ is( $warnings, 0, 'no warnings' );
 #         for Catalyst 5.9
 ok( get("/run_time_plugins"),     "get ok" );
 
+local $ENV{CATALYST_DEBUG} = 0;
+
 is( $warnings, 1, '1 warning' );
 
 use_ok 'TestApp';
@@ -56,3 +61,4 @@ my @expected = qw(
 # Faux::Plugin is no longer reported
 is_deeply [ TestApp->registered_plugins ], \@expected,
   'registered_plugins() should only report the plugins for the current class';
+
index 00ee842..cbc5aac 100644 (file)
@@ -26,12 +26,17 @@ sub build_test_app_with_setup {
     return $name;
 }
 
-local %ENV; # Don't allow env variables to mess us up.
+local %ENV = %ENV;
+
+# Remove all relevant env variables to avoid accidental fail
+foreach my $name (grep { /^(CATALYST|TESTAPP)/ } keys %ENV) {
+    delete $ENV{$name};
+}
 
 {
-    my $app = build_test_app_with_setup('MyTestDebug', '-Debug');
+    my $app = build_test_app_with_setup('TestAppMyTestDebug', '-Debug');
 
-    ok my $c = MyTestDebug->new, 'Get debug app object';
+    ok my $c = $app->new, 'Get debug app object';
     ok my $log = $c->log, 'Get log object';
     isa_ok $log, 'Catalyst::Log', 'It should be a Catalyst::Log object';
     ok $log->is_warn, 'Warnings should be enabled';
@@ -43,7 +48,7 @@ local %ENV; # Don't allow env variables to mess us up.
 }
 
 {
-    my $app = build_test_app_with_setup('MyTestLogParam', '-Log=warn,error,fatal');
+    my $app = build_test_app_with_setup('TestAppMyTestLogParam', '-Log=warn,error,fatal');
 
     ok my $c = $app->new, 'Get log app object';
     ok my $log = $c->log, 'Get log object';
@@ -56,7 +61,7 @@ local %ENV; # Don't allow env variables to mess us up.
     ok !$c->debug, 'Catalyst debugging is off';
 }
 {
-    my $app = build_test_app_with_setup('MyTestNoParams');
+    my $app = build_test_app_with_setup('TestAppMyTestNoParams');
 
     ok my $c = $app->new, 'Get log app object';
     ok my $log = $c->log, 'Get log object';
@@ -72,12 +77,12 @@ my $log_meta = Class::MOP::Class->create_anon_class(
     methods => { map { $_ => sub { 0 } } qw/debug error fatal info warn/ },
 );
 {
-    package MyTestAppWithOwnLogger;
+    package TestAppWithOwnLogger;
     use base qw/Catalyst/;
     __PACKAGE__->log($log_meta->new_object);
     __PACKAGE__->setup('-Debug');
 }
 
-ok my $c = MyTestAppWithOwnLogger->new, 'Get with own logger app object';
+ok my $c = TestAppWithOwnLogger->new, 'Get with own logger app object';
 ok $c->debug, '$c->debug is true';
 
index 401ea99..1406944 100644 (file)
@@ -27,10 +27,15 @@ sub test_log_object {
     }
 }
 
-local %ENV; # Ensure blank or someone, somewhere will fail..
+local %ENV = %ENV;
+
+# Remove all relevant env variables to avoid accidental fail
+foreach my $name (grep { /^(CATALYST|TESTAPP)/ } keys %ENV) {
+    delete $ENV{$name};
+}
 
 {
-    my $app = mock_app('TestLogAppParseLevels');
+    my $app = mock_app('TestAppParseLogLevels');
     $app->setup_log('error,warn');
     ok !$app->debug, 'Not in debug mode';
     test_log_object($app->log,
@@ -42,8 +47,9 @@ local %ENV; # Ensure blank or someone, somewhere will fail..
     );
 }
 {
-    local %ENV = ( CATALYST_DEBUG => 1 );
-    my $app = mock_app('TestLogAppDebugEnvSet');
+    local %ENV = %ENV;
+    $ENV{CATALYST_DEBUG} = 1;
+    my $app = mock_app('TestAppLogDebugEnvSet');
     $app->setup_log('');
     ok $app->debug, 'In debug mode';
     test_log_object($app->log,
@@ -55,8 +61,9 @@ local %ENV; # Ensure blank or someone, somewhere will fail..
     );
 }
 {
-    local %ENV = ( CATALYST_DEBUG => 0 );
-    my $app = mock_app('TestLogAppDebugEnvUnset');
+    local %ENV = %ENV;
+    $ENV{CATALYST_DEBUG} = 0;
+    my $app = mock_app('TestAppLogDebugEnvUnset');
     $app->setup_log('warn');
     ok !$app->debug, 'Not In debug mode';
     test_log_object($app->log,
@@ -68,7 +75,7 @@ local %ENV; # Ensure blank or someone, somewhere will fail..
     );
 }
 {
-    my $app = mock_app('TestLogAppEmptyString');
+    my $app = mock_app('TestAppLogEmptyString');
     $app->setup_log('');
     ok !$app->debug, 'Not In debug mode';
     # Note that by default, you get _all_ the log levels turned on
@@ -81,7 +88,7 @@ local %ENV; # Ensure blank or someone, somewhere will fail..
     );
 }
 {
-    my $app = mock_app('TestLogAppDebugOnly');
+    my $app = mock_app('TestAppLogDebugOnly');
     $app->setup_log('debug');
     ok $app->debug, 'In debug mode';
     test_log_object($app->log,
index 8cc979f..11ef840 100644 (file)
@@ -22,40 +22,46 @@ my $mock_log = Class::MOP::Class->create_anon_class(
 sub mock_app {
     my $name = shift;
     %log_messages = (); # Flatten log messages.
-    print "Setting up mock application: $name\n";
     my $meta = Moose->init_meta( for_class => $name );
     $meta->superclasses('Catalyst');
     $meta->add_method('log', sub { $mock_log }); 
     return $meta->name;
 }
 
-local %ENV; # Ensure blank or someone, somewhere will fail..
+local %ENV = %ENV;
+
+# Remove all relevant env variables to avoid accidental fail
+foreach my $name (grep { /^(CATALYST|TESTAPP)/ } keys %ENV) {
+    delete $ENV{$name};
+}
 
 {
-    my $app = mock_app('TestNoStats');
+    my $app = mock_app('TestAppNoStats');
     $app->setup_stats();
     ok !$app->use_stats, 'stats off by default';
 }
 {
-    my $app = mock_app('TestStats');
+    my $app = mock_app('TestAppStats');
     $app->setup_stats(1);
     ok $app->use_stats, 'stats on if you say >setup_stats(1)';
 }
 {
-    my $app = mock_app('TestStatsDebugTurnsStatsOn');
+    my $app = mock_app('TestAppStatsDebugTurnsStatsOn');
     $app->meta->add_method('debug' => sub { 1 });
     $app->setup_stats();
     ok $app->use_stats, 'debug on turns stats on';
 }
 {
-    local %ENV = ( CATALYST_STATS => 1 );
-    my $app = mock_app('TestStatsAppStatsEnvSet');
+    local %ENV = %ENV;
+    $ENV{CATALYST_STATS} = 1;
+    my $app = mock_app('TestAppStatsEnvSet');
     $app->setup_stats();
     ok $app->use_stats, 'ENV turns stats on';
 }
 {
-    local %ENV = ( CATALYST_STATS => 0 );
-    my $app = mock_app('TestStatsAppStatsEnvUnset');
+    local %ENV = %ENV;
+    $ENV{CATALYST_STATS} = 0;
+    my $app = mock_app('TestAppStatsEnvUnset');
     $app->meta->add_method('debug' => sub { 1 });
     $app->setup_stats(1);
     ok !$app->use_stats, 'ENV turns stats off, even when debug on and ->setup_stats(1)';
index 731c4da..1ffff9c 100644 (file)
 # executing another action from the dispatcher (i.e. wrapping actions)
 # is present, so that the Authorization::ACL plugin can be re-written
 # to not be full of such crazy shit.
-{
-    package ACLTestApp;
-    use Test::More;
-
-    use strict;
-    use warnings;
-    use MRO::Compat;
-    use Scalar::Util ();
-
-    use base qw/Catalyst Catalyst::Controller/;
-    use Catalyst qw//;
-
-    sub execute {
-        my $c = shift;
-        my ( $class, $action ) = @_;
-
-        if ( Scalar::Util::blessed($action)
-            and $action->name ne "foobar" ) {
-              eval { $c->detach( 'foobar', [$action, 'foo'] ) };
-        }
-
-        $c->next::method( @_ );
-    }
-
-    sub foobar : Private {
-        die $Catalyst::DETACH;
-    }
-
-    sub gorch : Local {
-        my ( $self, $c, $frozjob ) = @_;
-        is $frozjob, 'wozzle';
-        $c->res->body("gorch");
-    }
-
-    __PACKAGE__->setup;
-}
 
 use strict;
 use warnings;
index cb3c1e2..3b91ef2 100644 (file)
@@ -1,23 +1,12 @@
-use Catalyst ();
+use strict;
+use warnings;
 
-{
-    package TestApp;
-    use base qw/Catalyst/;
-}
-{
-    package TestApp::Controller::Base;
-    use base qw/Catalyst::Controller/;
-}
-{
-    package TestApp::Controller::Other;
-    use base qw/TestApp::Controller::Base/;
-}
-
-TestApp->setup_component('TestApp::Controller::Other');
-TestApp->setup_component('TestApp::Controller::Base');
+use FindBin;
+use lib "$FindBin::Bin/lib";
 
 use Test::More tests => 1;
 use Test::Exception;
+use TestAppNonMooseController;
 
 # Metaclass init order causes fail.
 # There are TODO tests in Moose for this, see
@@ -25,6 +14,6 @@ use Test::Exception;
 # after which the evil kludge in core can die in a fire.
 
 lives_ok {
-    TestApp::Controller::Base->get_action_methods
+    TestAppNonMooseController::ControllerBase->get_action_methods
 } 'Base class->get_action_methods ok when sub class initialized first';
 
index 928b48e..676f354 100644 (file)
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 12;
+use Test::More tests => 13;
 use Time::HiRes qw/gettimeofday/;
 use Tree::Simple;
 
@@ -19,6 +19,8 @@ BEGIN { use_ok("Catalyst::Stats") };
     my $stats = Catalyst::Stats->new;
     is (ref($stats), "Catalyst::Stats", "new");
 
+    is_deeply([ $stats->created ], [0, 0], "created time");
+
     my @expected; # level, string, time
 
     $fudge_t[0] = 1;