From: John Napiorkowski Date: Wed, 25 Mar 2015 20:24:33 +0000 (-0500) Subject: merged from master to sync release X-Git-Tag: 5.90089_002~27 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Runtime.git;a=commitdiff_plain;h=130b45ec858db6863e3d6959f7a6e3b6908cd48e;hp=-c merged from master to sync release --- 130b45ec858db6863e3d6959f7a6e3b6908cd48e diff --combined Changes index 0d1c586,595d249..e1eaea0 --- a/Changes +++ b/Changes @@@ -1,11 -1,19 +1,25 @@@ # This file documents the revision history for Perl extension Catalyst. +5.90089_001 - TBA + - New Feature: Type Constraints on Args/CapturArgs. ALlows you to declare + a Moose, MooseX::Types or Type::Tiny named constraint on your Arg or + CaptureArg. + - New top level document on Route matching. (Catalyst::RouteMatching). + + 5.90085 - 2015-03-25 + - Small change to Catalyst::Action to prevent autovivication of Args value (dim1++) + - Minor typo fixes (Abraxxa++) + - Make sure than when using chained actions and when more than one action + matches the same path specification AND has Args(0), that we follow the + "in a tie, the last action defined wins" rule. There is a small chance + this is a breaking change for you. See Catalyst::Upgrading for more. + You may use the application configuration setting "use_chained_args_0_special_case" + to disable this new behavior, if you must for back-compat reasons. + - Added PATCH HTTP Method action attribute shortcut. + - Several new configuration options aimed to give improved backwards compatibility + for when your URL query parameters or keywords have non UTF-8 encodings. + See Catalyst::Upgrading. + 5.90084 - 2015-02-23 - Small change to the way body parameters are created in order to prevent trying to create parameters twice. diff --combined lib/Catalyst.pm index 0d8a817,03b49c6..03acccc --- a/lib/Catalyst.pm +++ b/lib/Catalyst.pm @@@ -129,7 -129,7 +129,7 @@@ __PACKAGE__->stats_class('Catalyst::Sta __PACKAGE__->_encode_check(Encode::FB_CROAK | Encode::LEAVE_SRC); # Remember to update this in Catalyst::Runtime as well! -our $VERSION = '5.90085'; +our $VERSION = '5.90089_001'; $VERSION = eval $VERSION if $VERSION =~ /_/; # numify for warning-free dev releases sub import { @@@ -3904,6 -3904,51 +3904,51 @@@ parameter to true =item * + C + + If true, then do not try to character decode any wide characters in your + request URL query or keywords. Most readings of the relevent specifications + suggest these should be UTF-* encoded, which is the default that L + will use, hwoever if you are creating a lot of URLs manually or have external + evil clients, this might cause you trouble. If you find the changes introduced + in Catalyst version 5.90080+ break some of your query code, you may disable + the UTF-8 decoding globally using this configuration. + + This setting takes precedence over C and + C + + =item * + + C + + By default we decode query and keywords in your request URL using UTF-8, which + is our reading of the relevent specifications. This setting allows one to + specify a fixed value for how to decode your query. You might need this if + you are doing a lot of custom encoding of your URLs and not using UTF-8. + + This setting take precedence over C. + + =item * + + C + + Setting this to true will default your query decoding to whatever your + general global encoding is (the default is UTF-8). + + =item * + + C + + In older versions of Catalyst, when more than one action matched the same path + AND all those matching actions declared Args(0), we'd break the tie by choosing + the first action defined. We now normalized how Args(0) works so that it + follows the same rule as Args(N), which is to say when we need to break a tie + we choose the LAST action defined. If this breaks your code and you don't + have time to update to follow the new normalized approach, you may set this + value to true and it will globally revert to the original chaining behavior. + + =item * + C - See L. =item * diff --combined lib/Catalyst/Controller.pm index c94f22e,67ecee7..9b8b037 --- a/lib/Catalyst/Controller.pm +++ b/lib/Catalyst/Controller.pm @@@ -550,6 -550,7 +550,7 @@@ sub _parse_PUT_attr { Method => 'PU sub _parse_DELETE_attr { Method => 'DELETE' } sub _parse_OPTIONS_attr { Method => 'OPTIONS' } sub _parse_HEAD_attr { Method => 'HEAD' } + sub _parse_PATCH_attr { Method => 'PATCH' } sub _expand_role_shortname { my ($self, @shortnames) = @_; @@@ -786,29 -787,7 +787,29 @@@ Like L but scoped under the nam =head2 CaptureArgs -Please see L +Allowed values for CaptureArgs is a single integer (CaptureArgs(2), meaning two +allowed) or you can declare a L, L or L +named constraint such as CaptureArgs(Int,Str) would require two args with +the first being a Integer and the second a string. You may declare your own +custom type constraints and import them into the controller namespace: + + package MyApp::Controller::Root; + + use Moose; + use MooseX::MethodAttributes; + use MyApp::Types qw/Int/; + + extends 'Catalyst::Controller'; + + sub chain_base :Chained(/) CaptureArgs(1) { } + + sub any_priority_chain :Chained(chain_base) PathPart('') Args(1) { } + + sub int_priority_chain :Chained(chain_base) PathPart('') Args(Int) { } + +See L for more. + +Please see L for more. =head2 ActionClass @@@ -858,38 -837,6 +859,38 @@@ When used with L indicates the n the path. However if no Args value is set, assumed to 'slurp' all remaining path pars under this namespace. +Allowed values for Args is a single integer (Args(2), meaning two allowed) or you +can declare a L, L or L named constraint such +as Args(Int,Str) would require two args with the first being a Integer and the +second a string. You may declare your own custom type constraints and import +them into the controller namespace: + + package MyApp::Controller::Root; + + use Moose; + use MooseX::MethodAttributes; + use MyApp::Types qw/Tuple Int Str StrMatch UserId/; + + extends 'Catalyst::Controller'; + + sub user :Local Args(UserId) { + my ($self, $c, $int) = @_; + } + + sub an_int :Local Args(Int) { + my ($self, $c, $int) = @_; + } + + sub many_ints :Local Args(ArrayRef[Int]) { + my ($self, $c, @ints) = @_; + } + + sub match :Local Args(StrMatch[qr{\d\d-\d\d-\d\d}]) { + my ($self, $c, $int) = @_; + } + +See L for more. + =head2 Consumes('...') Matches the current action against the content-type of the request. Typically diff --combined lib/Catalyst/DispatchType/Chained.pm index 421175f,831f6e8..b9d6d07 --- a/lib/Catalyst/DispatchType/Chained.pm +++ b/lib/Catalyst/DispatchType/Chained.pm @@@ -98,7 -98,7 +98,7 @@@ sub list @{ $self->_endpoints } ) { my $args = $endpoint->list_extra_info->{Args}; - my @parts = (defined($args) ? (("*") x $args) : '...'); + my @parts = (defined($endpoint->attributes->{Args}[0]) ? (("*") x $args) : '...'); my @parents = (); my $parent = "DUMMY"; my $extra = $self->_list_extra_http_methods($endpoint); @@@ -130,12 -130,7 +130,12 @@@ $name = "${extra} ${name}"; } if (defined(my $cap = $p->list_extra_info->{CaptureArgs})) { - $name .= ' ('.$cap.')'; + if($p->has_captures_constraints) { + my $tc = join ',', @{$p->captures_constraints}; + $name .= " ($tc)"; + } else { + $name .= " ($cap)"; + } } if (defined(my $ct = $p->list_extra_info->{Consumes})) { $name .= ' :'.$ct; @@@ -149,13 -144,6 +149,13 @@@ } push(@rows, [ '', $name ]); } + + if($endpoint->has_args_constraints) { + my $tc = join ',', @{$endpoint->args_constraints}; + $endpoint .= " ($tc)"; + } else { + $endpoint .= defined($endpoint->attributes->{Args}[0]) ? " ($args)" : " (...)"; + } push(@rows, [ '', (@rows ? "=> " : '').($extra ? "$extra " : ''). ($scheme ? "$scheme: ":'')."/${endpoint}". ($consumes ? " :$consumes":"" ) ]); my @display_parts = map { $_ =~s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg; decode_utf8 $_ } @parts; $rows[0][0] = join('/', '', @display_parts) || '/'; @@@ -248,7 -236,7 +248,7 @@@ sub recurse_match my @try_actions = @{$children->{$try_part}}; TRY_ACTION: foreach my $action (@try_actions) { if (my $capture_attr = $action->attributes->{CaptureArgs}) { - my $capture_count = $capture_attr->[0] || 0; + my $capture_count = $action->number_of_captures|| 0; # Short-circuit if not enough remaining parts next TRY_ACTION unless @parts >= $capture_count; @@@ -260,7 -248,7 +260,7 @@@ push(@captures, splice(@parts, 0, $capture_count)); # check if the action may fit, depending on a given test by the app - if ($action->can('match_captures')) { next TRY_ACTION unless $action->match_captures($c, \@captures) } + next TRY_ACTION unless $action->match_captures($c, \@captures); # try the remaining parts against children of this action my ($actions, $captures, $action_parts, $n_pathparts) = $self->recurse_match( @@@ -298,13 -286,29 +298,29 @@@ # The current best action might also be Args(0), # but we couldn't chose between then anyway so we'll take the last seen - if (!$best_action || + if ( + !$best_action || @parts < @{$best_action->{parts}} || - (!@parts && defined($args_attr) && $args_attr eq "0")){ + ( + !@parts && + defined($args_attr) && + ( + $args_attr eq "0" && + ( + ($c->config->{use_chained_args_0_special_case}||0) || + ( + exists($best_action->{args_attr}) && defined($best_action->{args_attr}) ? + ($best_action->{args_attr} ne 0) : 1 + ) + ) + ) + ) + ){ $best_action = { actions => [ $action ], captures=> [], parts => \@parts, + args_attr => $args_attr, n_pathparts => scalar(@pathparts), }; } @@@ -321,6 -325,32 +337,6 @@@ Calls register_path for every Path attr =cut -sub _check_args_attr { - my ( $self, $action, $name ) = @_; - - return unless exists $action->attributes->{$name}; - - if (@{$action->attributes->{$name}} > 1) { - Catalyst::Exception->throw( - "Multiple $name attributes not supported registering " . $action->reverse() - ); - } - my $args = $action->attributes->{$name}->[0]; - if (defined($args) and not ( - Scalar::Util::looks_like_number($args) and - int($args) == $args and $args >= 0 - )) { - require Data::Dumper; - local $Data::Dumper::Terse = 1; - local $Data::Dumper::Indent = 0; - $args = Data::Dumper::Dumper($args); - Catalyst::Exception->throw( - "Invalid $name($args) for action " . $action->reverse() . - " (use '$name' or '$name()')" - ); - } -} - sub register { my ( $self, $c, $action ) = @_; @@@ -368,6 -398,10 +384,6 @@@ $self->_actions->{'/'.$action->reverse} = $action; - foreach my $name (qw(Args CaptureArgs)) { - $self->_check_args_attr($action, $name); - } - if (exists $action->attributes->{Args} and exists $action->attributes->{CaptureArgs}) { Catalyst::Exception->throw( "Combining Args and CaptureArgs attributes not supported registering " . @@@ -399,15 -433,11 +415,15 @@@ sub uri_for_action my @captures = @$captures; my $parent = "DUMMY"; my $curr = $action; + # If this is an action chain get the last action in the chain + if($curr->can('chain') ) { + $curr = ${$curr->chain}[-1]; + } while ($curr) { - if (my $cap = $curr->attributes->{CaptureArgs}) { - return undef unless @captures >= ($cap->[0]||0); # not enough captures - if ($cap->[0]) { - unshift(@parts, splice(@captures, -$cap->[0])); + if (my $cap = $curr->number_of_captures) { + return undef unless @captures >= $cap; # not enough captures + if ($cap) { + unshift(@parts, splice(@captures, -$cap)); } } if (my $pp = $curr->attributes->{PathPart}) { @@@ -691,28 -721,6 +707,28 @@@ An action that is part of a chain (tha attribute) but has no C<:CaptureArgs> attribute is treated by Catalyst as a chain end. +Allowed values for CaptureArgs is a single integer (CaptureArgs(2), meaning two +allowed) or you can declare a L, L or L +named constraint such as CaptureArgs(Int,Str) would require two args with +the first being a Integer and the second a string. You may declare your own +custom type constraints and import them into the controller namespace: + + package MyApp::Controller::Root; + + use Moose; + use MooseX::MethodAttributes; + use MyApp::Types qw/Int/; + + extends 'Catalyst::Controller'; + + sub chain_base :Chained(/) CaptureArgs(1) { } + + sub any_priority_chain :Chained(chain_base) PathPart('') Args(1) { } + + sub int_priority_chain :Chained(chain_base) PathPart('') Args(Int) { } + +See L for more. + =item Args By default, endpoints receive the rest of the arguments in the path. You diff --combined lib/Catalyst/Runtime.pm index cc02f87,4e16a4f..572f50f --- a/lib/Catalyst/Runtime.pm +++ b/lib/Catalyst/Runtime.pm @@@ -1,4 -1,4 +1,3 @@@ --package Catalyst::Runtime; use strict; use warnings; @@@ -7,7 -7,7 +6,7 @@@ BEGIN { require 5.008003; # Remember to update this in Catalyst as well! -our $VERSION = '5.90085'; +our $VERSION = '5.90089_001'; $VERSION = eval $VERSION if $VERSION =~ /_/; # numify for warning-free dev releases =head1 NAME