From: John Napiorkowski Date: Fri, 12 Apr 2013 15:29:16 +0000 (-0400) Subject: prepped changelog X-Git-Tag: 5.90030~1 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Runtime.git;a=commitdiff_plain;h=f653d2c823617c580b943ebc7b5f44774cb2579d;hp=fa33a3ea47380bd1fad2f27f3b46ae7867532f55 prepped changelog --- diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..01c0852 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,46 @@ +language: perl +perl: + - "5.16" + - "5.14" + - "5.12" + - "5.10" + +install: + # git bits sometimes needed... + - git config user.name 'Travis-CI' + - git config user.email 'travis@nowhere.dne' + + # ensure we have the latest cpanm + - echo y | perlbrew install-cpanm + + # see if we can't speed things up a bit + - rm -rf ~/.cpanm + - mkdir ~/.cpanm + - sudo mount tmpfs -t tmpfs ~/.cpanm + + # these fail on parallel test runs + # Net::Server: https://rt.cpan.org/Ticket/Display.html?id=84126 + - cpanm --metacpan --skip-satisfied Net::Server Template File::Remove Filesys::Notify::Simple Config::Any CGI::Simple Plack + + # for testing + - cpanm --metacpan --skip-satisfied YAML + + # enable various test options, including parallel testing + - export AUTOMATED_TESTING=1 HARNESS_OPTIONS=j10:c HARNESS_TIMER=1 + + # M::I deps + - cpanm --metacpan --skip-satisfied Module::Install Module::Install::AuthorRequires Module::Install::CheckConflicts Module::Install::AuthorTests Module::Install::Authority + + # author deps -- wish there was a better way + - cpanm --metacpan --skip-satisfied CatalystX::LeakChecker Catalyst::Devel Catalyst::Engine::PSGI Starman MooseX::Daemonize + - cpanm --metacpan --skip-satisfied Test::Without::Module Test::NoTabs Test::Pod Test::Pod::Coverage Test::Spelling Pod::Coverage::TrustPod + - cpanm --metacpan --skip-satisfied --installdeps . + + # we want these for our tests, but not for any others + - export AUTHOR_TESTING=1 + - export RELEASE_TESTING=1 + + - make manifest + +script: + - make disttest diff --git a/Changes b/Changes index c10ca7f..abb8ce2 100644 --- a/Changes +++ b/Changes @@ -1,6 +1,16 @@ # This file documents the revision history for Perl extension Catalyst. -5.90021 - TBA +5.90030 - 2013-04-12 + ! POSSIBLE BREAKING CHANGE: Removed Regexp dispatch type from core, and put + it in an external package. If you need Regexp dispatch types you should + add "Catalyst-DispatchType-Regex" as a distribution to your build system. + - make $app->uri_for and related methods return something sane, when called + as an application method, instead of a context method. Now if you call + MyApp::Web->uri_for(...) you will get a generic URI object that you need to + resolve manually. + - documentation updates around forwarding to chained actions + - Fixed bug when a PSGI engine need to use psgix logger + - Added cpanfile as a way to notice we are a dev checkout - Added 'x-tunneled-method' HTTP Header method override to match features in Catalyst::Action::REST and in other similar systems on CPAN diff --git a/Makefile.PL b/Makefile.PL index 0ab8a7f..d906d0f 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -69,6 +69,10 @@ requires 'Plack' => '0.9991'; # IIS6+7 fix middleware requires 'Plack::Middleware::ReverseProxy' => '0.04'; requires 'Plack::Test::ExternalServer'; +# Install the standalone Regex dispatch modules in order to ease the +# depreciation transition +requires 'Catalyst::DispatchType::Regex' => '5.90021'; + test_requires 'Class::Data::Inheritable'; test_requires 'Test::Exception'; test_requires 'Test::More' => '0.88'; diff --git a/lib/Catalyst.pm b/lib/Catalyst.pm index 43bda89..a823b34 100644 --- a/lib/Catalyst.pm +++ b/lib/Catalyst.pm @@ -267,9 +267,9 @@ MYAPP_WEB_HOME. If both variables are set, the MYAPP_HOME one will be used. If none of these are set, Catalyst will attempt to automatically detect the home directory. If you are working in a development environment, Catalyst -will try and find the directory containing either Makefile.PL, Build.PL or -dist.ini. If the application has been installed into the system (i.e. -you have done C), then Catalyst will use the path to your +will try and find the directory containing either Makefile.PL, Build.PL, +dist.ini, or cpanfile. If the application has been installed into the system +(i.e. you have done C), then Catalyst will use the path to your application module, without the .pm extension (e.g., /foo/MyApp if your application was installed at /foo/MyApp.pm) @@ -1342,9 +1342,13 @@ sub uri_for { my $args = join('/', grep { defined($_) } @args); $args =~ s/\?/%3F/g; # STUPID STUPID SPECIAL CASE $args =~ s!^/+!!; - my $base = $c->req->base; - my $class = ref($base); - $base =~ s{(?req->base; + $class = ref($base); + $base =~ s{(? miyagawa: Tatsuhiko Miyagawa +mgrimes: Mark Grimes + mst: Matt S. Trout mugwump: Sam Vilain diff --git a/lib/Catalyst/Controller.pm b/lib/Catalyst/Controller.pm index b04ce96..28b54be 100644 --- a/lib/Catalyst/Controller.pm +++ b/lib/Catalyst/Controller.pm @@ -477,25 +477,6 @@ sub _parse_Path_attr { } } -sub _parse_Regex_attr { - my ( $self, $c, $name, $value ) = @_; - return ( 'Regex', $value ); -} - -sub _parse_Regexp_attr { shift->_parse_Regex_attr(@_); } - -sub _parse_LocalRegex_attr { - my ( $self, $c, $name, $value ) = @_; - unless ( $value =~ s/^\^// ) { $value = "(?:.*?)$value"; } - - my $prefix = $self->path_prefix( $c ); - $prefix .= '/' if length( $prefix ); - - return ( 'Regex', "^${prefix}${value}" ); -} - -sub _parse_LocalRegexp_attr { shift->_parse_LocalRegex_attr(@_); } - sub _parse_Chained_attr { my ($self, $c, $name, $value) = @_; @@ -668,7 +649,7 @@ overridden from the "namespace" config key. =head2 $self->path_prefix($c) -Returns the default path prefix for :PathPrefix, :Local, :LocalRegex and +Returns the default path prefix for :PathPrefix, :Local and relative :Path actions in this component. Defaults to the action_namespace or can be overridden from the "path" config key. @@ -770,7 +751,9 @@ This is a general toolbox for attaching your action to a give path. =head2 Regexp -Status: Deprecated. Use Chained methods or other techniques +B Use Chained methods or other techniques. +If you really depend on this, install the standalone +L distribution. A global way to match a give regular expression in the incoming request path. @@ -778,6 +761,10 @@ A global way to match a give regular expression in the incoming request path. =head2 LocalRegexp +B Use Chained methods or other techniques. +If you really depend on this, install the standalone +L distribution. + Like L but scoped under the namespace of the containing controller =head2 Chained diff --git a/lib/Catalyst/DispatchType/Chained.pm b/lib/Catalyst/DispatchType/Chained.pm index 5041442..44f890e 100644 --- a/lib/Catalyst/DispatchType/Chained.pm +++ b/lib/Catalyst/DispatchType/Chained.pm @@ -685,9 +685,11 @@ of the endpoint of the chain, not on the chained actions way. The C actions will be run before the chain dispatching begins. In every other aspect, C actions behave as documented. -The Cing to other actions does just what you would expect. But if -you C out of a chain, the rest of the chain will not get called -after the C. +The Cing to other actions does just what you would expect. i.e. +only the target action is run. The actions that that action is chained +to are not run. +If you C out of a chain, the rest of the chain will not get +called after the C. =head2 match_captures diff --git a/lib/Catalyst/DispatchType/Regex.pm b/lib/Catalyst/DispatchType/Regex.pm deleted file mode 100644 index 4b1beae..0000000 --- a/lib/Catalyst/DispatchType/Regex.pm +++ /dev/null @@ -1,185 +0,0 @@ -package Catalyst::DispatchType::Regex; - -use Moose; -extends 'Catalyst::DispatchType::Path'; - -use Text::SimpleTable; -use Catalyst::Utils; -use Text::Balanced (); - -has _compiled => ( - is => 'rw', - isa => 'ArrayRef', - required => 1, - default => sub{ [] }, - ); - -no Moose; - -=head1 NAME - -Catalyst::DispatchType::Regex - Regex DispatchType - -=head1 SYNOPSIS - -See L. - -=head1 DESCRIPTION - -Dispatch type managing path-matching behaviour using regexes. For -more information on dispatch types, see: - -=over 4 - -=item * L for how they affect application authors - -=item * L for implementation information. - -=back - -=head1 METHODS - -=head2 $self->list($c) - -Output a table of all regex actions, and their private equivalent. - -=cut - -sub list { - my ( $self, $c ) = @_; - 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" ); - } - $c->log->debug( "Loaded Regex actions:\n" . $re->draw . "\n" ) - if ( @{ $self->_compiled } ); -} - -=head2 $self->match( $c, $path ) - -Checks path against every compiled regex, and offers the action for any regex -which matches a chance to match the request. If it succeeds, sets action, -match and captures on $c->req and returns 1. If not, returns 0 without -altering $c. - -=cut - -sub match { - my ( $self, $c, $path ) = @_; - - return if $self->SUPER::match( $c, $path ); - - # Check path against plain text first - - foreach my $compiled ( @{ $self->_compiled } ) { - if ( my @captures = ( $path =~ $compiled->{re} ) ) { - next unless $compiled->{action}->match($c); - $c->req->action( $compiled->{path} ); - $c->req->match($path); - $c->req->captures( \@captures ); - $c->action( $compiled->{action} ); - $c->namespace( $compiled->{action}->namespace ); - return 1; - } - } - - return 0; -} - -=head2 $self->register( $c, $action ) - -Registers one or more regex actions for an action object. -Also registers them as literal paths. - -Returns 1 if any regexps were registered. - -=cut - -sub register { - my ( $self, $c, $action ) = @_; - my $attrs = $action->attributes; - my @register = @{ $attrs->{'Regex'} || [] }; - - foreach my $r (@register) { - $self->register_path( $c, $r, $action ); - $self->register_regex( $c, $r, $action ); - } - - return 1 if @register; - return 0; -} - -=head2 $self->register_regex($c, $re, $action) - -Register an individual regex on the action. Usually called from the -register method. - -=cut - -sub register_regex { - my ( $self, $c, $re, $action ) = @_; - push( - @{ $self->_compiled }, # and compiled regex for us - { - re => qr#$re#, - action => $action, - path => $re, - } - ); -} - -=head2 $self->uri_for_action($action, $captures) - -returns a URI for this action if it can find a regex attributes that contains -the correct number of () captures. Note that this may function incorrectly -in the case of nested captures - if your regex does (...(..))..(..) you'll -need to pass the first and third captures only. - -=cut - -sub uri_for_action { - my ( $self, $action, $captures ) = @_; - - if (my $regexes = $action->attributes->{Regex}) { - REGEX: foreach my $orig (@$regexes) { - my $re = "$orig"; - $re =~ s/^\^//; - $re =~ s/\$$//; - $re =~ s/\\([^\\])/$1/g; - my $final = '/'; - my @captures = @$captures; - while (my ($front, $rest) = split(/\(/, $re, 2)) { - last unless defined $rest; - ($rest, $re) = - Text::Balanced::extract_bracketed("(${rest}", '('); - next REGEX unless @captures; - $final .= $front.shift(@captures); - } - $final .= $re; - next REGEX if @captures; - return $final; - } - } - return undef; -} - -=head1 AUTHORS - -Catalyst Contributors, see Catalyst.pm - -=head1 COPYRIGHT - -This library is free software. You can redistribute it and/or modify it under -the same terms as Perl itself. - -=cut - -__PACKAGE__->meta->make_immutable; - -1; diff --git a/lib/Catalyst/Dispatcher.pm b/lib/Catalyst/Dispatcher.pm index fb1efea..d9fe5b3 100644 --- a/lib/Catalyst/Dispatcher.pm +++ b/lib/Catalyst/Dispatcher.pm @@ -22,7 +22,7 @@ use namespace::clean -except => 'meta'; # See Catalyst-Plugin-Server for them being added to, which should be much less ugly. # Preload these action types -our @PRELOAD = qw/Index Path Regex/; +our @PRELOAD = qw/Index Path/; # Postload these action types our @POSTLOAD = qw/Default/; @@ -517,7 +517,9 @@ sub register { # FIXME - Some error checking and re-throwing needed here, as # we eat exceptions loading dispatch types. eval { Class::MOP::load_class($class) }; - push( @{ $self->dispatch_types }, $class->new ) unless $@; + my $load_failed = $@; + $self->_check_deprecated_dispatch_type( $key, $load_failed ); + push( @{ $self->dispatch_types }, $class->new ) unless $load_failed; $registered->{$class} = 1; } } @@ -689,6 +691,28 @@ sub dispatch_type { return undef; } +sub _check_deprecated_dispatch_type { + my ($self, $key, $load_failed) = @_; + + return unless $key =~ /^(Local)?Regexp?/; + + # TODO: Should these throw an exception rather than just warning? + if ($load_failed) { + warn( "Attempt to use deprecated $key dispatch type.\n" + . " Use Chained methods or install the standalone\n" + . " Catalyst::DispatchType::Regex if necessary.\n" ); + } elsif ( !defined $Catalyst::DispatchType::Regex::VERSION + || $Catalyst::DispatchType::Regex::VERSION le '5.90020' ) { + # We loaded the old core version of the Regex module this will break + warn( "The $key DispatchType has been removed from Catalyst core.\n" + . " An old version of the core Catalyst::DispatchType::Regex\n" + . " has been loaded and will likely fail. Please remove\n" + . " $INC{'Catalyst/DispatchType/Regex.pm'}\n" + . " and use Chained methods or install the standalone\n" + . " Catalyst::DispatchType::Regex if necessary.\n" ); + } +} + use Moose; # 5.70 backwards compatibility hacks. diff --git a/lib/Catalyst/Engine.pm b/lib/Catalyst/Engine.pm index 8386639..2367139 100644 --- a/lib/Catalyst/Engine.pm +++ b/lib/Catalyst/Engine.pm @@ -543,6 +543,7 @@ Populate the context object from the request object. sub prepare_request { my ($self, $ctx, %args) = @_; + $ctx->log->psgienv($args{env}) if $ctx->log->can('psgienv'); $ctx->request->_set_env($args{env}); $self->_set_env($args{env}); # Nasty back compat! $ctx->response->_set_response_cb($args{response_cb}); diff --git a/lib/Catalyst/Log.pm b/lib/Catalyst/Log.pm index b035d89..d72ee16 100644 --- a/lib/Catalyst/Log.pm +++ b/lib/Catalyst/Log.pm @@ -13,6 +13,22 @@ our %LEVEL_MATCH = (); # Stored as additive, thus debug = 31, warn = 30 etc has level => (is => 'rw'); has _body => (is => 'rw'); has abort => (is => 'rw'); +has _psgi_logger => (is => 'rw', predicate => '_has_psgi_logger', clearer => '_clear_psgi_logger'); +has _psgi_errors => (is => 'rw', predicate => '_has_psgi_errors', clearer => '_clear_psgi_errors'); + +sub clear_psgi { + my $self = shift; + $self->_clear_psgi_logger; + $self->_clear_psgi_errors; +} + +sub psgienv { + my ($self, $env) = @_; + + $self->_psgi_logger($env->{'psgix.logger'}) if $env->{'psgix.logger'}; + $self->_psgi_errors($env->{'psgi.errors'}) if $env->{'psgi.errors'}; +} + { my @levels = qw[ debug info warn error fatal ]; @@ -91,10 +107,17 @@ sub _log { my $self = shift; my $level = shift; my $message = join( "\n", @_ ); - $message .= "\n" unless $message =~ /\n$/; - my $body = $self->_body; - $body .= sprintf( "[%s] %s", $level, $message ); - $self->_body($body); + if ($self->can('_has_psgi_logger') and $self->_has_psgi_logger) { + $self->_psgi_logger->({ + level => $level, + message => $message, + }); + } else { + $message .= "\n" unless $message =~ /\n$/; + my $body = $self->_body; + $body .= sprintf( "[%s] %s", $level, $message ); + $self->_body($body); + } } sub _flush { @@ -110,7 +133,11 @@ sub _flush { sub _send_to_log { my $self = shift; - print STDERR @_; + if ($self->can('_has_psgi_errors') and $self->_has_psgi_errors) { + $self->_psgi_errors->print(@_); + } else { + print STDERR @_; + } } # 5.7 compat code. @@ -135,6 +162,8 @@ __PACKAGE__->meta->make_immutable(inline_constructor => 0); __END__ +=for stopwords psgienv + =head1 NAME Catalyst::Log - Catalyst Log Class @@ -263,6 +292,21 @@ This protected method is what actually sends the log information to STDERR. You may subclass this module and override this method to get finer control over the log output. +=head2 psgienv $env + + $log->psgienv($env); + +NOTE: This is not meant for public consumption. + +Set the PSGI environment for this request. This ensures logs will be sent to +the right place. If the environment has a C, it will be used. If +not, we will send logs to C if that exists. As a last fallback, we +will send to STDERR as before. + +=head2 clear_psgi + +Clears the PSGI environment attributes set by L. + =head2 meta =head1 SEE ALSO diff --git a/lib/Catalyst/Upgrading.pod b/lib/Catalyst/Upgrading.pod index 6157b55..b6d3c8b 100644 --- a/lib/Catalyst/Upgrading.pod +++ b/lib/Catalyst/Upgrading.pod @@ -214,6 +214,15 @@ This behavior has been removed, and now a 500 response will be returned to the test. This change standardizes behavior, so that local test requests behave similarly to remote requests. +=head2 Regex dispatch type is deprecated. + +The Regex dispatchtype (L) has been deprecated. + +You are encouraged to move your application to Chained dispatch (L). + +If you cannot do so, please add a dependency to Catalyst::DispatchType::Regex to your application's +Makefile.PL + =head1 Upgrading to Catalyst 5.80 Most applications and plugins should run unaltered on Catalyst 5.80. diff --git a/lib/Catalyst/Utils.pm b/lib/Catalyst/Utils.pm index d46e143..245c789 100644 --- a/lib/Catalyst/Utils.pm +++ b/lib/Catalyst/Utils.pm @@ -173,12 +173,14 @@ These are: =item dist.ini +=item L + =back =cut sub dist_indicator_file_list { - qw{Makefile.PL Build.PL dist.ini}; + qw{Makefile.PL Build.PL dist.ini cpanfile}; } sub home { diff --git a/t/aggregate/live_component_controller_action_regexp.t b/t/aggregate/live_component_controller_action_regexp.t deleted file mode 100644 index fd65665..0000000 --- a/t/aggregate/live_component_controller_action_regexp.t +++ /dev/null @@ -1,141 +0,0 @@ -#!perl - -use strict; -use warnings; - -use FindBin; -use lib "$FindBin::Bin/../lib"; - -our $iters; - -BEGIN { $iters = $ENV{CAT_BENCH_ITERS} || 1; } - -use Test::More tests => 38*$iters; -use Catalyst::Test 'TestApp'; - -use Catalyst::Request; - -if ( $ENV{CAT_BENCHMARK} ) { - require Benchmark; - Benchmark::timethis( $iters, \&run_tests ); -} -else { - for ( 1 .. $iters ) { - run_tests(); - } -} - -sub run_tests { - { - ok( my $response = request('http://localhost/action/regexp/10/hello'), - 'Request' ); - ok( $response->is_success, 'Response Successful 2xx' ); - is( $response->content_type, 'text/plain', 'Response Content-Type' ); - is( $response->header('X-Catalyst-Action'), - '^action/regexp/(\d+)/(\w+)$', 'Test Action' ); - is( - $response->header('X-Test-Class'), - 'TestApp::Controller::Action::Regexp', - 'Test Class' - ); - like( - $response->content, - qr/^bless\( .* 'Catalyst::Request' \)$/s, - 'Content is a serialized Catalyst::Request' - ); - } - - { - ok( my $response = request('http://localhost/action/regexp/hello/10'), - 'Request' ); - ok( $response->is_success, 'Response Successful 2xx' ); - is( $response->content_type, 'text/plain', 'Response Content-Type' ); - is( $response->header('X-Catalyst-Action'), - '^action/regexp/(\w+)/(\d+)$', 'Test Action' ); - is( - $response->header('X-Test-Class'), - 'TestApp::Controller::Action::Regexp', - 'Test Class' - ); - like( - $response->content, - qr/^bless\( .* 'Catalyst::Request' \)$/s, - 'Content is a serialized Catalyst::Request' - ); - } - - { - ok( my $response = request('http://localhost/action/regexp/mandatory'), - 'Request' ); - ok( $response->is_success, 'Response Successful 2xx' ); - is( $response->content_type, 'text/plain', 'Response Content-Type' ); - is( $response->header('X-Catalyst-Action'), - '^action/regexp/(mandatory)(/optional)?$', 'Test Action' ); - is( - $response->header('X-Test-Class'), - 'TestApp::Controller::Action::Regexp', - 'Test Class' - ); - my $content = $response->content; - my $req = eval $content; - - is( scalar @{ $req->captures }, 2, 'number of captures' ); - is( $req->captures->[ 0 ], 'mandatory', 'mandatory capture' ); - ok( !defined $req->captures->[ 1 ], 'optional capture' ); - } - - { - ok( my $response = request('http://localhost/action/regexp/mandatory/optional'), - 'Request' ); - ok( $response->is_success, 'Response Successful 2xx' ); - is( $response->content_type, 'text/plain', 'Response Content-Type' ); - is( $response->header('X-Catalyst-Action'), - '^action/regexp/(mandatory)(/optional)?$', 'Test Action' ); - is( - $response->header('X-Test-Class'), - 'TestApp::Controller::Action::Regexp', - 'Test Class' - ); - my $content = $response->content; - my $req = eval $content; - - is( scalar @{ $req->captures }, 2, 'number of captures' ); - is( $req->captures->[ 0 ], 'mandatory', 'mandatory capture' ); - is( $req->captures->[ 1 ], '/optional', 'optional capture' ); - } - - # test localregex in the root controller - { - ok( my $response = request('http://localhost/localregex'), - 'Request' ); - ok( $response->is_success, 'Response Successful 2xx' ); - is( $response->content_type, 'text/plain', 'Response Content-Type' ); - is( $response->header('X-Catalyst-Action'), - '^localregex$', 'Test Action' ); - is( - $response->header('X-Test-Class'), - 'TestApp::Controller::Root', - 'Test Class' - ); - } - - { - my $url = 'http://localhost/action/regexp/redirect/life/universe/42/everything'; - ok( my $response = request($url), - 'Request' ); - ok( $response->is_redirect, 'Response is redirect' ); - is( $response->header('X-Catalyst-Action'), - '^action/regexp/redirect/(\w+)/universe/(\d+)/everything$', 'Test Action' ); - is( - $response->header('X-Test-Class'), - 'TestApp::Controller::Action::Regexp', - 'Test Class' - ); - is( - $response->header('location'), - $response->request->uri, - 'Redirect URI is the same as the request URI' - ); - } -} - diff --git a/t/aggregate/live_priorities.t b/t/aggregate/live_priorities.t index 1e05747..bd28d25 100644 --- a/t/aggregate/live_priorities.t +++ b/t/aggregate/live_priorities.t @@ -6,7 +6,7 @@ use warnings; use FindBin; use lib "$FindBin::Bin/../lib"; -use Test::More tests => 28; +use Test::More tests => 14; use Catalyst::Test 'TestApp'; local $^W = 0; @@ -15,18 +15,11 @@ my $uri_base = 'http://localhost/priorities'; my @tests = ( # Simple - 'Regex vs. Local', { path => '/re_vs_loc', expect => 'local' }, - 'Regex vs. LocalRegex', { path => '/re_vs_locre', expect => 'regex' }, - 'Regex vs. Path', { path => '/re_vs_path', expect => 'path' }, - 'Local vs. LocalRegex', { path => '/loc_vs_locre', expect => 'local' }, 'Local vs. Path 1', { path => '/loc_vs_path1', expect => 'local' }, 'Local vs. Path 2', { path => '/loc_vs_path2', expect => 'path' }, - 'Path vs. LocalRegex', { path => '/path_vs_locre', expect => 'path' }, # index - 'index vs. Regex', { path => '/re_vs_index', expect => 'index' }, 'index vs. Local', { path => '/loc_vs_index', expect => 'index' }, - 'index vs. LocalRegex', { path => '/locre_vs_index', expect => 'index' }, 'index vs. Path', { path => '/path_vs_index', expect => 'index' }, 'multimethod zero', { path => '/multimethod', expect => 'zero' }, diff --git a/t/aggregate/unit_core_uri_for_action.t b/t/aggregate/unit_core_uri_for_action.t index 9b34229..156f79e 100644 --- a/t/aggregate/unit_core_uri_for_action.t +++ b/t/aggregate/unit_core_uri_for_action.t @@ -36,38 +36,6 @@ ok(!defined($dispatcher->uri_for_action($path_action, [ 'foo' ])), "no URI returned for Path action when snippets are given"); # -# Regex Action -# -my $regex_action = $dispatcher->get_action_by_path( - '/action/regexp/one' - ); - -ok(!defined($dispatcher->uri_for_action($regex_action)), - "Regex action without captures returns undef"); - -ok(!defined($dispatcher->uri_for_action($regex_action, [ 1, 2, 3 ])), - "Regex action with too many captures returns undef"); - -is($dispatcher->uri_for_action($regex_action, [ 'foo', 123 ]), - "/action/regexp/foo/123", - "Regex action interpolates captures correctly"); - -my $regex_action_bs = $dispatcher->get_action_by_path( - '/action/regexp/one_backslashes' - ); - -ok(!defined($dispatcher->uri_for_action($regex_action_bs)), - "Regex action without captures returns undef"); - -ok(!defined($dispatcher->uri_for_action($regex_action_bs, [ 1, 2, 3 ])), - "Regex action with too many captures returns undef"); - -is($dispatcher->uri_for_action($regex_action_bs, [ 'foo', 123 ]), - "/action/regexp/foo/123.html", - "Regex action interpolates captures correctly"); - - -# # Index Action # my $index_action = $dispatcher->get_action_by_path( @@ -126,10 +94,6 @@ is($context->uri_for($path_action, qw/one two/, { q => 1 }), ok(!defined($context->uri_for($path_action, [ 'blah' ])), "no URI returned by uri_for for Path action with snippets"); -is($context->uri_for($regex_action, [ 'foo', 123 ], qw/bar baz/, { q => 1 }), - "http://127.0.0.1/foo/action/regexp/foo/123/bar/baz?q=1", - "uri_for correct for regex with captures, args and query"); - is($context->uri_for($chained_action, [ 1 ], 2, { q => 1 }), "http://127.0.0.1/foo/chained/foo/1/end/2?q=1", "uri_for correct for chained with captures, args and query"); diff --git a/t/aggregate/unit_utils_home.t b/t/aggregate/unit_utils_home.t index 4a11c08..139e021 100644 --- a/t/aggregate/unit_utils_home.t +++ b/t/aggregate/unit_utils_home.t @@ -9,7 +9,7 @@ use Path::Class qw/ dir /; use Cwd qw/ cwd /; my @dists = Catalyst::Utils::dist_indicator_file_list(); -is(scalar(@dists), 3, 'Makefile.PL Build.PL dist.ini'); +is(scalar(@dists), 4, 'Makefile.PL Build.PL dist.ini cpanfile'); my $cwd = cwd(); foreach my $inc ('', 'lib', 'blib'){ diff --git a/t/author/spelling.t b/t/author/spelling.t index edb24e6..4213b3b 100644 --- a/t/author/spelling.t +++ b/t/author/spelling.t @@ -16,7 +16,7 @@ add_stopwords(qw( BUILDARGS metaclass namespaces pre ARGV ReverseProxy filename tempname request's subdirectory ini uninstalled uppercased wiki bitmask uri url urls dir hostname proxied http https IP SSL - inline INLINE plugins + inline INLINE plugins cpanfile FastCGI Stringifies Rethrows DispatchType Wishlist Refactor ROADMAP HTTPS Unescapes Restarter Nginx Refactored ActionClass LocalRegex LocalRegexp MyAction metadata Andreas @@ -104,6 +104,7 @@ add_stopwords(qw( jon konobi marcus + mgrimes miyagawa mst naughton diff --git a/t/lib/TestApp/Controller/Action/Regexp.pm b/t/lib/TestApp/Controller/Action/Regexp.pm deleted file mode 100644 index 7966874..0000000 --- a/t/lib/TestApp/Controller/Action/Regexp.pm +++ /dev/null @@ -1,35 +0,0 @@ -package TestApp::Controller::Action::Regexp; - -use strict; -use base 'TestApp::Controller::Action'; - -sub one : Action Regex('^action/regexp/(\w+)/(\d+)$') { - my ( $self, $c ) = @_; - $c->forward('TestApp::View::Dump::Request'); -} - -sub two : Action LocalRegexp('^(\d+)/(\w+)$') { - my ( $self, $c ) = @_; - $c->forward('TestApp::View::Dump::Request'); -} - -sub three : Action LocalRegex('^(mandatory)(/optional)?$'){ - my ( $self, $c ) = @_; - $c->forward('TestApp::View::Dump::Request'); -} - -sub four : Action Regex('^action/regexp/redirect/(\w+)/universe/(\d+)/everything$') { - my ( $self, $c ) = @_; - $c->res->redirect( - $c->uri_for($c->action, $c->req->captures, - @{$c->req->arguments}, $c->req->params - ) - ); -} - -sub one_backslashes : Action Regex('^action/regexp/(\w+)/(\d+)\.html$') { - my ( $self, $c ) = @_; - $c->forward('TestApp::View::Dump::Request'); -} - -1; diff --git a/t/lib/TestApp/Controller/Log.pm b/t/lib/TestApp/Controller/Log.pm new file mode 100644 index 0000000..1a8cf0a --- /dev/null +++ b/t/lib/TestApp/Controller/Log.pm @@ -0,0 +1,14 @@ +package TestApp::Controller::Log; + +use strict; +use base 'Catalyst::Controller'; + +sub debug :Local { + my ( $self, $c ) = @_; + $c->log->debug('debug'); + $c->res->body( 'logged' ); +} + + +1; + diff --git a/t/lib/TestApp/Controller/Priorities.pm b/t/lib/TestApp/Controller/Priorities.pm index 751270b..b9daa88 100644 --- a/t/lib/TestApp/Controller/Priorities.pm +++ b/t/lib/TestApp/Controller/Priorities.pm @@ -4,34 +4,6 @@ use strict; use base 'Catalyst::Controller'; # -# Regex vs. Local -# - -sub re_vs_loc_re :Regex('/priorities/re_vs_loc') { $_[1]->res->body( 'regex' ) } -sub re_vs_loc :Local { $_[1]->res->body( 'local' ) } - -# -# Regex vs. LocalRegex -# - -sub re_vs_locre_locre :LocalRegex('re_vs_(locre)') { $_[1]->res->body( 'local_regex' ) } -sub re_vs_locre_re :Regex('/priorities/re_vs_locre') { $_[1]->res->body( 'regex' ) } - -# -# Regex vs. Path -# - -sub re_vs_path_path :Path('/priorities/re_vs_path') { $_[1]->res->body( 'path' ) } -sub re_vs_path_re :Regex('/priorities/re_vs_path') { $_[1]->res->body( 'regex' ) } - -# -# Local vs. LocalRegex -# - -sub loc_vs_locre_locre :LocalRegex('loc_vs_locre') { $_[1]->res->body( 'local_regex' ) } -sub loc_vs_locre :Local { $_[1]->res->body( 'local' ) } - -# # Local vs. Path (depends on definition order) # @@ -42,31 +14,12 @@ sub loc_vs_path2 :Local { $_[1]->res->body( 'loca sub loc_vs_path2_loc :Path('/priorities/loc_vs_path2') { $_[1]->res->body( 'path' ) } # -# Path vs. LocalRegex -# - -sub path_vs_locre_locre :LocalRegex('path_vs_(locre)') { $_[1]->res->body( 'local_regex' ) } -sub path_vs_locre_path :Path('/priorities/path_vs_locre') { $_[1]->res->body( 'path' ) } - -# -# Regex vs. index (has sub controller) -# - -sub re_vs_idx :Regex('/priorities/re_vs_index') { $_[1]->res->body( 'regex' ) } - -# # Local vs. index (has sub controller) # sub loc_vs_index :Local { $_[1]->res->body( 'local' ) } # -# LocalRegex vs. index (has sub controller) -# - -sub locre_vs_idx :LocalRegex('locre_vs_index') { $_[1]->res->body( 'local_regex' ) } - -# # Path vs. index (has sub controller) # diff --git a/t/lib/TestApp/Controller/Priorities/re_vs_index.pm b/t/lib/TestApp/Controller/Priorities/re_vs_index.pm deleted file mode 100644 index da56b89..0000000 --- a/t/lib/TestApp/Controller/Priorities/re_vs_index.pm +++ /dev/null @@ -1,8 +0,0 @@ -package TestApp::Controller::Priorities::re_vs_index; - -use strict; -use base 'Catalyst::Controller'; - -sub index :Private { $_[1]->res->body( 'index' ) } - -1; diff --git a/t/lib/TestApp/Controller/Root.pm b/t/lib/TestApp/Controller/Root.pm index e5137e0..f2acb21 100644 --- a/t/lib/TestApp/Controller/Root.pm +++ b/t/lib/TestApp/Controller/Root.pm @@ -24,13 +24,6 @@ sub emptybody : Local { $c->res->body(''); } -sub localregex : LocalRegex('^localregex$') { - my ( $self, $c ) = @_; - $c->res->header( 'X-Test-Class' => ref($self) ); - $c->response->content_type('text/plain; charset=utf-8'); - $c->forward('TestApp::View::Dump::Request'); -} - sub index : Private { my ( $self, $c ) = @_; $c->res->body('root index'); diff --git a/t/lib/TestApp/View/Dump.pm b/t/lib/TestApp/View/Dump.pm index afbc0eb..dff41e8 100644 --- a/t/lib/TestApp/View/Dump.pm +++ b/t/lib/TestApp/View/Dump.pm @@ -39,6 +39,10 @@ sub process { # Remove context from reference if needed my $context = delete $reference->{_context}; + if (my $log = $reference->{_log}) { + $log->clear_psgi if ($log->can('psgienv')); + } + if ( my $output = $self->dump( $reference, $purity ) ) { diff --git a/t/psgi-log.t b/t/psgi-log.t new file mode 100644 index 0000000..e010d07 --- /dev/null +++ b/t/psgi-log.t @@ -0,0 +1,106 @@ +=head1 PROBLEM + +In https://github.com/plack/Plack/commit/cafa5db84921f020183a9c834fd6a4541e5a6b84 +chansen made a change to the FCGI handler in Plack, in which he replaced +STDERR, STDOUT and STDIN with proper IO::Handle objects. + +The side effect of that change is that catalyst outputing logs on STDERR will +no longer end up by default in the error log of the webserver when running +under FCGI. This test tries to make sure we use the propper parts of the psgi +environment when we output things from Catalyst::Log. + +There is one more "regression", and that is warnings. By using +Catalyst::Plugin::LogWarnings, you also get those in the right place if this +test passes :) + +=cut + +use strict; +use warnings; +no warnings 'once'; +use FindBin; +use lib "$FindBin::Bin/lib"; + +use Test::More; + +use File::Spec; +use File::Temp qw/ tempdir /; + +use TestApp; + +use Plack::Builder; +use Plack::Test; +use HTTP::Request::Common; + +{ + package MockHandle; + use Moose; + + has 'log' => (is => 'ro', isa => 'ArrayRef', traits => ['Array'], default => sub { [] }, + handles => { + 'logs' => 'elements', + 'print' => 'push', + } + ); + + no Moose; +} + +#subtest "psgi.errors" => sub +{ + + my $handle = MockHandle->new(); + my $app = builder { + + enable sub { + my $app = shift; + sub { + my $env = shift; + $env->{'psgi.errors'} = $handle; + my $res = $app->($env); + return $res; + }; + }; + TestApp->psgi_app; + }; + + + test_psgi $app, sub { + my $cb = shift; + my $res = $cb->(GET "/log/debug"); + my @logs = $handle->logs; + is(scalar(@logs), 1, "psgi.errors: one event output"); + like($logs[0], qr/debug$/, "psgi.errors: event matches test data"); + }; +}; + +#subtest "psgix.logger" => sub +{ + + my @logs; + my $logger = sub { + push(@logs, @_); + }; + my $app = builder { + enable sub { + my $app = shift; + sub { + my $env = shift; + $env->{'psgix.logger'} = $logger; + $app->($env); + }; + }; + TestApp->psgi_app; + }; + + test_psgi $app, sub { + my $cb = shift; + my $res = $cb->(GET "/log/debug"); + is(scalar(@logs), 1, "psgix.logger: one event logged"); + is_deeply($logs[0], { level => 'debug', message => "debug" }, "psgix.logger: right stuff"); + }; +}; + + + +done_testing;