Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

introduce Exception::Class exceptions

Introducing the Exception::Class exceptions into Dancer.
Exceptions, defined on Dancer::Exceptions can be thrown
anywhere within the Dancer code base backend, making it
easy to handle flow changes on the execution.

For instance, the redirect helper now throws Dancer::Exception::Halt
which makes the execution return at that point and return.

This makes the following broken code:

 get '/go/:url/', sub {
   redirect params->{url};
   "I'm an innocent last string";
 }

.. to work as expected.

Dancer::Exception::Pass was also introduced and it's used
directly from Dancer::pass.
  • Loading branch information...
commit 63b85646f1da0852b5a05f2c8a67f9b99df621ea 1 parent eac49c0
@damog damog authored
View
1  Makefile.PL
@@ -13,6 +13,7 @@ WriteMakefile(
'Test::Requires' => '0',
'Test::More' => '0',
'Test::MockObject' => '0',
+ 'Exception::Class' => '0',
},
EXE_FILES => ['script/dancer'],
ABSTRACT => "A minimal-effort oriented web application framework",
View
4 lib/Dancer.pm
@@ -9,6 +9,7 @@ use Dancer::Config 'setting';
use Dancer::FileUtils;
use Dancer::GetOpt;
use Dancer::Error;
+use Dancer::Exceptions;
use Dancer::Helpers;
use Dancer::Logger;
use Dancer::Renderer;
@@ -68,7 +69,8 @@ sub layout { set(layout => shift) }
sub logger { set(logger => @_) && Dancer::Logger->init }
sub mime_type { Dancer::Config::mime_types(@_) }
sub params { Dancer::SharedData->params }
-sub pass { Dancer::Response::pass() }
+# sub pass { Dancer::Response::pass() }
+sub pass { pass_exception }
sub path { Dancer::FileUtils::path(@_) }
sub post { Dancer::Route->add('post', @_) }
sub put { Dancer::Route->add('put', @_) }
View
38 lib/Dancer/Exceptions.pm
@@ -0,0 +1,38 @@
+package Dancer::Exceptions;
+
+use strict;
+use vars qw/$VERSION/;
+
+$VERSION = 0.1;
+
+my %e;
+
+BEGIN {
+ %e = (
+ 'Dancer::Exception::Halt' => {
+ description => 'Exception to halt and exit the execution of a route.',
+ alias => 'halt',
+ },
+ 'Dancer::Exception::Pass' => {
+ description => 'Passes the route evaluation to the next route block.',
+ alias => 'pass_exception',
+ }
+ );
+}
+
+use Exception::Class (%e);
+
+sub import {
+ my ($class, %args) = @_;
+
+ my $caller = caller;
+
+ while(my ($c, $v) = each %e) {
+ {
+ no strict 'refs';
+ *{"${caller}::".$v->{alias}} = \&{$v->{alias}};
+ }
+ }
+}
+
+1;
View
3  lib/Dancer/Helpers.pm
@@ -11,6 +11,7 @@ use CGI;
use Dancer::Response;
use Dancer::Config 'setting';
use Dancer::SharedData;
+use Dancer::Exceptions;
sub send_file {
my ($path) = @_;
@@ -74,6 +75,8 @@ sub redirect {
status => $status || 302,
headers => { 'Location' => $destination },
});
+
+ halt; # w00t!
}
'Dancer::Helpers';
View
103 lib/Dancer/Route.pm
@@ -97,60 +97,69 @@ sub call($$) {
Dancer::Logger->warning($warning) if $warning;
}
- # trap errors
- if ( $@ ||
- (setting('warnings') && ($warning || $compilation_warning))) {
+ # maybe a not retarded way to listen for the exceptions
+ # would be good here :)
+ # Halt: just stall everything and return the Response singleton
+ # useful for the redirect helper
+ if(Dancer::Exception::Halt->caught) {
+ return Dancer::Response->current;
+ } elsif
+ # Pass: pass to the next route if available. otherwise, 404.
+ (Dancer::Exception::Pass->caught) {
+ if ($handler->{'next'}) {
+ return Dancer::Route->call($handler->{'next'});
+ }
+ else {
+ Dancer::SharedData->reset_all();
+ my $error = Dancer::Error->new(code => 404,
+ message => "<h2>Route Resolution Failed</h2>"
+ . "<p>Last matching route passed, "
+ . "but no other route left.</p>");
+ return $error->render;
+ }
+ # no exceptions? continue the old way, although this
+ # mechanism should be dropped in favor of exceptions in the
+ # future
+ } else {
+ # trap errors
+ if ( $@ ||
+ (setting('warnings') && ($warning || $compilation_warning))) {
- Dancer::SharedData->reset_all();
-
- my $error;
- if ($@) {
- $error = Dancer::Error->new(code => 500,
- title => 'Route Handler Error',
- type => 'Execution failed',
- message => $@);
-
- }
- elsif ($warning) {
- $error = Dancer::Error->new(code => 500,
- title => 'Route Handler Error',
- type => 'Runtime Warning',
- message => $warning);
-
- }
- else {
- $error = Dancer::Error->new(code => 500,
- title => 'Route Handler Error',
- type => 'Compilation Warning',
- message => $compilation_warning);
- }
- return $error->render;
- }
-
- my $response = Dancer::Response->current;
-
- if ($response->{pass}) {
- if ($handler->{'next'}) {
- return Dancer::Route->call($handler->{'next'});
- }
- else {
- Dancer::SharedData->reset_all();
- my $error = Dancer::Error->new(code => 404,
- message => "<h2>Route Resolution Failed</h2>"
- . "<p>Last matching route passed, "
- . "but no other route left.</p>");
- return $error->render;
- }
- }
- else {
+ Dancer::SharedData->reset_all();
+
+ my $error;
+ if ($@) {
+ $error = Dancer::Error->new(code => 500,
+ title => 'Route Handler Error',
+ type => 'Execution failed',
+ message => $@);
+
+ }
+ elsif ($warning) {
+ $error = Dancer::Error->new(code => 500,
+ title => 'Route Handler Error',
+ type => 'Runtime Warning',
+ message => $warning);
+
+ }
+ else {
+ $error = Dancer::Error->new(code => 500,
+ title => 'Route Handler Error',
+ type => 'Compilation Warning',
+ message => $compilation_warning);
+ }
+ return $error->render;
+ }
+
+ my $response = Dancer::Response->current;
# drop the content if this is a HEAD request
$content = '' if $handler->{method} eq 'head';
my $ct = $response->{content_type} || setting('content_type');
my $st = $response->{status} || 200;
-
+
Dancer::SharedData->reset_all();
-
+
return $content if ref($content) eq 'Dancer::Response';
return Dancer::Response->new(
status => $st,
Please sign in to comment.
Something went wrong with that request. Please try again.