Skip to content

Commit

Permalink
Merge branch 'devel' of github.com:sukria/Dancer into devel
Browse files Browse the repository at this point in the history
  • Loading branch information
xsawyerx committed Feb 29, 2012
2 parents 3da5372 + 5fe0152 commit a75e7d3
Show file tree
Hide file tree
Showing 17 changed files with 143 additions and 123 deletions.
9 changes: 9 additions & 0 deletions CHANGES
@@ -1,5 +1,14 @@
{{$NEXT}}

[ BUG FIXES ]
* GH-738: Define exception type ::Core::Request, to avoid things blowing
up when Dancer::Request raises exceptions of that type
(David Precious, thanks to damog for reporting)

[ DOCUMENTATION ]
* Fix examples for multi-app deployment under Plack::Builder in deployment
* docs (c0bra)

1.3092 27.01.2012

[ BUG FIXES ]
Expand Down
2 changes: 2 additions & 0 deletions MANIFEST
Expand Up @@ -174,6 +174,8 @@ t/03_route_handler/public/404.html
t/03_route_handler/public/utf8file.txt
t/03_route_handler/views/error.tt
t/03_route_handler/views/hello.tt
t/03_route_handler/views/foo/index.tt
t/03_route_handler/views/foo/bar.tt
t/04_static_file/001_base.t
t/04_static_file/003_mime_types_reinit.t
t/04_static_file/01_mime_types.t
Expand Down
83 changes: 21 additions & 62 deletions lib/Dancer.pm
Expand Up @@ -532,7 +532,7 @@ your app. You can control the exporting through the normal
L<Exporter> mechanism. For example:
# Just export the route controllers
use Dancer qw(before after get post put patch);
use Dancer qw(get post put patch del);
# Export everything but pass to avoid clashing with Test::More
use Test::More;
Expand Down Expand Up @@ -583,26 +583,23 @@ By default, the L<warnings> pragma will also be exported, meaning your
app/script will be running under C<use warnings>. If you do not want this, set
the L<import_warnings|Dancer::Config/import_warnings> setting to a false value.
=head2 !keyword
=head1 FUNCTIONS
If you want to simply prevent Dancer from exporting specific keywords (perhaps
you plan to implement them yourself in a different way, or you don't plan to use
them and they clash with another module you're loading), you can simply exclude
them:
=head2 after
use Dancer qw(!session);
Add a hook at the B<after> position:
The above would import all keywords as normal, with the exception of C<session>.
after sub {
my $response = shift;
# do something with response, e.g.:
$response->header('X-Beer' => 'Yes please');
};
The anonymous function which is given to C<after> will be executed after
having executed a route, but before the response is returned (so you can modify
the response here, if you need to)..
=head1 FUNCTIONS
=head2 after
You can define multiple after filters, using the C<after> helper as
many times as you wish; each filter will be executed, in the order you added
them.
Deprecated - see the C<after> L<hook|Dancer/hook>.
=head2 any
Expand All @@ -620,48 +617,11 @@ Or even, a route handler that would match any HTTP methods:
=head2 before
Defines a before filter:
before sub {
# do something with request, vars or params
};
The anonymous function given to C<before> will be executed before executing a
route handler to handle the request.
If the function modifies the request's C<path_info> or C<method>, a new
search for a matching route is performed and the filter is re-executed.
Considering that this can lead to an infinite loop, this mechanism
is stopped after 10 times with an exception.
The before filter can set a response with a redirection code (either
301 or 302): in this case the matched route (if any) will be ignored and the
redirection will be performed immediately.
You can define multiple before filters, using the C<before> helper as
many times as you wish; each filter will be executed in the order you added
them.
Deprecated - see the C<before> L<hook|Dancer/hook>.
=head2 before_template
Defines a before_template filter:
before_template sub {
my $tokens = shift;
# do something with request, vars or params
# for example, adding a token to the template
$tokens->{token_name} = "some value";
};
The anonymous function which is given to C<before_template> will be executed
before sending data and tokens to the template. Receives a HashRef of the
tokens that will be inserted into the template.
This filter works as the C<before> and C<after> filter.
Now the preferred way for this is to use C<hook>s (namely, the
C<before_template> one). Check C<hook> documentation below.
Deprecated - see the C<before_template> L<hook|Dancer/hook>.
=head2 cookies
Expand Down Expand Up @@ -774,13 +734,12 @@ application.
It effectively lets you chain routes together in a clean manner.
get qr{ /demo/articles/(.+) }x => sub {
my ($article_id) = splat;
get '/demo/articles/:article_id' => sub {
# you'll have to implement this next sub yourself :)
change_the_main_database_to_demo();
forward '/articles/$article_id';
forward "/articles/" . params->{article_id};
};
In the above example, the users that reach I</demo/articles/30> will actually
Expand All @@ -791,19 +750,19 @@ database by merely going to I</demo/...>.
You'll notice that in the example we didn't indicate whether it was B<GET> or
B<POST>. That is because C<forward> chains the same type of route the user
reached. If it was a B<GET>, it will remain a B<GET>.
reached. If it was a B<GET>, it will remain a B<GET> (but if you do need to
change the method, you can do so; read on below for details.)
Broader functionality might be added in the future.
B<WARNING> : Issuing a forward immediately exits the current route,
and perform the forward. Thus, any code after a forward is ignored, until the
end of the route. e.g.
get '/some/path => sub {
get '/foo/:article_id' => sub {
if ($condition) {
forward '/articles/$article_id';
forward "/articles/" . params->{article_id};
# The following code is never executed
do_stuf();
do_stuff();
}
more_stuff();
Expand Down
19 changes: 1 addition & 18 deletions lib/Dancer/Config.pm
Expand Up @@ -54,23 +54,6 @@ my $setters = {
my ($setting, $value) = @_;
$^W = $value ? 1 : 0;
},
auto_page => sub {
my ($setting, $auto_page) = @_;
if ($auto_page) {
require Dancer::App;
Dancer::App->current->registry->universal_add(
'get', '/:page',
sub {
my $params = Dancer::SharedData->request->params;
if (-f Dancer::engine('template')->view($params->{page})) {
return Dancer::template($params->{'page'});
} else {
return Dancer::pass();
}
}
);
}
},
traces => sub {
my ($setting, $traces) = @_;
$Dancer::Exception::Verbose = $traces ? 1 : 0;
Expand Down Expand Up @@ -601,7 +584,7 @@ Simply enable auto_page in your config:
Then, if you request C</foo/bar>, Dancer will look in the views dir for
C</foo/bar.tt>.
Dancer will honor your C<before_template> code, and all default
Dancer will honor your C<before_template_render> code, and all default
variables. They will be accessible and interpolated on automatic
served pages.
Expand Down
6 changes: 3 additions & 3 deletions lib/Dancer/Cookbook.pod
Expand Up @@ -553,10 +553,10 @@ hashref as the third param to the template keyword:
template 'index.tt', {}, { layout => undef };

If your application is not mounted under root (B</>), you can use a
before_template instead of hardcoding the path to your application for your
css, images and javascript:
before_template_render hook instead of hardcoding the path to your
application for your css, images and javascript:

before_template sub {
hook 'before_template_render' => sub {
my $tokens = shift;
$tokens->{uri_base} = request->base->path;
};
Expand Down
1 change: 1 addition & 0 deletions lib/Dancer/Exception.pm
Expand Up @@ -116,6 +116,7 @@ register_exception(@$_) foreach (
[ 'Core::Handler::PSGI', message_pattern => 'handler - %s', composed_from => [ qw(Core::Handler) ] ],
[ 'Core::Plugin', message_pattern => 'plugin - %s', composed_from => [ qw(Core) ] ],
[ 'Core::Renderer', message_pattern => 'renderer - %s', composed_from => [ qw(Core) ] ],
[ 'Core::Request', message_pattern => 'request - %s', composed_from => [ qw(Core) ] ],
[ 'Core::Route', message_pattern => 'route - %s', composed_from => [ qw(Core) ] ],
[ 'Core::Serializer', message_pattern => 'serializer - %s', composed_from => [ qw(Core) ] ],
[ 'Core::Template', message_pattern => 'template - %s', composed_from => [ qw(Core) ] ],
Expand Down
7 changes: 6 additions & 1 deletion lib/Dancer/Handler.pm
Expand Up @@ -84,6 +84,7 @@ sub render_request {
$action = try {
Dancer::Renderer->render_file
|| Dancer::Renderer->render_action
|| Dancer::Renderer->render_autopage
|| Dancer::Renderer->render_error(404);
} continuation {
# workflow exception (continuation)
Expand All @@ -96,7 +97,11 @@ sub render_request {
my ($exception) = @_;
Dancer::Factory::Hook->execute_hooks('on_handler_exception', $exception);
Dancer::Logger::error(
'request to ' . $request->path_info . " crashed: $exception");
sprintf(
'request to %s %s crashed: %s',
$request->method, $request->path_info, $exception
)
);

# use stringification, to get exception message in case of a
# Dancer::Exception
Expand Down
30 changes: 15 additions & 15 deletions lib/Dancer/Introduction.pod
Expand Up @@ -230,15 +230,15 @@ B<show_errors> setting.
Note that you can also choose to consider all warnings in your route handlers
as errors when the setting B<warnings> is set to 1.

=head1 FILTERS
=head1 HOOKS

=head2 Before filters
=head2 Before hooks

Before filters are evaluated before each request within the context of the
Before hooks are evaluated before each request within the context of the
request and can modify the request and response. It's possible to define
variables which will be accessible in the action blocks with the keyword 'var'.

before sub {
hook 'before' => sub {
var note => 'Hi there';
request->path_info('/foo/oversee')
};
Expand All @@ -252,7 +252,7 @@ variables which will be accessible in the action blocks with the keyword 'var'.
For another example, this can be used along with session support to easily
give non-logged-in users a login page:

before sub {
hook 'before' => sub {
if (!session('user') && request->path_info !~ m{^/login}) {
# Pass the original path requested along to the handler:
var requested_path => request->path_info;
Expand All @@ -265,32 +265,32 @@ The request keyword returns the current Dancer::Request object representing the
incoming request. See the documentation of the L<Dancer::Request> module for
details.

=head2 After filters
=head2 After hooks

C<after> filters are evaluated after the response has been built by a route
C<after> hooks are evaluated after the response has been built by a route
handler, and can alter the response itself, just before it's sent to the
client.

The filter is given the response object as its first argument:
The hook is given the response object as its first argument:

after sub {
hook 'after' => sub {
my $response = shift;
$response->{content} = 'after filter got here!';
$response->{content} = 'after hook got here!';
};


=head2 Before template filters
=head2 Before template hook

C<before_template> hooks are called whenever a template is going to be
C<before_template_render> hooks are called whenever a template is going to be
processed, they are passed the tokens hash which they can alter.

before_template sub {
hook 'before_template_render' => sub {
my $tokens = shift;
$tokens->{foo} = 'bar';
}
};

The tokens hash will then be passed to the template with all the modifications
performed by the filter. This is a good way to setup some global vars you like
performed by the hook. This is a good way to setup some global vars you like
to have in all your templates, like the name of the user logged in or a
section name.

Expand Down
41 changes: 40 additions & 1 deletion lib/Dancer/Renderer.pm
Expand Up @@ -98,7 +98,7 @@ sub get_action_response {
my $app = ($handler && $handler->app) ? $handler->app : Dancer::App->current();

# run the before filters, before "running" the route handler
Dancer::Factory::Hook->instance->execute_hooks('before');
Dancer::Factory::Hook->instance->execute_hooks('before', $handler);

# recurse if something has changed
my $MAX_RECURSIVE_LOOP = 10;
Expand Down Expand Up @@ -149,6 +149,45 @@ sub get_action_response {
}
}

sub render_autopage {
return unless Dancer::setting('auto_page');

my $request = Dancer::SharedData->request;
my $path = $request->path_info;

# See if we find a matching view for this request, if so, render it
my $viewpath = $path;
$viewpath =~ s{^/}{};
my $view = Dancer::engine('template')->view($viewpath) || '';

if ($view && -f $view) {
# A view exists for the path requested, go ahead and render it:
return _autopage_response($viewpath);
}

# Try appending "index" and looking again
$view = Dancer::engine('template')->view(
Dancer::FileUtils::path($viewpath, 'index')
)|| '';
Dancer::error("Looking for $viewpath/index - got $view");
if ($view && -f $view) {
return _autopage_response(
Dancer::FileUtils::path($viewpath, 'index')
);
}

return;
}
sub _autopage_response {
my $viewpath = shift;
my $response = Dancer::Response->new;
$response->status(200);
$response->content(
Dancer::template($viewpath)
);
return $response;
}

sub serialize_response_if_needed {
my $response = Dancer::SharedData->response();

Expand Down
9 changes: 5 additions & 4 deletions lib/Dancer/Route.pm
Expand Up @@ -81,10 +81,11 @@ sub match {
my $path = $request->path_info;
my %params;

Dancer::Logger::core("trying to match `$path' "
. "against /"
. $self->{_compiled_regexp}
. "/");
Dancer::Logger::core(
sprintf "Trying to match '%s %s' against /%s/ (generated from '%s')",
$request->method, $path, $self->{_compiled_regexp}, $self->pattern
);


my @values = $path =~ $self->{_compiled_regexp};

Expand Down

0 comments on commit a75e7d3

Please sign in to comment.