From f6a1d27776f3dd2c4dc8eb964932f9099617bfba Mon Sep 17 00:00:00 2001 From: Russell Jenkins Date: Sat, 28 Sep 2013 15:15:43 +1000 Subject: [PATCH] Use Return::MultiLevel to wrap route dispatch. As suggested in #432, use Return::MultiLevel to wrap route dispatch. Cache the multilevel return coderef in the context for forward/redirect to use. Add Return::MultiLevel to prereqs and Scope::Upper to recommends. --- dist.ini | 3 ++- lib/Dancer2/Core/Context.pm | 13 +++++++++++++ lib/Dancer2/Core/Dispatcher.pm | 19 ++++++++++++++++--- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/dist.ini b/dist.ini index 1e4a69275..acbb6f032 100644 --- a/dist.ini +++ b/dist.ini @@ -73,7 +73,7 @@ URI::Escape = 0 parent = 0 Template::Tiny = 0 Class::Load = 0 - +Return::MultiLevel = 0 [Prereqs / Recommends] ; Serializers @@ -94,6 +94,7 @@ Crypt::URandom = 0 ; extract pod data from apps Pod::Simple::Search = 0 Pod::Simple::SimpleTree = 0 +Scope::Upper = 0 [Prereqs / Suggests] ; Used by Dancer2::Session::YAML diff --git a/lib/Dancer2/Core/Context.pm b/lib/Dancer2/Core/Context.pm index 6ec15f4d2..69663b0d2 100644 --- a/lib/Dancer2/Core/Context.pm +++ b/lib/Dancer2/Core/Context.pm @@ -284,4 +284,17 @@ sub destroy_session { return; } + +=attr with_return + +Used to cache the coderef from L within the dispatcher. + +=cut + +has with_return => ( + is => 'rw', + predicate => 1, + clearer => 'clear_with_response', +); + 1; diff --git a/lib/Dancer2/Core/Dispatcher.pm b/lib/Dancer2/Core/Dispatcher.pm index 3a81cb654..c565d21f8 100644 --- a/lib/Dancer2/Core/Dispatcher.pm +++ b/lib/Dancer2/Core/Dispatcher.pm @@ -8,6 +8,8 @@ use Dancer2::Core::Types; use Dancer2::Core::Context; use Dancer2::Core::Response; +use Return::MultiLevel qw(with_return); + has apps => ( is => 'rw', isa => ArrayRef, @@ -65,9 +67,20 @@ sub dispatch { $context->request->_set_route_params($match); - my $response = $self->_dispatch_route($route, $context); - - return $response if $response->is_halted; + my $response = with_return { + my ($return) = @_; + # stash the multilevel return coderef in the context + $context->with_return($return) if ! $context->has_with_return; + return $self->_dispatch_route($route, $context); + }; + # Ensure we clear the with_return handler + $context->clear_with_response; + + # No further processing of this response if its halted + if ( $response->is_halted ) { + $app->context(undef); + return $response; + } # pass the baton if the response says so... if ( $response->has_passed ) {