Skip to content

Commit

Permalink
Merge branch 'release/1.3089_01'
Browse files Browse the repository at this point in the history
  • Loading branch information
xsawyerx committed Nov 26, 2011
2 parents a4f3aec + 69537e4 commit 04acd81
Show file tree
Hide file tree
Showing 57 changed files with 1,123 additions and 338 deletions.
19 changes: 19 additions & 0 deletions CHANGES
@@ -1,3 +1,22 @@
1.3089_01 26.11.2011

[ BUG FIXES ]
* Fix bug that made system() fail with -1 under Dancer (felixdo).
* Support for 'content_type' option on send_file when sending a
system wide file (Emmanuel Rodriguez).
* Support HTTP_X_FORWARDED_HOST in behing proxy (Ipaponov).
* Deserialize PATCH requests (Sam Kington).
* Encode log messages properly if charset UTF-8 is set (David Precious,
thanks to Penfold for the fix & MiklerGM for reporting).

[ ENHANCEMENTS ]
* Continuations-style exception system! (Damien Krotkine).
* The ability for dancer_response to send file contents for file uploads
as a scalar, instead of reading from file on disk (Squeeks).

[ DOCUMENTATION ]
* Clean up "plack_middlewares" example in docs (Richard Simões).

1.3080 25.10.2011 1.3080 25.10.2011
** Codename: Sawyer's Sugar Stream // Sawyer X ** ** Codename: Sawyer's Sugar Stream // Sawyer X **


Expand Down
10 changes: 10 additions & 0 deletions MANIFEST
Expand Up @@ -13,6 +13,14 @@ examples/dancr/views/show_entries.tt
lib/Dancer.pm lib/Dancer.pm
lib/Dancer/App.pm lib/Dancer/App.pm
lib/Dancer/Config.pm lib/Dancer/Config.pm
lib/Dancer/Continuation.pm
lib/Dancer/Continuation/Halted.pm
lib/Dancer/Continuation/Route.pm
lib/Dancer/Continuation/Route/ErrorSent.pm
lib/Dancer/Continuation/Route/FileSent.pm
lib/Dancer/Continuation/Route/Forwarded.pm
lib/Dancer/Continuation/Route/Passed.pm
lib/Dancer/Continuation/Route/Templated.pm
lib/Dancer/Cookbook.pod lib/Dancer/Cookbook.pod
lib/Dancer/Cookie.pm lib/Dancer/Cookie.pm
lib/Dancer/Cookies.pm lib/Dancer/Cookies.pm
Expand All @@ -23,6 +31,7 @@ lib/Dancer/Development/Integration.pod
lib/Dancer/Engine.pm lib/Dancer/Engine.pm
lib/Dancer/Error.pm lib/Dancer/Error.pm
lib/Dancer/Exception.pm lib/Dancer/Exception.pm
lib/Dancer/Exception/Base.pm
lib/Dancer/Factory/Hook.pm lib/Dancer/Factory/Hook.pm
lib/Dancer/FileUtils.pm lib/Dancer/FileUtils.pm
lib/Dancer/GetOpt.pm lib/Dancer/GetOpt.pm
Expand Down Expand Up @@ -302,6 +311,7 @@ t/23_dancer_tests/01_basic.t
t/23_dancer_tests/02_tests_functions.t t/23_dancer_tests/02_tests_functions.t
t/24_deployment/01_multi_webapp.t t/24_deployment/01_multi_webapp.t
t/25_exceptions/01_exceptions.t t/25_exceptions/01_exceptions.t
t/25_exceptions/02_exceptions.t
t/25_exceptions/views/error.tt t/25_exceptions/views/error.tt
t/25_exceptions/views/index.tt t/25_exceptions/views/index.tt
t/25_exceptions/views/layouts/main.tt t/25_exceptions/views/layouts/main.tt
Expand Down
1 change: 1 addition & 0 deletions Makefile.PL
Expand Up @@ -47,6 +47,7 @@ WriteMakefile1(
'HTTP::Server::Simple::PSGI' => '0.11', 'HTTP::Server::Simple::PSGI' => '0.11',
'MIME::Types' => '0', 'MIME::Types' => '0',
'URI' => '1.59', 'URI' => '1.59',
'Try::Tiny' => '0.09',


# core # core
'File::Basename' => '0', 'File::Basename' => '0',
Expand Down
154 changes: 126 additions & 28 deletions lib/Dancer.pm
Expand Up @@ -5,7 +5,7 @@ use warnings;
use Carp; use Carp;
use Cwd 'realpath'; use Cwd 'realpath';


our $VERSION = '1.3080'; our $VERSION = '1.3089_01';
our $AUTHORITY = 'SUKRIA'; our $AUTHORITY = 'SUKRIA';


use Dancer::App; use Dancer::App;
Expand All @@ -26,6 +26,14 @@ use Dancer::Session;
use Dancer::SharedData; use Dancer::SharedData;
use Dancer::Handler; use Dancer::Handler;
use Dancer::MIME; use Dancer::MIME;
use Dancer::Exception qw(:all);

use Dancer::Continuation::Halted;
use Dancer::Continuation::Route::Forwarded;
use Dancer::Continuation::Route::Passed;
use Dancer::Continuation::Route::ErrorSent;
use Dancer::Continuation::Route::FileSent;
use Dancer::Continuation::Route::Templated;


use File::Spec; use File::Spec;


Expand Down Expand Up @@ -132,13 +140,19 @@ sub dirname { Dancer::FileUtils::dirname(@_) }
sub engine { Dancer::Engine->engine(@_) } sub engine { Dancer::Engine->engine(@_) }
sub error { goto &Dancer::Logger::error } sub error { goto &Dancer::Logger::error }
sub false { 0 } sub false { 0 }
sub forward { Dancer::SharedData->response->forward(@_) } sub forward { Dancer::SharedData->response->forward(@_);
# throw a special continuation exception
Dancer::Continuation::Route::Forwarded->new->throw;
}
sub from_dumper { Dancer::Serializer::Dumper::from_dumper(@_) } sub from_dumper { Dancer::Serializer::Dumper::from_dumper(@_) }
sub from_json { Dancer::Serializer::JSON::from_json(@_) } sub from_json { Dancer::Serializer::JSON::from_json(@_) }
sub from_xml { Dancer::Serializer::XML::from_xml(@_) } sub from_xml { Dancer::Serializer::XML::from_xml(@_) }
sub from_yaml { Dancer::Serializer::YAML::from_yaml(@_) } sub from_yaml { Dancer::Serializer::YAML::from_yaml(@_) }
sub get { map { my $r = $_; Dancer::App->current->registry->universal_add($r, @_) } qw(head get) } sub get { map { my $r = $_; Dancer::App->current->registry->universal_add($r, @_) } qw(head get) }
sub halt { Dancer::SharedData->response->halt(@_) } sub halt { Dancer::SharedData->response->halt(@_);
# throw a special continuation exception
Dancer::Continuation::Halted->new->throw;
}
sub header { goto &headers } sub header { goto &headers }
sub push_header { Dancer::SharedData->response->push_header(@_); } sub push_header { Dancer::SharedData->response->push_header(@_); }
sub headers { Dancer::SharedData->response->headers(@_); } sub headers { Dancer::SharedData->response->headers(@_); }
Expand All @@ -158,7 +172,10 @@ sub mime { Dancer::MIME->instance() }
sub options { Dancer::App->current->registry->universal_add('options', @_) } sub options { Dancer::App->current->registry->universal_add('options', @_) }
sub params { Dancer::SharedData->request->params(@_) } sub params { Dancer::SharedData->request->params(@_) }
sub param { params->{$_[0]} } sub param { params->{$_[0]} }
sub pass { Dancer::SharedData->response->pass(1) } sub pass { Dancer::SharedData->response->pass(1);
# throw a special continuation exception
Dancer::Continuation::Route::Passed->new->throw;
}
sub patch { Dancer::App->current->registry->universal_add('patch', @_) } sub patch { Dancer::App->current->registry->universal_add('patch', @_) }
sub path { Dancer::FileUtils::path(@_) } sub path { Dancer::FileUtils::path(@_) }
sub post { Dancer::App->current->registry->universal_add('post', @_) } sub post { Dancer::App->current->registry->universal_add('post', @_) }
Expand All @@ -167,16 +184,26 @@ sub put { Dancer::App->current->registry->universal_add('put', @
sub redirect { goto &_redirect } sub redirect { goto &_redirect }
sub render_with_layout { Dancer::Template::Abstract->_render_with_layout(@_) } sub render_with_layout { Dancer::Template::Abstract->_render_with_layout(@_) }
sub request { Dancer::SharedData->request } sub request { Dancer::SharedData->request }
sub send_error { Dancer::Error->new(message => $_[0], code => $_[1] || 500)->render() } sub send_error { Dancer::Continuation::Route::ErrorSent->new(
sub send_file { goto &_send_file } return_value => Dancer::Error->new(
message => $_[0],
code => $_[1] || 500)->render()
)->throw }
#sub send_file { goto &_send_file }
sub send_file { Dancer::Continuation::Route::FileSent->new(
return_value => _send_file(@_)
)->throw
}
sub set { goto &setting } sub set { goto &setting }
sub set_cookie { Dancer::Cookies->set_cookie(@_) } sub set_cookie { Dancer::Cookies->set_cookie(@_) }
sub setting { Dancer::App->applications ? Dancer::App->current->setting(@_) : Dancer::Config::setting(@_) } sub setting { Dancer::App->applications ? Dancer::App->current->setting(@_) : Dancer::Config::setting(@_) }
sub session { goto &_session } sub session { goto &_session }
sub splat { @{ Dancer::SharedData->request->params->{splat} || [] } } sub splat { @{ Dancer::SharedData->request->params->{splat} || [] } }
sub start { goto &_start } sub start { goto &_start }
sub status { Dancer::SharedData->response->status(@_) } sub status { Dancer::SharedData->response->status(@_) }
sub template { Dancer::Template::Abstract->template(@_) } sub template { Dancer::Continuation::Route::Templated->new(
return_value => Dancer::Template::Abstract->template(@_)
)->throw }
sub to_dumper { Dancer::Serializer::Dumper::to_dumper(@_) } sub to_dumper { Dancer::Serializer::Dumper::to_dumper(@_) }
sub to_json { Dancer::Serializer::JSON::to_json(@_) } sub to_json { Dancer::Serializer::JSON::to_json(@_) }
sub to_xml { Dancer::Serializer::XML::to_xml(@_) } sub to_xml { Dancer::Serializer::XML::to_xml(@_) }
Expand Down Expand Up @@ -248,7 +275,7 @@ sub _load_app {
# load the application # load the application
_init_script_dir($script); _init_script_dir($script);
my ($res, $error) = Dancer::ModuleLoader->load($app_name); my ($res, $error) = Dancer::ModuleLoader->load($app_name);
$res or croak "unable to load application $app_name : $error"; $res or raise core => "unable to load application $app_name : $error";


# restore the main application # restore the main application
Dancer::App->set_running_app('main'); Dancer::App->set_running_app('main');
Expand Down Expand Up @@ -304,7 +331,7 @@ sub _init_script_dir {
|| Dancer::FileUtils::path($appdir, 'views')); || Dancer::FileUtils::path($appdir, 'views'));


my ($res, $error) = Dancer::ModuleLoader->use_lib(Dancer::FileUtils::path($appdir, 'lib')); my ($res, $error) = Dancer::ModuleLoader->use_lib(Dancer::FileUtils::path($appdir, 'lib'));
$res or croak "unable to set libdir : $error"; $res or raise core => "unable to set libdir : $error";
} }




Expand All @@ -327,7 +354,7 @@ sub _redirect {


sub _session { sub _session {
engine 'session' engine 'session'
or croak "Must specify session engine in settings prior to using 'session' keyword"; or raise core => "Must specify session engine in settings prior to using 'session' keyword";
@_ == 0 ? Dancer::Session->get @_ == 0 ? Dancer::Session->get
: @_ == 1 ? Dancer::Session->read(@_) : @_ == 1 ? Dancer::Session->read(@_)
: Dancer::Session->write(@_); : Dancer::Session->write(@_);
Expand All @@ -342,8 +369,8 @@ sub _send_file {


# if you asked for streaming but it's not supported in PSGI # if you asked for streaming but it's not supported in PSGI
if ( $options{'streaming'} && ! $env->{'psgi.streaming'} ) { if ( $options{'streaming'} && ! $env->{'psgi.streaming'} ) {
# TODO: throw a fit (AKA "exception") or a Dancer::Error (or croak)? # TODO: throw a fit (AKA "exception") or a Dancer::Error?
croak 'Sorry, streaming is not supported on this server.'; raise core => 'Sorry, streaming is not supported on this server.';
} }


if (exists($options{content_type})) { if (exists($options{content_type})) {
Expand Down Expand Up @@ -769,20 +796,21 @@ reached. If it was a B<GET>, it will remain a B<GET>.
Broader functionality might be added in the future. Broader functionality might be added in the future.
It is important to note that issuing a forward by itself does not exit and B<WARNING> : Issuing a forward immediately exits the current route,
forward immediately, forwarding is deferred until after the current route and perform the forward. Thus, any code after a forward is ignored, until the
or filter has been processed. To exit and forward immediately, use the return end of the route. e.g.
function, e.g.
get '/some/path => sub { get '/some/path => sub {
if ($condition) { if ($condition) {
return forward '/articles/$article_id'; forward '/articles/$article_id';
# The following code is never executed
do_stuf();
} }
more_stuff(); more_stuff();
}; };
You probably always want to use C<return> with forward. So it's not necessary anymore to use C<return> with forward.
Note that forward doesn't parse GET arguments. So, you can't use Note that forward doesn't parse GET arguments. So, you can't use
something like: something like:
Expand Down Expand Up @@ -840,14 +868,20 @@ renders the response immediately:
before sub { before sub {
if ($some_condition) { if ($some_condition) {
return halt("Unauthorized"); halt("Unauthorized");
# This code is not executed :
do_stuff();
} }
}; };
get '/' => sub { get '/' => sub {
"hello there"; "hello there";
}; };
B<WARNING> : Issuing a halt immediately exits the current route, and perform
the halt. Thus, any code after a halt is ignored, until the end of the route.
So it's not necessary anymore to use C<return> with halt.
=head2 headers =head2 headers
Adds custom headers to responses: Adds custom headers to responses:
Expand Down Expand Up @@ -1056,6 +1090,26 @@ This hook receives as argument a L<Dancer::Response> object.
my $response = shift; my $response = shift;
}; };
=item on_handler_exception
This hook is called when an exception has been caught, at the handler level,
just before creating and rendering L<Dancer::Error>. This hook receives as
argument a L<Dancer::Exception> object.
hook on_handler_exception => sub {
my $exception = shift;
};
=item on_route_exception
This hook is called when an exception has been caught, at the route level, just
before rethrowing it higher. This hook receives the exception as argument. It
can be a Dancer::Exception, or a string, or whatever was used to C<die>.
hook on_route_exception => sub {
my $exception = shift;
};
=back =back
=head2 layout =head2 layout
Expand Down Expand Up @@ -1145,12 +1199,16 @@ I<This method should be called from a route handler>.
Tells Dancer to pass the processing of the request to the next Tells Dancer to pass the processing of the request to the next
matching route. matching route.
You should always C<return> after calling C<pass>: B<WARNING> : Issuing a pass immediately exits the current route, and perform
the pass. Thus, any code after a pass is ignored, until the end of the route.
So it's not necessary anymore to use C<return> with pass.
get '/some/route' => sub { get '/some/route' => sub {
if (...) { if (...) {
# we want to let the next matching route handler process this one # we want to let the next matching route handler process this one
return pass(); pass(...);
# This code will be ignored
do_stuff();
} }
}; };
Expand Down Expand Up @@ -1329,10 +1387,18 @@ Returns a HTTP error. By default the HTTP code returned is 500:
} }
} }
This will not cause your route handler to return immediately, so be careful that B<WARNING> : Issuing a send_error immediately exits the current route, and perform
your route handler doesn't then override the error. You can avoid that by the send_error. Thus, any code after a send_error is ignored, until the end of the route.
saying C<return send_error(...)> instead. So it's not necessary anymore to use C<return> with send_error.
get '/some/route' => sub {
if (...) {
# we want to let the next matching route handler process this one
send_error(..);
# This code will be ignored
do_stuff();
}
};
=head2 send_file =head2 send_file
Expand All @@ -1344,6 +1410,19 @@ the C<system_path> option (see below).
return send_file(params->{file}); return send_file(params->{file});
} }
B<WARNING> : Issuing a send_file immediately exits the current route, and perform
the send_file. Thus, any code after a send_file is ignored, until the end of the route.
So it's not necessary anymore to use C<return> with send_file.
get '/some/route' => sub {
if (...) {
# we want to let the next matching route handler process this one
send_file(...);
# This code will be ignored
do_stuff();
}
};
Send file supports streaming possibility using PSGI streaming. The server should Send file supports streaming possibility using PSGI streaming. The server should
support it but normal streaming is supported on most, if not all. support it but normal streaming is supported on most, if not all.
Expand Down Expand Up @@ -1615,6 +1694,20 @@ Tells the route handler to build a response with the current template engine:
template 'some_view', { token => 'value'}; template 'some_view', { token => 'value'};
}; };
B<WARNING> : Issuing a template immediately exits the current route, and perform
the template. Thus, any code after a template is ignored, until the end of the route.
So it's not necessary anymore to use C<return> with template.
get '/some/route' => sub {
if (...) {
# we want to let the next matching route handler process this one
template(...);
# This code will be ignored
do_stuff();
}
};
The first parameter should be a template available in the views directory, the The first parameter should be a template available in the views directory, the
second one (optional) is a HashRef of tokens to interpolate, and the third second one (optional) is a HashRef of tokens to interpolate, and the third
(again optional) is a HashRef of options. (again optional) is a HashRef of options.
Expand Down Expand Up @@ -1727,19 +1820,24 @@ versions:
=head2 var =head2 var
Defines a variable shared between filters and route handlers. Provides an accessor for variables shared between filters and route handlers.
Given a key/value pair, it sets a variable:
before sub { before sub {
var foo => 42; var foo => 42;
}; };
Route handlers and other filters will be able to read that variable with the Later, route handlers and other filters will be able to read that variable:
C<vars> keyword.
get '/path' => sub {
my $foo = var 'foo';
...
};
=head2 vars =head2 vars
Returns the HashRef of all shared variables set during the filter/route Returns the HashRef of all shared variables set during the filter/route
chain: chain with the C<var> keyword:
get '/path' => sub { get '/path' => sub {
if (vars->{foo} eq 42) { if (vars->{foo} eq 42) {
Expand Down

0 comments on commit 04acd81

Please sign in to comment.