Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'release/1.3012'

  • Loading branch information...
commit cffd469c197a8731e45429a6d41c173502a4ad73 2 parents c580150 + 5d4296e
Alexis Sukrieh authored
Showing with 507 additions and 327 deletions.
  1. +41 −2 CHANGES
  2. +3 −2 MANIFEST
  3. +134 −174 lib/Dancer.pm
  4. +1 −1  lib/Dancer/Config.pm
  5. +17 −14 lib/Dancer/Cookies.pm
  6. +31 −7 lib/Dancer/Deployment.pod
  7. +20 −2 lib/Dancer/Deprecation.pm
  8. +24 −4 lib/Dancer/Handler.pm
  9. +1 −1  lib/Dancer/Handler/PSGI.pm
  10. +0 −13 lib/Dancer/Renderer.pm
  11. +14 −0 lib/Dancer/Response.pm
  12. +0 −3  lib/Dancer/Route.pm
  13. +1 −1  lib/Dancer/Serializer/JSON.pm
  14. +2 −1  lib/Dancer/Session/Abstract.pm
  15. +44 −1 lib/Dancer/Template/Abstract.pm
  16. +4 −2 lib/Dancer/Template/TemplateToolkit.pm
  17. +9 −11 lib/Dancer/Test.pm
  18. +2 −2 script/dancer
  19. +3 −3 t/00_base/14_changelog.t
  20. +5 −5 t/01_config/06_stack_trace.t
  21. +3 −5 t/03_route_handler/18_auto_page.t
  22. +2 −0  t/03_route_handler/29_forward.t
  23. +0 −32 t/09_cookies/04_has_changed.t
  24. +1 −1  t/10_template/05_template_toolkit.t
  25. +4 −3 t/12_response/01_CRLF_injection.t
  26. +6 −6 t/12_response/03_charset.t
  27. +33 −26 t/12_response/07_cookies.t
  28. +52 −0 t/12_response/08_drop_content.t
  29. +22 −0 t/12_response/09_headers_to_array.t
  30. +23 −0 t/14_serializer/16_bug_gh_299.t
  31. +5 −5 t/20_deprecation/01_api.t
View
43 CHANGES
@@ -1,8 +1,9 @@
-1.3011_01 23.02.2011
+1.3012 01.03.2011
[ BUG FIXES ]
* Fix cookies disappearing when more than one is set.
- (Chris Andrews)
+ Complete refactoring of the cookie handling.
+ (Chris Andrews, Geistteufel)
* Properly set the settings in Dancer::Test only after config loading.
(Sawyer X)
* Fix possible loss of last directory in path.
@@ -12,8 +13,16 @@
(Sawyer X)
* Fix anti UNC substitution under Cygwin
(Rowan Thorpe)
+ * GH#299 Return appropriate headers on HEAD request (content-type, ...)
+ (franck cuny)
+ * Use the dancer_version variable in scaffolded app.
+ (Sawyer X, reported by Brian E. Lozier)
[ ENHANCEMENTS ]
+ * Fix manifest
+ (Damien Krotkine)
+ * Various packaging, changelog and test fixes
+ (Damien Krotkine)
* Add a new accessor to Dancer::Request: ->uri.
(it's an alias to ->request_uri)
(Franck Cuny)
@@ -40,10 +49,40 @@
* Refactoring of internal objects in the core,
use more of Dancer::Object. Introduce attributes_defaults
(Damien Krotkine)
+ * Add a perl_version variable to all templates, used in scaffolded app.
+ (Sawyer X, reported by Brian E. Lozier)
+ * Better output when template file is missing.
+ (Brian E. Lozier, Sawyer X)
[ DOCUMENTATION ]
* Add missing methods (e.g. "referer"), sorting, clean up.
(Flavio Poletti)
+ * Complete working example of deployment under Nginx/Starman in
+ Deployment.pod
+ (Geistteufel)
+
+1.3010_01 12.02.2011
+
+ [ BUG FIXES ]
+ * GH#136: fix again Mime::Type issues in preforking environment
+ (Chris Andrews)
+ * GH#220: fix for path issues under MacOS X and Windows platforms.
+ A new function is provided by Dancer::FileUtils: path_no_verify()
+ (Rowan Thorpe)
+ * Fix for infinite loops detection in before filters
+ (Flavio Poletti)
+
+ [ ENHANCEMENTS ]
+ * Better detection of the application layout under non-UNIX platforms.
+ (Rowan Thorpe, Alexis Sukrieh)
+
+ [ DOCUMENTATION ]
+ * Fix a typo in Dancer::Request::Upload's POD
+ (Rowan Thorpe)
+ * Better documentation for the before filters, explanations about the
+ potential infinite loops that can happen when using before filters (and
+ what Dancer does in that case).
+ (Flavio Poletti)
1.3011 14.02.2011
View
5 MANIFEST
@@ -28,7 +28,6 @@ lib/Dancer/Handler.pm
lib/Dancer/Handler/Debug.pm
lib/Dancer/Handler/PSGI.pm
lib/Dancer/Handler/Standalone.pm
-lib/Dancer/Helpers.pm
lib/Dancer/HTTP.pm
lib/Dancer/Introduction.pod
lib/Dancer/Logger.pm
@@ -207,7 +206,6 @@ t/09_cookies/000_create_fake_env.t
t/09_cookies/01_use.t
t/09_cookies/02_cookie_object.t
t/09_cookies/03_persistence.t
-t/09_cookies/04_has_changed.t
t/09_cookies/05_api.t
t/10_template/000_create_fake_env.t
t/10_template/01_factory.t
@@ -234,6 +232,8 @@ t/12_response/04_charset_server.t
t/12_response/05_api.t
t/12_response/06_filter_halt_status.t
t/12_response/07_cookies.t
+t/12_response/08_drop_content.t
+t/12_response/09_headers_to_array.t
t/13_engines/00_load.t
t/13_engines/02_template_init.t
t/14_serializer/000_create_fake_env.t
@@ -252,6 +252,7 @@ t/14_serializer/12_bug_gh106.t
t/14_serializer/13_xml.t
t/14_serializer/14_api.t
t/14_serializer/14_show_errors.t
+t/14_serializer/16_bug_gh_299.t
t/14_serializer/handler-helper.t
t/15_plugins/000_create_fake_env.t
t/15_plugins/01_register.t
View
308 lib/Dancer.pm
@@ -7,18 +7,17 @@ use Cwd 'realpath';
use vars qw($VERSION $AUTHORITY @EXPORT);
-$VERSION = '1.3011_01';
+$VERSION = '1.3012';
$AUTHORITY = 'SUKRIA';
+use Dancer::App;
use Dancer::Config;
-use Dancer::Deprecation;
+use Dancer::Cookies;
use Dancer::FileUtils;
use Dancer::GetOpt;
use Dancer::Error;
use Dancer::Logger;
-use Dancer::Plugin;
use Dancer::Renderer;
-use Dancer::Response;
use Dancer::Route;
use Dancer::Serializer::JSON;
use Dancer::Serializer::YAML;
@@ -27,8 +26,8 @@ use Dancer::Serializer::Dumper;
use Dancer::Session;
use Dancer::SharedData;
use Dancer::Handler;
-use Dancer::ModuleLoader;
use Dancer::MIME;
+
use File::Spec;
use base 'Exporter';
@@ -56,6 +55,7 @@ use base 'Exporter';
get
halt
header
+ push_header
headers
layout
load
@@ -106,8 +106,9 @@ sub captures { Dancer::SharedData->request->params->{captures} }
sub cookies { Dancer::Cookies->cookies }
sub config { Dancer::Config::settings() }
sub content_type { Dancer::SharedData->response->content_type(@_) }
-sub dance { Dancer::start(@_) }
+sub dance { goto &start }
sub debug { goto &Dancer::Logger::debug }
+sub del { Dancer::App->current->registry->universal_add('delete', @_) }
sub dirname { Dancer::FileUtils::dirname(@_) }
sub engine { Dancer::Engine->engine(@_) }
sub error { goto &Dancer::Logger::error }
@@ -115,165 +116,48 @@ sub false { 0 }
sub forward { Dancer::SharedData->response->forward(shift) }
sub from_dumper { Dancer::Serializer::Dumper::from_dumper(@_) }
sub from_json { Dancer::Serializer::JSON::from_json(@_) }
-sub from_yaml { Dancer::Serializer::YAML::from_yaml(@_) }
sub from_xml { Dancer::Serializer::XML::from_xml(@_) }
+sub from_yaml { Dancer::Serializer::YAML::from_yaml(@_) }
sub get { map { my $r = $_; Dancer::App->current->registry->universal_add($r, @_) } qw(head get) }
+sub halt { Dancer::SharedData->response->halt(@_) }
sub header { goto &headers }
+sub push_header { Dancer::SharedData->response->push_header(@_); }
+sub headers { Dancer::SharedData->response->headers(@_); }
sub layout { set(layout => shift) }
sub load { require $_ for @_ }
+sub load_app { goto &_load_app } # goto doesn't add a call frame. So caller() will work as expected
sub logger { set(logger => @_) }
-sub halt { Dancer::SharedData->response->halt(@_) }
-sub headers { Dancer::SharedData->response->headers(@_); }
-sub mime_type {
- my $mime = Dancer::MIME->instance();
- if (scalar(@_)==2) { $mime->add_mime_type(@_) }
- elsif (scalar(@_)==1) { $mime->mime_type_for(@_) }
- else { $mime->aliases }
-}
+sub mime_type { goto &_mime_type }
+sub options { Dancer::App->current->registry->universal_add('options', @_) }
sub params { Dancer::SharedData->request->params(@_) }
sub pass { Dancer::SharedData->response->pass(1) }
sub path { realpath(Dancer::FileUtils::path(@_)) }
sub post { Dancer::App->current->registry->universal_add('post', @_) }
sub prefix { Dancer::App->current->set_prefix(@_) }
-sub del { Dancer::App->current->registry->universal_add('delete', @_) }
-sub options { Dancer::App->current->registry->universal_add('options', @_) }
sub put { Dancer::App->current->registry->universal_add('put', @_) }
-sub redirect {
- my ($destination, $status) = @_;
- if ($destination =~ m!^(\w://)?/!) {
- # no absolute uri here, build one, RFC 2616 forces us to do so
- my $request = Dancer::SharedData->request;
- $destination = $request->uri_for($destination, {}, 1);
- }
- my $response = Dancer::SharedData->response;
- $response->status($status || 302);
- $response->headers('Location' => $destination);
-}
-sub render_with_layout {
- my ($content, $tokens, $options) = @_;
-
- Dancer::Deprecation::deprecated(
- feature => 'render_with_layout',
- version => '1.3000',
- reason => "use the 'engine' keyword to get the template engine, and use 'apply_layout' on the result",
- );
-
- my $full_content = Dancer::Template->engine->apply_layout($content, $tokens, $options);
-
- if (! defined $full_content) {
- return Dancer::Error->new(
- code => 404,
- message => "Page not found",
- )->render();
- }
- return $full_content;
-}
+sub redirect { goto &_redirect }
+sub render_with_layout { Dancer::Template::Abstract->_render_with_layout(@_) }
sub request { Dancer::SharedData->request }
-sub send_error {
- my ( $content, $status ) = @_;
- $status ||= 500;
- Dancer::Error->new( code => $status, message => $content )->render();
-}
-sub send_file {
- my ($path) = @_;
-
- my $request = Dancer::Request->new_for_request('GET' => $path);
- Dancer::SharedData->request($request);
-
- my $resp = Dancer::Renderer::get_file_response();
- return $resp if $resp;
-
- Dancer::Error->new(
- code => 404,
- message => "No such file: `$path'"
- )->render();
-
-}
+sub send_error { Dancer::Error->new(message => $_[0], code => $_[1] || 500)->render() }
+sub send_file { goto &_send_file }
sub set { goto &setting }
+sub set_cookie { Dancer::Cookies->set_cookie(@_) }
sub setting { Dancer::App->applications ? Dancer::App->current->setting(@_) : Dancer::Config::setting(@_) }
-# set_cookie name => value,
-# expires => time() + 3600, domain => '.foo.com'
-sub set_cookie {
- my ( $name, $value, %options ) = @_;
- Dancer::Cookies->cookies->{$name} = Dancer::Cookie->new(
- name => $name,
- value => $value,
- %options
- );
-}
-sub session {
- croak "Must specify session engine in settings prior to using 'session' keyword" unless setting('session');
- if (@_ == 0) {
- return Dancer::Session->get;
- }
- else {
- return (@_ == 1)
- ? Dancer::Session->read(@_)
- : Dancer::Session->write(@_);
- }
-}
+sub session { goto &_session }
sub splat { @{ Dancer::SharedData->request->params->{splat} || [] } }
-sub status { Dancer::SharedData->response->status(@_) }
-sub template {
- my ( $view, $tokens, $options ) = @_;
-
- my $content;
-
- if ($view) {
- $content = Dancer::Template->engine->apply_renderer( $view, $tokens );
- if ( !defined $content ) {
- return Dancer::Error->new(
- code => 404,
- message => "Page not found",
- )->render();
- }
- }
- else {
- $options ||= {};
- $content = delete $options->{content};
- }
-
- my $full_content =
- Dancer::Template->engine->apply_layout( $content, $tokens, $options );
- defined $full_content
- and return $full_content;
-
- Dancer::Error->new(
- code => 404,
- message => "Page not found",
- )->render();
-}
-sub true { 1 }
+sub start { goto &_start }
+sub status { Dancer::SharedData->response->status(@_) }
+sub template { Dancer::Template::Abstract->template(@_) }
sub to_dumper { Dancer::Serializer::Dumper::to_dumper(@_) }
sub to_json { Dancer::Serializer::JSON::to_json(@_) }
-sub to_yaml { Dancer::Serializer::YAML::to_yaml(@_) }
sub to_xml { Dancer::Serializer::XML::to_xml(@_) }
+sub to_yaml { Dancer::Serializer::YAML::to_yaml(@_) }
+sub true { 1 }
sub upload { Dancer::SharedData->request->upload(@_) }
sub uri_for { Dancer::SharedData->request->uri_for(@_) }
sub var { Dancer::SharedData->var(@_) }
sub vars { Dancer::SharedData->vars }
sub warning { goto &Dancer::Logger::warning }
-# FIXME handle previous usage of load_app with multiple app names
-sub load_app {
- my ($app_name, %options) = @_;
- Dancer::Logger::core("loading application $app_name");
-
- # set the application
- my $app = Dancer::App->set_running_app($app_name);
-
- # Application options
- $app->prefix($options{prefix}) if $options{prefix};
- $app->settings($options{settings}) if $options{settings};
-
- # load the application
- my ($package, $script) = caller;
- _init($script);
- my ($res, $error) = Dancer::ModuleLoader->load($app_name);
- $res or croak "unable to load application $app_name : $error";
-
- # restore the main application
- Dancer::App->set_running_app('main');
-}
# When importing the package, strict and warnings pragma are loaded,
# and the appdir detection is performed.
@@ -292,27 +176,36 @@ sub import {
Dancer::GetOpt->process_args();
- _init($script);
+ _init_script_dir($script);
Dancer::Config->load;
}
-# Start/Run the application with the chosen apphandler
-sub start {
- my ($class, $request) = @_;
- Dancer::Config->load;
+# private code
- # Backward compatibility for app.psgi that has sub { Dancer->dance($req) }
- if ($request) {
- return Dancer::Handler->handle_request($request);
- }
+# FIXME handle previous usage of load_app with multiple app names
+sub _load_app {
+ my ($app_name, %options) = @_;
+ my $script = (caller)[1];
+ Dancer::Logger::core("loading application $app_name");
- my $handler = Dancer::Handler->get_handler;
- Dancer::Logger::core("loading handler '".ref($handler)."'");
- return $handler->dance;
+ # set the application
+ my $app = Dancer::App->set_running_app($app_name);
+
+ # Application options
+ $app->prefix($options{prefix}) if $options{prefix};
+ $app->settings($options{settings}) if $options{settings};
+
+ # load the application
+ _init_script_dir($script);
+ my ($res, $error) = Dancer::ModuleLoader->load($app_name);
+ $res or croak "unable to load application $app_name : $error";
+
+ # restore the main application
+ Dancer::App->set_running_app('main');
}
-sub _init {
- my $script = shift;
+sub _init_script_dir {
+ my ($script) = @_;
my ($script_vol, $script_dirs, $script_name) =
File::Spec->splitpath(File::Spec->rel2abs($script));
@@ -326,9 +219,9 @@ sub _init {
my @script_dirs = File::Spec->splitdir($script_dirs);
my $script_path;
if ($script_vol) {
- $script_path = path($script_vol, $script_dirs);
+ $script_path = Dancer::path($script_vol, $script_dirs);
} else {
- $script_path = path($script_dirs);
+ $script_path = Dancer::path($script_dirs);
}
my $LAYOUT_PRE_DANCER_1_2 = 1;
@@ -338,34 +231,91 @@ sub _init {
if ($script_dirs[$#script_dirs - 1] eq 'bin')
or ($script_dirs[$#script_dirs - 1] eq 'public');
- setting appdir => $ENV{DANCER_APPDIR}
- || (
+ my $appdir = $ENV{DANCER_APPDIR} || (
$LAYOUT_PRE_DANCER_1_2
? $script_path
- : File::Spec->rel2abs(path($script_path, File::Spec->updir()))
- );
+ : File::Spec->rel2abs(Dancer::path($script_path, '..'))
+ );
+ Dancer::setting(appdir => $appdir);
# once the dancer_appdir have been defined, we export to env
- $ENV{DANCER_APPDIR} = setting('appdir');
+ $ENV{DANCER_APPDIR} = $appdir;
- Dancer::Logger::core(
- "initializing appdir to: `" . setting('appdir') . "'");
+ Dancer::Logger::core("initializing appdir to: `$appdir'");
- setting confdir => $ENV{DANCER_CONFDIR}
- || setting('appdir');
+ Dancer::setting(confdir => $ENV{DANCER_CONFDIR}
+ || $appdir);
- setting public => $ENV{DANCER_PUBLIC}
- || Dancer::FileUtils::path_no_verify(setting('appdir'), 'public');
+ Dancer::setting(public => $ENV{DANCER_PUBLIC}
+ || Dancer::FileUtils::path_no_verify($appdir, 'public'));
- setting views => $ENV{DANCER_VIEWS}
- || Dancer::FileUtils::path_no_verify(setting('appdir'), 'views');
+ Dancer::setting(views => $ENV{DANCER_VIEWS}
+ || Dancer::FileUtils::path_no_verify($appdir, 'views'));
- setting logger => 'file';
+ Dancer::setting(logger => 'file');
- my ($res, $error) = Dancer::ModuleLoader->use_lib(Dancer::FileUtils::path_no_verify(setting('appdir'), 'lib'));
+ my ($res, $error) = Dancer::ModuleLoader->use_lib(Dancer::FileUtils::path_no_verify($appdir, 'lib'));
$res or croak "unable to set libdir : $error";
}
+sub _mime_type {
+ my $mime = Dancer::MIME->instance();
+ @_ == 0 ? $mime->aliases
+ : @_ == 1 ? $mime->mime_type_for(@_)
+ : $mime->add_mime_type(@_);
+}
+
+sub _redirect {
+ my ($destination, $status) = @_;
+ if ($destination =~ m!^(\w://)?/!) {
+ # no absolute uri here, build one, RFC 2616 forces us to do so
+ my $request = Dancer::SharedData->request;
+ $destination = $request->uri_for($destination, {}, 1);
+ }
+ my $response = Dancer::SharedData->response;
+ $response->status($status || 302);
+ $response->headers('Location' => $destination);
+}
+
+sub _session {
+ engine 'session'
+ or croak "Must specify session engine in settings prior to using 'session' keyword";
+ @_ == 0 ? Dancer::Session->get
+ : @_ == 1 ? Dancer::Session->read(@_)
+ : Dancer::Session->write(@_);
+}
+
+sub _send_file {
+ my ($path) = @_;
+
+ my $request = Dancer::Request->new_for_request('GET' => $path);
+ Dancer::SharedData->request($request);
+
+ my $resp = Dancer::Renderer::get_file_response();
+ return $resp if $resp;
+
+ Dancer::Error->new(
+ code => 404,
+ message => "No such file: `$path'"
+ )->render();
+
+}
+
+# Start/Run the application with the chosen apphandler
+sub _start {
+ my ($class, $request) = @_;
+ Dancer::Config->load;
+
+ # Backward compatibility for app.psgi that has sub { Dancer->dance($req) }
+ if ($request) {
+ return Dancer::Handler->handle_request($request);
+ }
+
+ my $handler = Dancer::Handler->get_handler;
+ Dancer::Logger::core("loading handler '".ref($handler)."'");
+ return $handler->dance;
+}
+
1;
__END__
@@ -673,10 +623,20 @@ Adds custom headers to responses:
=head2 header
-Adds a custom header to response:
+adds a custom header to response:
+
+ get '/send/header', sub {
+ header 'x-my-header' => 'shazam!';
+ }
+
+=head2 push_header
+
+Do the same as C<header>, but allow for multiple headers with the same name.
get '/send/header', sub {
- header 'X-My-Header' => 'shazam!';
+ push_header 'x-my-header' => '1';
+ push_header 'x-my-header' => '2';
+ will result in two headers "x-my-header" in the response
}
=head2 layout
View
2  lib/Dancer/Config.pm
@@ -86,7 +86,7 @@ my $normalizers = {
};
sub mime_types {
- Dancer::Deprecation::deprecated(
+ Dancer::Deprecation->deprecated(
reason => "use 'mime_type' from Dancer.pm",
);
my $mime = Dancer::MIME->instance();
View
31 lib/Dancer/Cookies.pm
@@ -36,15 +36,23 @@ sub parse_cookie_from_env {
return $cookies;
}
-# return true if the given cookie is not the same as the one sent by the client
-sub has_changed {
- my ($self, $cookie) = @_;
- my ($name, $value) = ($cookie->{name}, $cookie->{value});
-
- my $client_cookies = parse_cookie_from_env();
- my $search = $client_cookies->{$name};
- return 1 unless defined $search;
- return $search->value ne $value;
+# set_cookie name => value,
+# expires => time() + 3600, domain => '.foo.com'
+sub set_cookie {
+ my ( $class, $name, $value, %options ) = @_;
+ my $cookie = Dancer::Cookie->new(
+ name => $name,
+ value => $value,
+ %options
+ );
+ Dancer::Cookies->set_cookie_object($name => $cookie);
+}
+
+sub set_cookie_object {
+ my ($class, $name, $cookie) = @_;
+ Dancer::SharedData->response->push_header(
+ 'Set-Cookie' => $cookie->to_header);
+ Dancer::Cookies->cookies->{$name} = $cookie;
}
1;
@@ -94,11 +102,6 @@ of all cookies.
It also returns all the hashref it created.
-=head2 has_changed
-
-Accepts a cookie and returns true if the given cookie is not the same as the one
-sent by the user.
-
=head1 AUTHOR
Alexis Sukrieh
View
38 lib/Dancer/Deployment.pod
@@ -323,18 +323,42 @@ This configuration will proxy all request to the B</application> path to the pat
with Nginx:
- upstream backend {
- server 10.0.0.1:8080;
- server 10.0.0.2:8080;
- ...
+ upstream backendurl {
+ server unix:THE_PATH_OF_YOUR_PLACKUP_SOCKET_HERE.sock;
}
server {
- location / {
- proxy_pass http://backend;
- }
+ listen 80;
+ server_name YOUR_HOST_HERE;
+
+ access_log /var/log/YOUR_ACCESS_LOG_HERE.log;
+ error_log /var/log/YOUR_ERROR_LOG_HERE.log info;
+
+ root YOUR_ROOT_PROJECT/public;
+ location / {
+ try_files $uri @proxy;
+ access_log off;
+ expires max;
+ }
+
+ location @proxy {
+ proxy_set_header Host $http_host;
+ proxy_set_header X-Forwarded-Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_pass http://backendurl;
+ }
+
}
+You will need plackup to start a worker listening on a socket :
+
+ cd YOUR_PROJECT_PATH
+ sudo -u www plackup -E production -s Starman --workers=2 -l THE_PATH_OF_YOUR_PLACKUP_SOCKET_HERE.sock -a bin/app.pl
+
+A good way to start this is to use C<daemontools> and place this line with
+all environments variables in the "run" file.
+
=head2 Running from Apache
You can run your Dancer app from Apache using the following examples:
View
22 lib/Dancer/Deprecation.pm
@@ -5,7 +5,7 @@ use warnings;
use Carp qw/croak carp/;
sub deprecated {
- my %args = @_;
+ my ($class, %args) = @_;
my ( $package, undef, undef, $sub ) = caller(1);
@@ -37,7 +37,7 @@ Dancer::Deprecation - handle deprecation messages
=head1 SYNOPSIS
- Dancer::Deprecation::deprecated(
+ Dancer::Deprecation->deprecated(
feature => 'sub_name',
version => '1.3000',
reason => '...',
@@ -49,6 +49,24 @@ Dancer::Deprecation - handle deprecation messages
=head3 deprecated
+List of possible parameters:
+
+=over 4
+
+=item B<feature> name of the feature to deprecate
+
+=item B<version> from which version the feature is deprecated
+
+=item B<message> message to display
+
+=item B<fatal> if set to true, croak instead of carp
+
+item B<reason> why is the feature deprecated
+
+=back
+
+You can call the method with no arguments, and a default message using informations from C<caller> will be build for you.
+
=head1 LICENSE
This module is free software and is distributed under the same terms as Perl
View
28 lib/Dancer/Handler.pm
@@ -4,6 +4,7 @@ use strict;
use warnings;
use Carp 'croak';
+use File::stat;
use HTTP::Headers;
use Dancer::Logger;
@@ -115,19 +116,38 @@ sub render_response {
my $response = Dancer::SharedData->response();
my $content = $response->content;
- unless ( ref($content) eq 'GLOB' ) {
+ unless ( ref($content) eq 'GLOB' ) {
my $charset = setting('charset');
my $ctype = $response->header('Content-Type');
- if ($charset && $ctype && _is_text($ctype)) {
- $content = Encode::encode($charset, $content);
- $response->header('Content-Type' => "$ctype; charset=$charset")
+ if ( $charset && $ctype && _is_text($ctype) ) {
+ $content = Encode::encode( $charset, $content );
+ $response->header( 'Content-Type' => "$ctype; charset=$charset" )
if $ctype !~ /$charset/;
}
+ $response->header( 'Content-Length' => length($content) )
+ if !defined $response->header('Content-Length');
$content = [$content];
}
+ else {
+ if ( !defined $response->header('Content-Length') ) {
+ my $stat = stat $content;
+ $response->header( 'Content-Length' => $stat->size );
+ }
+ }
+
+ # drop content if request is HEAD
+ $content = ['']
+ if ( defined Dancer::SharedData->request
+ && Dancer::SharedData->request->is_head() );
+ # drop content AND content_length if reponse is 1xx or (2|3)04
+ if ($response->status =~ (/^[23]04$/ )) {
+ $content = [''];
+ $response->header('Content-Length' => 0);
+ }
+
Dancer::Logger::core("response: " . $response->status);
my $status = $response->status();
View
2  lib/Dancer/Handler/PSGI.pm
@@ -71,7 +71,7 @@ sub apply_plack_middlewares {
# XXX remove this after 1.2
if ( ref $middlewares eq 'HASH' ) {
- Dancer::Deprecation::deprecated(
+ Dancer::Deprecation->deprecated(
fatal => 1,
feature => 'Listing Plack middlewares as a hash ref',
reason => 'Must be listed as an array ref',
View
13 lib/Dancer/Renderer.pm
@@ -52,19 +52,6 @@ sub response_with_headers {
$response->{headers} ||= HTTP::Headers->new;
$response->header('X-Powered-By' => "Perl Dancer ${Dancer::VERSION}");
- # add cookies
- my @cookies = ();
- foreach my $c (keys %{Dancer::Cookies->cookies}) {
- my $cookie = Dancer::Cookies->cookies->{$c};
- if (Dancer::Cookies->has_changed($cookie)) {
- push @cookies, $cookie->to_header;
- }
- }
- if (scalar @cookies) {
- my $header = join ', ', @cookies;
- $response->header('Set-Cookie' => $header);
- }
-
return $response;
}
View
14 lib/Dancer/Response.pm
@@ -105,6 +105,20 @@ sub header {
}
}
+sub push_header {
+ my $self = shift;
+ my $header = shift;
+
+ if (@_) {
+ foreach my $h(@_) {
+ $self->{headers}->push_header( $header => $h );
+ }
+ }
+ else {
+ return $self->{headers}->header($header);
+ }
+}
+
sub headers {
my $self = shift;
$self->{headers}->header(@_);
View
3  lib/Dancer/Route.pm
@@ -183,9 +183,6 @@ sub run {
# prevent warnings
$content = (defined $content) ? $content : '';
- # drop content if HEAD request
- $content = '' if $request->is_head;
-
my $ct =
( defined $response && defined $response->content_type )
? $response->content_type()
View
2  lib/Dancer/Serializer/JSON.pm
@@ -75,7 +75,7 @@ sub _options_as_hashref {
carp "options for to_json/from_json must be key value pairs (as a hashref)";
}
else {
- Dancer::Deprecation::deprecated(
+ Dancer::Deprecation->deprecated(
version => '1.3002',
message => 'options as hash for to_json/from_json is DEPRECATED. please pass a hashref',
);
View
3  lib/Dancer/Session/Abstract.pm
@@ -97,7 +97,8 @@ sub write_session_id {
Dancer::Cookie::_epoch_to_gmtstring(time + $expires);
}
- Dancer::Cookies->cookies->{$SESSION_NAME} = Dancer::Cookie->new(%cookie);
+ my $c = Dancer::Cookie->new(%cookie);
+ Dancer::Cookies->set_cookie_object($SESSION_NAME => $c);
}
1;
View
45 lib/Dancer/Template/Abstract.pm
@@ -3,7 +3,10 @@ package Dancer::Template::Abstract;
use strict;
use warnings;
use Carp;
+
+use Dancer::Deprecation;
use Dancer::FileUtils 'path';
+
use base 'Dancer::Engine';
# Overloads this method to implement the rendering
@@ -46,7 +49,6 @@ sub apply_renderer {
($tokens, undef) = _prepare_tokens_options($tokens);
$view = $self->view($view);
- -r $view or return;
$_->($tokens) for (@{Dancer::App->current->registry->hooks->{before_template}});
@@ -91,6 +93,7 @@ sub _prepare_tokens_options {
# these are the default tokens provided for template processing
$tokens ||= {};
+ $tokens->{perl_version} = $];
$tokens->{dancer_version} = $Dancer::VERSION;
$tokens->{settings} = Dancer::Config->settings;
$tokens->{request} = Dancer::SharedData->request;
@@ -102,6 +105,46 @@ sub _prepare_tokens_options {
return ($tokens, $options);
}
+sub _render_with_layout {
+ my ($class, $content, $tokens, $options) = @_;
+
+ Dancer::Deprecation::deprecated(
+ feature => 'render_with_layout',
+ version => '1.3000',
+ reason => "use the 'engine' keyword to get the template engine, and use 'apply_layout' on the result",
+ );
+
+ my $full_content = Dancer::Template->engine->apply_layout($content, $tokens, $options);
+
+ if (! defined $full_content) {
+ return Dancer::Error->new(
+ code => 404,
+ message => "Page not found",
+ )->render();
+ }
+ return $full_content;
+}
+
+sub template {
+ my ($class, $view, $tokens, $options) = @_;
+ my ($content, $full_content);
+
+ $options ||= {};
+ $content = $view ? Dancer::Template->engine->apply_renderer($view, $tokens)
+ : delete $options->{content};
+
+ defined $content and $full_content =
+ Dancer::Template->engine->apply_layout($content, $tokens, $options);
+
+ defined $full_content
+ and return $full_content;
+
+ Dancer::Error->new(
+ code => 404,
+ message => "Page not found",
+ )->render();
+}
+
1;
__END__
View
6 lib/Dancer/Template/TemplateToolkit.pm
@@ -46,8 +46,10 @@ sub init {
sub render {
my ($self, $template, $tokens) = @_;
- croak "'$template' is not a regular file"
- if !ref($template) && (!-f $template);
+
+ if ( ! ref $template ) {
+ -f $template or croak "'$template' doesn't exist or not a regular file";
+ }
my $content = "";
my $charset = setting('charset') || '';
View
20 lib/Dancer/Test.pm
@@ -55,7 +55,7 @@ sub import {
my ($package, $script) = caller;
$class->export_to_level(1, $class, @EXPORT);
- Dancer::_init($options{appdir});
+ Dancer::_init_script_dir($options{appdir});
Dancer::Config->load;
# set a default session engine for tests
@@ -205,19 +205,17 @@ sub dancer_response {
);
Dancer::SharedData->request($request);
- if (Dancer::Renderer::get_action_response()) {
- my $response = Dancer::SharedData->response();
- Dancer::SharedData->reset_response();
- return $response;
- }else{
- my $response = Dancer::SharedData->response();
- Dancer::SharedData->reset_response();
- (defined $response && $response->exists) ? return $response : return undef;
- }
+
+ my $get_action = Dancer::Renderer::get_action_response();
+ my $response = Dancer::SharedData->response();
+ $response->content('') if $method eq 'HEAD';
+ Dancer::SharedData->reset_response();
+ return $response if $get_action;
+ (defined $response && $response->exists) ? return $response : return undef;
}
sub get_response {
- Dancer::Deprecation::deprecated(
+ Dancer::Deprecation->deprecated(
fatal => 1,
feature => 'get_response',
reason => 'Use dancer_response() instead.',
View
4 script/dancer
@@ -372,11 +372,11 @@ WriteMakefile(
<tbody>
<tr>
<td>Perl version</td>
- <td><tt>'.$].'</tt></td>
+ <td><tt><% perl_version %></tt></td>
</tr>
<tr>
<td>Dancer version</td>
- <td><tt>'.$DANCER_VERSION.'</tt></td>
+ <td><tt><% dancer_version %></tt></td>
</tr>
<tr>
<td>Backend</td>
View
6 t/00_base/14_changelog.t
@@ -25,7 +25,7 @@ open(my $fh, '<', $changelog_filename);
my @lines = map { chomp; $_ } <$fh>;
my $tests_count = 0;
-while (1) { $lines[$tests_count++] !~ /^\Q$stop_checking_version\E/ or last }
+while (1) { $lines[$tests_count++] !~ /^\Q$stop_checking_version\E(?:\s|$)/ or last }
# test count = number of lines + 1
plan tests => $tests_count;
@@ -38,12 +38,12 @@ my $line_nb = 0;
my $line;
sub _consume_line { $line = shift @lines;
defined $line or goto END_CHANGES;
- $line =~ /^\Q$stop_checking_version\E/ and goto END_CHANGES;
+ $line =~ /^\Q$stop_checking_version\E(?:\s|$)/ and goto END_CHANGES;
$line_nb++;
}
sub _peek_line { $line = $lines[0];
defined $line or goto END_CHANGES;
- $line =~ /^\Q$stop_checking_version\E/ and goto END_CHANGES;
+ $line =~ /^\Q$stop_checking_version\E(?:\s|$)/ and goto END_CHANGES;
}
sub _fail { fail("changelog error (line $line_nb): " . shift() . " line was : '$line'"); }
sub _fail_bail_out { _fail(@_); BAIL_OUT("changelog is not safe enough to continue checking"); }
View
10 t/01_config/06_stack_trace.t
@@ -14,7 +14,7 @@ use Dancer::Template::TemplateToolkit;
eval { Dancer::Template::TemplateToolkit->render('/not/a/valid/file'); };
my @error_lines = split(/\n/, $@);
is(scalar(@error_lines), 1, "test non verbose croak");
- like($error_lines[0], qr!^'/not/a/valid/file' is not a regular file at!, "test non verbose croak");
+ like($error_lines[0], qr!^'/not/a/valid/file' doesn\'t exist or not a regular file at!, "test non verbose croak");
}
{
@@ -23,7 +23,7 @@ use Dancer::Template::TemplateToolkit;
eval { Dancer::Template::TemplateToolkit->render('/not/a/valid/file'); };
my @error_lines = split(/\n/, $@);
is(scalar(@error_lines), 3, "test verbose croak");
- like($error_lines[0], qr!^'/not/a/valid/file' is not a regular file at!, "test verbose croak");
+ like($error_lines[0], qr!^'/not/a/valid/file' doesn\'t exist or not a regular file at!, "test verbose croak");
like($error_lines[1], qr!^\s*Dancer::Template::TemplateToolkit::render\('Dancer::Template::TemplateToolkit', '/not/a/valid/file'\) called at!, "test verbose croak stack trace");
like($error_lines[2], qr!^\s*eval {...} called at t/01_config/06_stack_trace.t!, "test verbose croak stack trace");
}
@@ -35,17 +35,17 @@ use Dancer::Template::TemplateToolkit;
eval { Dancer::Template::TemplateToolkit->render('/not/a/valid/file'); };
my @error_lines = split(/\n/, $@);
is(scalar(@error_lines), 1, "test non verbose croak 2");
- like($error_lines[0], qr!^'/not/a/valid/file' is not a regular file at!, "test non verbose croak 2");
+ like($error_lines[0], qr!^'/not/a/valid/file' doesn\'t exist or not a regular file at!, "test non verbose croak 2");
}
{
# test setting traces to 1
- ok(setting(traces => 1));
+ ok(setting(traces => 1), 'can set traces');
is($Carp::Verbose, 1, "new Carp verbose is 1");
eval { Dancer::Template::TemplateToolkit->render('/not/a/valid/file'); };
my @error_lines = split(/\n/, $@);
is(scalar(@error_lines), 3, "test verbose croak");
- like($error_lines[0], qr!^'/not/a/valid/file' is not a regular file at!, "test verbose croak");
+ like($error_lines[0], qr!^'/not/a/valid/file' doesn\'t exist or not a regular file at!, "test verbose croak");
like($error_lines[1], qr!^\s*Dancer::Template::TemplateToolkit::render\('Dancer::Template::TemplateToolkit', '/not/a/valid/file'\) called at!, "test verbose croak stack trace");
like($error_lines[2], qr!^\s*eval {...} called at t/01_config/06_stack_trace.t!, "test verbose croak stack trace");
}
View
8 t/03_route_handler/18_auto_page.t
@@ -3,7 +3,7 @@
# takes care of rendering it.
use strict;
use warnings;
-use Test::More import => ['!pass'], tests => 4;
+use Test::More import => ['!pass'], tests => 3;
use File::Spec;
use lib File::Spec->catdir( 't', 'lib' );
@@ -23,7 +23,5 @@ my $resp = get_response_for_request('GET' => '/hello');
ok( defined($resp), "response found for /hello");
is $resp->{content}, "Hello\n", "content looks good";
Dancer::SharedData->reset_response();
-$resp = get_response_for_request('GET' => '/falsepage');
-ok( defined($resp), "response found for non existent page");
-
-is $resp->{status}, 404, "response is 404";
+eval { get_response_for_request('GET' => '/falsepage'); };
+ok $@, 'Failed to get response for nonexistent page';
View
2  t/03_route_handler/29_forward.t
@@ -33,6 +33,7 @@ response_exists [ GET => '/bounce/thesethings/' ];
response_content_is [ GET => '/bounce/thesethings/' ], 'homewithparams,thesethings';
my $expected_headers = [
+ 'Content-Length' => 4,
'Content-Type' => 'text/html',
'X-Powered-By' => "Perl Dancer ${Dancer::VERSION}",
];
@@ -52,6 +53,7 @@ response_content_is [ POST => '/' ], 'post-home';
response_exists [ POST => '/bounce/' ];
response_content_is [ POST => '/bounce/' ], 'post-home';
+$expected_headers->[1] = 9;
response_headers_are_deeply [ POST => '/bounce/' ], $expected_headers;
Dancer::Logger::logger->{fh}->close;
View
32 t/09_cookies/04_has_changed.t
@@ -1,32 +0,0 @@
-use Test::More tests => 4, import => ['!pass'];
-use strict;
-use warnings;
-use Dancer::Request;
-use Dancer::SharedData;
-
-# the request with a cookie string
-my $env = {
- REQUEST_METHOD => 'GET',
- SCRIPT_NAME => '/',
- COOKIE => 'test_cookie=42',
-};
-my $request = Dancer::Request->new($env);
-Dancer::SharedData->request($request);
-
-# testing
-use Dancer::Cookies;
-ok(Dancer::Cookies->init, "Dancer::Cookies->init");
-
-is_deeply(Dancer::Cookies->cookies, {
- test_cookie => bless {
- name => 'test_cookie',
- value => [42],
- path => '/'}, 'Dancer::Cookie'},
- "cookies look good");
-
-ok(! Dancer::Cookies->has_changed({name => 'test_cookie', value => 42}),
- "cookie did not change");
-
-ok(Dancer::Cookies->has_changed({name => 'test_cookie', value => 43}),
- "cookie changed");
-
View
2  t/10_template/05_template_toolkit.t
@@ -67,7 +67,7 @@ $expected = "one=1, two=2, three=3";
$template = "one=<% one %>, two=<% two %>, three=<% three %>";
eval { $engine->render($template, { one => 1, two => 2, three => 3}) };
-like $@, qr/is not a regular file/, "prorotype failure detected";
+like $@, qr/doesn't exist or not a regular file/, "prorotype failure detected";
$result = $engine->render(\$template, { one => 1, two => 2, three => 3});
is $result, $expected, "processed a template given as a scalar ref";
View
7 t/12_response/01_CRLF_injection.t
@@ -14,15 +14,16 @@ my $r =
my $res = Dancer::Handler::Standalone->render_response($r);
is_deeply(
$res->[1],
- [ 'Location' => "http://good.com\r\n Location: http://evil.com", ],
+ [ 'Location' => "http://good.com\r\n Location: http://evil.com", 'Content-Length' => 0,],
"CRLF injections are not allowed... a space is added to make the second line an RFC-compliant continuation line."
);
$r = Dancer::Response->new(
headers => [
- a => "foo\nevil body",
+ 'Content-Length' => 0,
+ a => "foo\nevil body",
]
);
$res = Dancer::Handler::Standalone->render_response($r);
-is $res->[1]->[1], "foo\r\n evil body";
+is $res->[1]->[3], "foo\r\n evil body";
View
12 t/12_response/03_charset.t
@@ -15,7 +15,7 @@ my $res = Dancer::Response->new(headers => [ 'Content-Type' => 'text/html' ], co
my $psgi_res = Dancer::Handler->render_response($res);
is(@$psgi_res, 3);
is($psgi_res->[0], 200, 'default status');
-is_deeply($psgi_res->[1], [ 'Content-Type' => 'text/html' ], 'default headers');
+is_deeply($psgi_res->[1], [ 'Content-Length', 0, 'Content-Type' => 'text/html' ], 'default headers');
is_deeply($psgi_res->[2], [''], 'default content');
ok $res->content_type('text/plain');
@@ -24,7 +24,7 @@ ok $res->content('123');
is_deeply(Dancer::Handler->render_response($res),
[
200,
- [ 'Content-Type', 'text/plain' ],
+ [ 'Content-Length', 0, 'Content-Type', 'text/plain' ],
[ '123' ],
],
);
@@ -34,7 +34,7 @@ setting charset => 'utf-8';
is_deeply(Dancer::Handler->render_response($res),
[
200,
- [ 'Content-Type', 'text/plain; charset=utf-8' ],
+ [ 'Content-Length', 0, 'Content-Type', 'text/plain; charset=utf-8' ],
[ '123' ],
],
);
@@ -44,7 +44,7 @@ ok $res->content("\x{0429}"); # cyrillic shcha -- way beyond latin1
is_deeply(Dancer::Handler->render_response(Dancer::Serializer->process_response($res)),
[
200,
- [ 'Content-Type', 'text/plain; charset=utf-8' ],
+ [ 'Content-Length', 0, 'Content-Type', 'text/plain; charset=utf-8' ],
[ Encode::encode('utf-8', "\x{0429}") ],
],
);
@@ -60,7 +60,7 @@ SKIP: {
is_deeply(Dancer::Handler->render_response(Dancer::Serializer->process_response($res)),
[
200,
- [ 'Content-Type', 'application/json; charset=utf-8' ],
+ [ 'Content-Length', 0, 'Content-Type', 'application/json; charset=utf-8' ],
[ JSON::to_json({ key => 'value' }) ],
],
);
@@ -81,7 +81,7 @@ SKIP: {
is_deeply(Dancer::Handler->render_response(Dancer::Serializer->process_response($res)),
[
200,
- [ 'Content-Type', 'text/xml; charset=utf-8' ],
+ [ 'Content-Length', 0, 'Content-Type', 'text/xml; charset=utf-8' ],
[ Encode::encode('utf-8', XML::Simple::XMLout( { key => "\x{0429}"
}, RootName => 'data' )) ],
],
View
59 t/12_response/07_cookies.t
@@ -1,34 +1,41 @@
+package main;
use strict;
use warnings;
+use Test::More tests => 4, import => ['!pass'];
-use Test::More import => ['!pass'];
-use File::Spec;
-use lib File::Spec->catdir( 't', 'lib' );
-use TestUtils;
+{
+ use Dancer;
+ get '/set_one_cookie' => sub {
+ set_cookie "a" => "b";
+ };
+ get '/set_two_cookies' => sub {
+ set_cookie "a" => "b";
+ set_cookie "c" => "d";
+ };
+}
-use Dancer ':syntax';
+use Dancer::Test;
-get '/onecookie', sub {
- set_cookie 'A'=> "thevalueofA";
- return '';
-};
-get '/twocookies', sub {
- set_cookie 'A'=> "thevalueofA";
- set_cookie 'B'=> "thevalueofB";
- return '';
-};
+{
+ note "Testing one cookie";
+ my $req = [GET => '/set_one_cookie'];
+ route_exists $req;
+ response_headers_are_deeply $req, [
+ 'Content-Type' => 'text/html',
+ 'Set-Cookie' => 'a=b; path=/; HttpOnly'
+ ];
+}
+{
+ note "Testing two cookies";
+ my $req = [GET => '/set_two_cookies'];
+ route_exists $req;
+ response_headers_are_deeply $req, [
+ 'Content-Type' => 'text/html',
+ 'Set-Cookie' => 'a=b; path=/; HttpOnly',
+ 'Set-Cookie' => 'c=d; path=/; HttpOnly',
+ ];
+}
-plan tests => 2;
+1;
-# /onecookie
-my $req = fake_request(GET => '/onecookie');
-Dancer::SharedData->request($req);
-my $headers = Dancer::Renderer::render_action();
-is($headers->header('Set-Cookie'), 'A=thevalueofA; path=/; HttpOnly');
-
-# /twocookies
-$req = fake_request(GET => '/twocookies');
-Dancer::SharedData->request($req);
-$headers = Dancer::Renderer::render_action();
-is($headers->header('Set-Cookie'), 'A=thevalueofA; path=/; HttpOnly, B=thevalueofB; path=/; HttpOnly');
View
52 t/12_response/08_drop_content.t
@@ -0,0 +1,52 @@
+use strict;
+use warnings;
+use Test::More import => ['!pass'];
+use LWP::UserAgent;
+
+BEGIN {
+ use Dancer::ModuleLoader;
+ plan skip_all => 'Test::TCP is needed to run this test'
+ unless Dancer::ModuleLoader->load('Test::TCP');
+}
+
+plan tests => 4;
+
+use Dancer ':syntax';
+use Dancer::Test;
+
+test();
+
+sub test {
+ Test::TCP::test_tcp(
+ client => sub {
+ my $port = shift;
+ my $url = "http://127.0.0.1:$port/";
+
+ my $ua = LWP::UserAgent->new;
+ for (qw/204 304/) {
+ my $req = HTTP::Request->new( GET => $url . $_ );
+ my $res = $ua->request($req);
+ ok !$res->content, 'no content for '.$_;
+ ok !$res->header('Content-Length'), 'no content-length for '.$_;
+ }
+ },
+ server => sub {
+ my $port = shift;
+ setting port => $port;
+ setting access_log => 0;
+
+ get '/204' => sub {
+ status 204;
+ return 'foo'
+ };
+ get '/304' => sub {
+ status 304;
+ return 'foo'
+ };
+
+ Dancer->dance();
+ },
+ );
+}
+
+
View
22 t/12_response/09_headers_to_array.t
@@ -0,0 +1,22 @@
+package main;
+use strict;
+use warnings;
+use Test::More tests => 1, import => ['!pass'];
+
+{
+
+ use Dancer;
+ get '/' => sub {
+ push_header A => 1;
+ push_header A => 2;
+ push_header B => 3;
+ };
+
+}
+
+use Dancer::Test;
+
+response_headers_are_deeply [GET => '/'],
+ [ 'Content-Type' => 'text/html', 'A' => 1, 'A' => 2, 'B' => 3];
+
+1;
View
23 t/14_serializer/16_bug_gh_299.t
@@ -0,0 +1,23 @@
+use strict;
+use warnings;
+
+use Test::More import => ['!pass'];
+
+plan skip_all => "JSON is needed to run this tests"
+ unless Dancer::ModuleLoader->load('JSON');
+plan tests => 5;
+
+use Dancer ':syntax';
+use Dancer::Test;
+
+set serializer => 'JSON';
+get '/' => sub{ { a => 1, b => 2, c => 3 } };
+
+for my $method (qw/GET HEAD/) {
+ my $response = dancer_response($method => '/');
+ is $response->status, 200, "status is 200 for $method";
+ is $response->header('Content-Type'), 'application/json', "content_type is ok for $method";
+}
+
+my $response = dancer_response(HEAD => '/');
+ok !$response->content;
View
10 t/20_deprecation/01_api.t
@@ -9,7 +9,7 @@ use Test::More tests => 10;
use Dancer::Deprecation;
sub foo {
- Dancer::Deprecation::deprecated(
+ Dancer::Deprecation->deprecated(
feature => 'foo',
version => '0.1',
message => 'calling foo is deprecated, you should use bar',
@@ -17,23 +17,23 @@ use Test::More tests => 10;
}
sub bar {
- Dancer::Deprecation::deprecated(
+ Dancer::Deprecation->deprecated(
'calling bar is also deprecated, you should use baz');
}
sub baz {
- Dancer::Deprecation::deprecated();
+ Dancer::Deprecation->deprecated();
}
sub foo_bar_baz {
- Dancer::Deprecation::deprecated(
+ Dancer::Deprecation->deprecated(
version => '0.1',
feature => 'foo_bar_baz',
);
}
sub fatal {
- Dancer::Deprecation::deprecated(
+ Dancer::Deprecation->deprecated(
message => 'this should die',
fatal => 1,
);
Please sign in to comment.
Something went wrong with that request. Please try again.