Permalink
Browse files

Merge branch 'release/1.3079_05'

  • Loading branch information...
2 parents ce7b0de + cd9e524 commit 12d646a403767672c00a5c25eb6e46e6d3584080 Alexis Sukrieh committed Oct 18, 2011
View
14 CHANGES
@@ -1,3 +1,17 @@
+1.3079_05 02.10.2011
+
+ [ API CHANGES ]
+ * Deprecation of 'before', 'before_template' and 'after' in favor of hook
+ (Alberto Simões)
+
+ [ ENHANCEMENTS]
+ * Add support for the HTTP 'PATCH' verb (David Precious)
+
+ [ BUG FIXES ]
+ * Minor corrections (jamhed, felixdo)
+ * Log if a view and or a layout is not found (Alberto Simões, reported
+ by David Previous)
+
1.3079_04 02.10.2011
[ ENHANCEMENTS ]
View
@@ -279,7 +279,6 @@ t/17_apps/00_base.t
t/17_apps/01_settings.t
t/17_apps/02_load_app.t
t/17_apps/03_prefix.t
-t/17_apps/04_issue_91.t
t/17_apps/05_api.t
t/19_dancer/01_script.t
t/19_dancer/02_script_version_from.t
@@ -309,8 +308,6 @@ t/25_exceptions/views/layouts/main.tt
t/lib/EasyMocker.pm
t/lib/Forum.pm
t/lib/LinkBlocker.pm
-t/lib/MyApp.pm
-t/lib/MyAppFoo.pm
t/lib/TestApp.pm
t/lib/TestAppUnicode.pm
t/lib/TestPlugin.pm
View
@@ -5,7 +5,7 @@ use warnings;
use Carp;
use Cwd 'realpath';
-our $VERSION = '1.3079_04';
+our $VERSION = '1.3079_05';
our $AUTHORITY = 'SUKRIA';
use Dancer::App;
@@ -67,6 +67,7 @@ our @EXPORT = qw(
params
pass
path
+ patch
post
prefix
push_header
@@ -99,10 +100,26 @@ our @EXPORT = qw(
# Dancer's syntax
-sub after { Dancer::Hook->new('after', @_) }
+sub after {
+ Dancer::Deprecation->deprecated(reason => "use hooks!",
+ version => '1.3080',
+ fatal => 0);
+ Dancer::Hook->new('after', @_);
+}
+sub before {
+ Dancer::Deprecation->deprecated(reason => "use hooks!",
+ version => '1.3080',
+ fatal => 0);
+ Dancer::Hook->new('before', @_);
+}
+sub before_template {
+ Dancer::Deprecation->deprecated(reason => "use hooks!",
+ version => '1.3080',
+ fatal => 0);
+ Dancer::Hook->new('before_template', @_);
+}
+
sub any { Dancer::App->current->registry->any_add(@_) }
-sub before { Dancer::Hook->new('before', @_) }
-sub before_template { Dancer::Hook->new('before_template', @_) }
sub captures { Dancer::SharedData->request->params->{captures} }
sub cookie { Dancer::Cookies->cookie( @_ ) }
sub cookies { Dancer::Cookies->cookies }
@@ -142,6 +159,7 @@ sub options { Dancer::App->current->registry->universal_add('options', @
sub params { Dancer::SharedData->request->params(@_) }
sub param { params->{$_[0]} }
sub pass { Dancer::SharedData->response->pass(1) }
+sub patch { Dancer::App->current->registry->universal_add('patch', @_) }
sub path { Dancer::FileUtils::path(@_) }
sub post { Dancer::App->current->registry->universal_add('post', @_) }
sub prefix { Dancer::App->current->set_prefix(@_) }
@@ -488,7 +506,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);
+ use Dancer qw(before after get post put patch);
# Export everything but pass to avoid clashing with Test::More
use Test::More;
@@ -548,11 +566,13 @@ Add a hook at the B<after> position:
after sub {
my $response = shift;
- # do something with request
+ # 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.
+having executed a route, but before the response is returned (so you can modify
+the response here, if you need to)..
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
@@ -1010,9 +1030,13 @@ by the layout
=item after
-This is an alias for 'after'.
+This is an alias for C<after>.
-This hook receives as argument a L<Dancer::Response> object.
+This hook runs after a request has been processed, but before the response is
+sent.
+
+It receives a L<Dancer::Response> object, which it can modify
+if it needs to make changes to the response which is about to be sent.
hook after => sub {
my $response = shift;
@@ -1130,6 +1154,25 @@ You should always C<return> after calling C<pass>:
}
};
+=head2 patch
+
+Defines a route for HTTP B<PATCH> requests to the given URL:
+
+ patch '/resource' => sub { ... };
+
+(C<PATCH> is a relatively new and not-yet-common HTTP verb, which is intended to
+work as a "partial-PUT", transferring just the changes; please see
+L<http://tools.ietf.org/html/rfc5789|RFC5789> for further details.)
+
+Please be aware that, if you run your app in standalone mode, C<PATCH> requests
+will not reach your app unless you have a new version of L<HTTP::Server::Simple>
+which accepts C<PATCH> as a valid verb. The current version at time of writing,
+C<0.44>, does not. A pull request has been submitted to add this support, which
+you can find at:
+
+L<https://github.com/bestpractical/http-server-simple/pull/1>
+
+
=head2 path
Concatenates multiple paths together, without worrying about the underlying
View
@@ -449,6 +449,14 @@ wouldn't store your users passwords in the clear, would you?)) follows:
+=head3 Retrieve complete hash stored in session
+
+Get complete hash stored in session:
+
+ my $hash = session;
+
+
+
=head1 APPEARANCE
=head2 Using templates - views and layouts
@@ -176,9 +176,9 @@ Start by creating a simple app.psgi file:
my $app1 = sub {
my $env = shift;
local $ENV{DANCER_APPDIR} = '/Users/franck/tmp/app1';
- setting appdir => '/Users/franck/tmp/app1';
load_app "app1";
Dancer::App->set_running_app('app1');
+ setting appdir => '/Users/franck/tmp/app1';
Dancer::Config->load;
my $request = Dancer::Request->new( env => $env );
Dancer->dance($request);
@@ -187,9 +187,9 @@ Start by creating a simple app.psgi file:
my $app2 = sub {
my $env = shift;
local $ENV{DANCER_APPDIR} = '/Users/franck/tmp/app2';
- setting appdir => '/Users/franck/tmp/app2';
load_app "app2";
Dancer::App->set_running_app('app2');
+ setting appdir => '/Users/franck/tmp/app2';
Dancer::Config->load;
my $request = Dancer::Request->new( env => $env );
Dancer->dance($request);
@@ -59,7 +59,7 @@ method 'get', so only GET requests will be honoured by that route:
get '/hello/:name' => sub {
# do something
- return "Hello ".params->{name};
+ return "Hello ".param('name');
};
@@ -121,13 +121,13 @@ be set in the params hashref.
get '/hello/:name' => sub {
- "Hey ".params->{name}.", welcome here!";
+ "Hey ".param('name').", welcome here!";
};
Tokens can be optional, for example:
get '/hello/:name?' => sub {
- "Hello there " . params->{name} || "whoever you are!";
+ "Hello there " . param('name') || "whoever you are!";
};
@@ -621,7 +621,7 @@ This is a possible webapp created with Dancer:
};
get '/hello/:name' => sub {
- "Hello ".params->{name};
+ "Hello ".param('name');
};
# run the webserver
@@ -61,7 +61,7 @@ sub format_message {
chomp $message;
if (setting('charset')) {
- unless (setting('charset') eq "UTF-8" && Encode::is_utf8($message)) {
+ unless (uc setting('charset') eq "UTF-8" && Encode::is_utf8($message)) {
$message = Encode::encode(setting('charset'), $message);
}
}
@@ -8,7 +8,7 @@ use Dancer::Plugin;
register 'ajax' => \&ajax;
-before sub {
+hook before => sub {
if (request->is_ajax) {
content_type('text/xml');
}
View
@@ -87,6 +87,7 @@ sub is_post { $_[0]->{method} eq 'POST' }
sub is_get { $_[0]->{method} eq 'GET' }
sub is_put { $_[0]->{method} eq 'PUT' }
sub is_delete { $_[0]->{method} eq 'DELETE' }
+sub is_patch { $_[0]->{method} eq 'PATCH' }
sub header { $_[0]->{headers}->header($_[1]) }
# public interface compat with CGI.pm objects
@@ -678,6 +679,10 @@ Return true if the method requested by the client is 'GET'
Return true if the method requested by the client is 'HEAD'
+=head2 is_patch()
+
+Return true if the method requested by the client is 'PATCH'
+
=head2 is_post()
Return true if the method requested by the client is 'POST'
@@ -91,7 +91,7 @@ sub register_route {
sub any_add {
my ($self, $pattern, @rest) = @_;
- my @methods = qw(get post put delete options);
+ my @methods = qw(get post put patch delete options);
if (ref($pattern) eq 'ARRAY') {
@methods = @$pattern;
@@ -4,6 +4,7 @@ use strict;
use warnings;
use Carp;
+use Dancer::Logger;
use Dancer::Factory::Hook;
use Dancer::FileUtils 'path';
@@ -41,9 +42,14 @@ sub layout {
my $layout_name = $self->_template_name($layout);
my $layout_path = path(Dancer::App->current->setting('views'), 'layouts', $layout_name);
- my $full_content =
- Dancer::Template->engine->render($layout_path,
- {%$tokens, content => $content});
+ my $full_content;
+ if (-e $layout_path) {
+ $full_content = Dancer::Template->engine->render(
+ $layout_path, {%$tokens, content => $content});
+ } else {
+ $full_content = $content;
+ Dancer::Logger::error("Defined layout ($layout_name) was not found!");
+ }
$full_content;
}
@@ -126,16 +132,31 @@ sub template {
my ($class, $view, $tokens, $options) = @_;
my ($content, $full_content);
+ my $engine = Dancer::Template->engine;
+
# it's important that $tokens is not undef, so that things added to it via
# a before_template in apply_renderer survive to the apply_layout. GH#354
$tokens ||= {};
$options ||= {};
- $content = $view ? Dancer::Template->engine->apply_renderer($view, $tokens)
- : delete $options->{content};
+ if ($view) {
+ # check if the requested view exists
+ my $view_path = $engine->view($view);
+ if (-e $view_path) {
+ $content = $engine->apply_renderer($view, $tokens);
+ } else {
+ Dancer::Logger::error("Supplied view ($view) was not found.");
+ return Dancer::Error->new(
+ code => 500,
+ message => 'view not found',
+ )->render();
+ }
+ } else {
+ $content = delete $options->{content};
+ }
defined $content and $full_content =
- Dancer::Template->engine->apply_layout($content, $tokens, $options);
+ $engine->apply_layout($content, $tokens, $options);
defined $full_content
and return $full_content;
View
@@ -179,7 +179,13 @@ applications focus on the verbs which closely map to the CRUD (Create,
Retrieve, Update, Delete) operations most database driven applications need to
implement.
-Dancer currently supports GET, PUT, POST, DELETE, OPTIONS which map to
+In addition, the C<PATCH> verb was defined in
+L<RFC5789|http://tools.ietf.org/html/rfc5789>, and is intended as a
+"partial PUT" - sending just the changes required to the entity in question.
+How this would be handled is down to your app, it will vary depending on the
+type of entity in question and the serialisation in use.
+
+Dancer currently supports GET, PUT/PATCH, POST, DELETE, OPTIONS which map to
Retrieve, Update, Create, Delete respectively. Let's take a look now at the
C</add> route handler which handles a POST operation.
@@ -41,7 +41,7 @@ Test::TCP::test_tcp(
show_errors => 1,
startup_info => 0 );
- after sub {
+ hook after => sub {
my $response = shift;
$response->header('X-Foo', 2);
};
@@ -10,8 +10,8 @@ plan tests => 19;
{
my $i = 0;
- before sub { content_type('text/xhtml'); };
- before sub {
+ hook before => sub { content_type('text/xhtml'); };
+ hook before => sub {
if ( request->path_info eq '/redirect_from' ) {
redirect('/redirect_to');
}
@@ -53,7 +53,7 @@ plan tests => 19;
# filters and params
{
- before sub {
+ hook before => sub {
return if request->path !~ /foo/;
ok( defined( params->{'format'} ),
"param format is defined in before filter" );
@@ -70,13 +70,13 @@ plan tests => 19;
# filter and halt
{
- before sub {
+ hook before => sub {
unless (params->{'requested'}) {
return halt("stopped");
}
};
- before sub {
+ hook before => sub {
unless (params->{'requested'}) {
halt("another halt");
}
Oops, something went wrong.

0 comments on commit 12d646a

Please sign in to comment.