The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.
Build.PL 13
Changes 017
MANIFEST 034
META.json 5960
META.yml 5960
Makefile.PL 24
lib/Dancer2/CLI/Command/gen.pm 22
lib/Dancer2/CLI/Command/version.pm 22
lib/Dancer2/CLI.pm 22
lib/Dancer2/Config.pod 22
lib/Dancer2/Cookbook.pod 22
lib/Dancer2/Core/App.pm 3159
lib/Dancer2/Core/Cookie.pm 22
lib/Dancer2/Core/DSL.pm 24
lib/Dancer2/Core/Dispatcher.pm 23
lib/Dancer2/Core/Error.pm 22
lib/Dancer2/Core/Factory.pm 53
lib/Dancer2/Core/HTTP.pm 22
lib/Dancer2/Core/Hook.pm 22
lib/Dancer2/Core/MIME.pm 22
lib/Dancer2/Core/Request/Upload.pm 22
lib/Dancer2/Core/Request.pm 22
lib/Dancer2/Core/Response.pm 333
lib/Dancer2/Core/Role/ConfigReader.pm 22
lib/Dancer2/Core/Role/DSL.pm 22
lib/Dancer2/Core/Role/Engine.pm 311
lib/Dancer2/Core/Role/Handler.pm 22
lib/Dancer2/Core/Role/HasLocation.pm 22
lib/Dancer2/Core/Role/Headers.pm 22
lib/Dancer2/Core/Role/Hookable.pm 22
lib/Dancer2/Core/Role/Logger.pm 33
lib/Dancer2/Core/Role/Serializer.pm 22
lib/Dancer2/Core/Role/SessionFactory/File.pm 22
lib/Dancer2/Core/Role/SessionFactory.pm 22
lib/Dancer2/Core/Role/StandardResponses.pm 22
lib/Dancer2/Core/Role/Template.pm 1313
lib/Dancer2/Core/Route.pm 22
lib/Dancer2/Core/Runner.pm 22
lib/Dancer2/Core/Session.pm 22
lib/Dancer2/Core/Time.pm 22
lib/Dancer2/Core/Types.pm 22
lib/Dancer2/Core.pm 22
lib/Dancer2/FileUtils.pm 22
lib/Dancer2/Handler/AutoPage.pm 33
lib/Dancer2/Handler/File.pm 22
lib/Dancer2/Logger/Capture/Trap.pm 22
lib/Dancer2/Logger/Capture.pm 22
lib/Dancer2/Logger/Console.pm 22
lib/Dancer2/Logger/Diag.pm 22
lib/Dancer2/Logger/File.pm 22
lib/Dancer2/Logger/Note.pm 22
lib/Dancer2/Logger/Null.pm 22
lib/Dancer2/Manual/Migration.pod 25
lib/Dancer2/Manual.pod 223
lib/Dancer2/Plugin/Ajax.pm 22
lib/Dancer2/Plugin.pm 22
lib/Dancer2/Plugins.pod 22
lib/Dancer2/Policy.pod 0119
lib/Dancer2/Serializer/Dumper.pm 22
lib/Dancer2/Serializer/JSON.pm 22
lib/Dancer2/Serializer/Mutable.pm 54
lib/Dancer2/Serializer/YAML.pm 22
lib/Dancer2/Session/Simple.pm 22
lib/Dancer2/Session/YAML.pm 22
lib/Dancer2/Template/Implementation/ForkedTiny.pm 22
lib/Dancer2/Template/Simple.pm 22
lib/Dancer2/Template/TemplateToolkit.pm 22
lib/Dancer2/Template/Tiny.pm 22
lib/Dancer2/Test.pm 22
lib/Dancer2/Tutorial.pod 22
lib/Dancer2.pm 22
script/dancer2 11
t/00-report-prereqs.dd 01
t/author-no-tabs.t 034
t/classes/Dancer2/import.t 0248
t/classes/Dancer2-Core/camelize.t 024
t/classes/Dancer2-Core-Factory/create.t 017
t/classes/Dancer2-Core-Hook/base.t 070
t/classes/Dancer2-Core-Response/new_from.t 080
t/classes/Dancer2-Core-Role-Engine/base.t 022
t/classes/Dancer2-Core-Role-Handler/base.t 021
t/classes/Dancer2-Core-Role-HasLocation/FakeDancerDir/bin/.exists 00
t/classes/Dancer2-Core-Role-HasLocation/FakeDancerDir/lib/fake/inner/dir/.exists 00
t/classes/Dancer2-Core-Role-HasLocation/FakeDancerFile/.dancer 00
t/classes/Dancer2-Core-Role-HasLocation/FakeDancerFile/fakescript.pl 00
t/classes/Dancer2-Core-Role-HasLocation/base.t 090
t/classes/Dancer2-Core-Role-StandardResponses/base.t 0171
t/classes/Dancer2-Core-Runner/base.t 0246
t/classes/Dancer2-Core-Runner/environment.t 038
t/classes/Dancer2-Core-Runner/psgi_app.t 092
t/dsl/content.t 077
t/issues/gh-723.t 057
t/session_hooks.t 111
t/sessions/VDf4nIP4n0A4Ya5vcE7SaaDntyVZj9oB.yml 02
t/sessions/VDfsgXhalKhiOdSVDEk4iwyf_j3JJ1lU.yml 02
t/sessions/VDgFcPJynjsERU0GCt8fE9hhT-R3ErKV.yml 02
t/sessions/VDgH-lQYfi_XUNztQLT-6ebJ_gzwGZKp.yml 02
t/sessions/VDgHth9A4cXrh0fLlBodXUMnCXkcPlOO.yml 02
t/sessions/VDsBvbCel9L5vqAA8X12v_IKYwpqtEIb.yml 02
t/sessions/VDsC67174msADj1P2kEtWWWWqenpf_Gh.yml 02
t/sessions/VDsdec7YkN_t5HYgYTY4UTO0rGbd3quL.yml 02
t/sessions/VDskH-mTqVSrtI7vn3Cfjc22M3sDZ4nf.yml 02
t/sessions/VDxpkwmXPxXgntfDkSbIJIW3-ZmOV6F2.yml 02
t/sessions/VDxr8vlFwjuihF5Oq6qfdcX_C-sqJFst.yml 02
t/sessions/VDxsUBz1JAMQos-edO9ShtnKnIqjRugy.yml 02
t/sessions/VDxszUJNZJrCm2146wLcBL4Tauj5tlx3.yml 02
t/sessions/VDxtWd3557qlVPhU5y4QeEnoTzopT4XL.yml 02
t/sessions/VDxuf7UcBT5V58xfDyZ2akeLCE0stVRe.yml 02
108 files changed (This is a version diff) 3011895
@@ -20,7 +20,7 @@ my %module_build_args = (
     "Dancer Core Developers"
   ],
   "dist_name" => "Dancer2",
-  "dist_version" => "0.151000",
+  "dist_version" => "0.152000",
   "license" => "perl",
   "module_name" => "Dancer2",
   "recommends" => {
@@ -112,6 +112,7 @@ my %module_build_args = (
     "IO::Handle" => 0,
     "IPC::Open3" => 0,
     "LWP::Protocol::PSGI" => "0.06",
+    "Plack::Response" => 0,
     "Plack::Test" => 0,
     "Test::Fatal" => 0,
     "Test::Memory::Cycle" => "1.04",
@@ -141,6 +142,7 @@ my %fallback_build_requires = (
   "IPC::Open3" => 0,
   "LWP::Protocol::PSGI" => "0.06",
   "Module::Build" => "0.3601",
+  "Plack::Response" => 0,
   "Plack::Test" => 0,
   "Test::Fatal" => 0,
   "Test::Memory::Cycle" => "1.04",
@@ -1,3 +1,20 @@
+0.152000  2014-10-14 04:30:59+02:00 Europe/Amsterdam
+
+    [ BUG FIXES ]
+    * GH #723: Redispatched requests lose data. (Sawyer X)
+
+    [ ENHANCEMENT ]
+    * Provide 'content' keyword to set the response content. (Sawyer x)
+    * GH #616, #155, #615: Session engines are now lazy! (Russell Jenkins)
+    * Dancer2 response objects can be created from arrays or from
+      Plack::Response objects. (Sawyer X)
+    * GH #718: Clean up App's Template engine. (Russell Jenkins)
+    * Adding class-based tests. (Sawyer X)
+
+    [ DOCUMENTATION ]
+    * Add a policy document under Dancer2::Policy. (Sawyer X)
+    * Document log_format instead of logger_format. (Sawyer X)
+
 0.151000  2014-10-08 21:49:06+02:00 Europe/Amsterdam
 
     [ ENHANCEMENT ]
@@ -62,6 +62,7 @@ lib/Dancer2/Manual/Migration.pod
 lib/Dancer2/Plugin.pm
 lib/Dancer2/Plugin/Ajax.pm
 lib/Dancer2/Plugins.pod
+lib/Dancer2/Policy.pod
 lib/Dancer2/Serializer/Dumper.pm
 lib/Dancer2/Serializer/JSON.pm
 lib/Dancer2/Serializer/Mutable.pm
@@ -114,8 +115,24 @@ t/author-no-tabs.t
 t/auto_page.t
 t/caller.t
 t/charset_server.t
+t/classes/Dancer2-Core-Factory/create.t
+t/classes/Dancer2-Core-Hook/base.t
+t/classes/Dancer2-Core-Response/new_from.t
+t/classes/Dancer2-Core-Role-Engine/base.t
+t/classes/Dancer2-Core-Role-Handler/base.t
+t/classes/Dancer2-Core-Role-HasLocation/FakeDancerDir/bin/.exists
 t/classes/Dancer2-Core-Role-HasLocation/FakeDancerDir/blib/bin/.exists
 t/classes/Dancer2-Core-Role-HasLocation/FakeDancerDir/blib/lib/fakescript.pl
+t/classes/Dancer2-Core-Role-HasLocation/FakeDancerDir/lib/fake/inner/dir/.exists
+t/classes/Dancer2-Core-Role-HasLocation/FakeDancerFile/.dancer
+t/classes/Dancer2-Core-Role-HasLocation/FakeDancerFile/fakescript.pl
+t/classes/Dancer2-Core-Role-HasLocation/base.t
+t/classes/Dancer2-Core-Role-StandardResponses/base.t
+t/classes/Dancer2-Core-Runner/base.t
+t/classes/Dancer2-Core-Runner/environment.t
+t/classes/Dancer2-Core-Runner/psgi_app.t
+t/classes/Dancer2-Core/camelize.t
+t/classes/Dancer2/import.t
 t/config.yml
 t/config/config.yml
 t/config/environments/failure.yml
@@ -138,6 +155,7 @@ t/dancer-test/config.yml
 t/deserialize.t
 t/dispatcher.t
 t/dsl.t
+t/dsl/content.t
 t/dsl/extend.t
 t/dsl/extend_config/config.yml
 t/dsl/halt.t
@@ -155,6 +173,7 @@ t/handler_file.t
 t/hooks.t
 t/http_methods.t
 t/http_status.t
+t/issues/gh-723.t
 t/lib/App1.pm
 t/lib/App2.pm
 t/lib/DancerPlugin.pm
@@ -210,6 +229,21 @@ t/session_lifecycle.t
 t/session_object.t
 t/sessions/VBzn5-yKiV0ZEaZqEtEvK_pmMT8n4QQx.yml
 t/sessions/VDKr30YvCd7R3WEniUv5Re5999E6SJmQ.yml
+t/sessions/VDf4nIP4n0A4Ya5vcE7SaaDntyVZj9oB.yml
+t/sessions/VDfsgXhalKhiOdSVDEk4iwyf_j3JJ1lU.yml
+t/sessions/VDgFcPJynjsERU0GCt8fE9hhT-R3ErKV.yml
+t/sessions/VDgH-lQYfi_XUNztQLT-6ebJ_gzwGZKp.yml
+t/sessions/VDgHth9A4cXrh0fLlBodXUMnCXkcPlOO.yml
+t/sessions/VDsBvbCel9L5vqAA8X12v_IKYwpqtEIb.yml
+t/sessions/VDsC67174msADj1P2kEtWWWWqenpf_Gh.yml
+t/sessions/VDsdec7YkN_t5HYgYTY4UTO0rGbd3quL.yml
+t/sessions/VDskH-mTqVSrtI7vn3Cfjc22M3sDZ4nf.yml
+t/sessions/VDxpkwmXPxXgntfDkSbIJIW3-ZmOV6F2.yml
+t/sessions/VDxr8vlFwjuihF5Oq6qfdcX_C-sqJFst.yml
+t/sessions/VDxsUBz1JAMQos-edO9ShtnKnIqjRugy.yml
+t/sessions/VDxszUJNZJrCm2146wLcBL4Tauj5tlx3.yml
+t/sessions/VDxtWd3557qlVPhU5y4QeEnoTzopT4XL.yml
+t/sessions/VDxuf7UcBT5V58xfDyZ2akeLCE0stVRe.yml
 t/shared_engines.t
 t/splat.t
 t/template.t
@@ -127,6 +127,7 @@
             "IO::Handle" : "0",
             "IPC::Open3" : "0",
             "LWP::Protocol::PSGI" : "0.06",
+            "Plack::Response" : "0",
             "Plack::Test" : "0",
             "Test::Fatal" : "0",
             "Test::Memory::Cycle" : "1.04",
@@ -145,235 +146,235 @@
    "provides" : {
       "Dancer2" : {
          "file" : "lib/Dancer2.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::CLI" : {
          "file" : "lib/Dancer2/CLI.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::CLI::Command::gen" : {
          "file" : "lib/Dancer2/CLI/Command/gen.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::CLI::Command::version" : {
          "file" : "lib/Dancer2/CLI/Command/version.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core" : {
          "file" : "lib/Dancer2/Core.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::App" : {
          "file" : "lib/Dancer2/Core/App.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Cookie" : {
          "file" : "lib/Dancer2/Core/Cookie.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::DSL" : {
          "file" : "lib/Dancer2/Core/DSL.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Dispatcher" : {
          "file" : "lib/Dancer2/Core/Dispatcher.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Error" : {
          "file" : "lib/Dancer2/Core/Error.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Factory" : {
          "file" : "lib/Dancer2/Core/Factory.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::HTTP" : {
          "file" : "lib/Dancer2/Core/HTTP.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Hook" : {
          "file" : "lib/Dancer2/Core/Hook.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::MIME" : {
          "file" : "lib/Dancer2/Core/MIME.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Request" : {
          "file" : "lib/Dancer2/Core/Request.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Request::Upload" : {
          "file" : "lib/Dancer2/Core/Request/Upload.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Response" : {
          "file" : "lib/Dancer2/Core/Response.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Role::ConfigReader" : {
          "file" : "lib/Dancer2/Core/Role/ConfigReader.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Role::DSL" : {
          "file" : "lib/Dancer2/Core/Role/DSL.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Role::Engine" : {
          "file" : "lib/Dancer2/Core/Role/Engine.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Role::Handler" : {
          "file" : "lib/Dancer2/Core/Role/Handler.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Role::HasLocation" : {
          "file" : "lib/Dancer2/Core/Role/HasLocation.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Role::Headers" : {
          "file" : "lib/Dancer2/Core/Role/Headers.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Role::Hookable" : {
          "file" : "lib/Dancer2/Core/Role/Hookable.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Role::Logger" : {
          "file" : "lib/Dancer2/Core/Role/Logger.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Role::Serializer" : {
          "file" : "lib/Dancer2/Core/Role/Serializer.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Role::SessionFactory" : {
          "file" : "lib/Dancer2/Core/Role/SessionFactory.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Role::SessionFactory::File" : {
          "file" : "lib/Dancer2/Core/Role/SessionFactory/File.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Role::StandardResponses" : {
          "file" : "lib/Dancer2/Core/Role/StandardResponses.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Role::Template" : {
          "file" : "lib/Dancer2/Core/Role/Template.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Route" : {
          "file" : "lib/Dancer2/Core/Route.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Runner" : {
          "file" : "lib/Dancer2/Core/Runner.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Session" : {
          "file" : "lib/Dancer2/Core/Session.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Time" : {
          "file" : "lib/Dancer2/Core/Time.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Core::Types" : {
          "file" : "lib/Dancer2/Core/Types.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::FileUtils" : {
          "file" : "lib/Dancer2/FileUtils.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Handler::AutoPage" : {
          "file" : "lib/Dancer2/Handler/AutoPage.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Handler::File" : {
          "file" : "lib/Dancer2/Handler/File.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Logger::Capture" : {
          "file" : "lib/Dancer2/Logger/Capture.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Logger::Capture::Trap" : {
          "file" : "lib/Dancer2/Logger/Capture/Trap.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Logger::Console" : {
          "file" : "lib/Dancer2/Logger/Console.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Logger::Diag" : {
          "file" : "lib/Dancer2/Logger/Diag.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Logger::File" : {
          "file" : "lib/Dancer2/Logger/File.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Logger::Note" : {
          "file" : "lib/Dancer2/Logger/Note.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Logger::Null" : {
          "file" : "lib/Dancer2/Logger/Null.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Plugin" : {
          "file" : "lib/Dancer2/Plugin.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Plugin::Ajax" : {
          "file" : "lib/Dancer2/Plugin/Ajax.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Serializer::Dumper" : {
          "file" : "lib/Dancer2/Serializer/Dumper.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Serializer::JSON" : {
          "file" : "lib/Dancer2/Serializer/JSON.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Serializer::Mutable" : {
          "file" : "lib/Dancer2/Serializer/Mutable.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Serializer::YAML" : {
          "file" : "lib/Dancer2/Serializer/YAML.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Session::Simple" : {
          "file" : "lib/Dancer2/Session/Simple.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Session::YAML" : {
          "file" : "lib/Dancer2/Session/YAML.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Template::Implementation::ForkedTiny" : {
          "file" : "lib/Dancer2/Template/Implementation/ForkedTiny.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Template::Simple" : {
          "file" : "lib/Dancer2/Template/Simple.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Template::TemplateToolkit" : {
          "file" : "lib/Dancer2/Template/TemplateToolkit.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Template::Tiny" : {
          "file" : "lib/Dancer2/Template/Tiny.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       },
       "Dancer2::Test" : {
          "file" : "lib/Dancer2/Test.pm",
-         "version" : "0.151000"
+         "version" : "0.152000"
       }
    },
    "release_status" : "stable",
@@ -390,6 +391,6 @@
       "x_IRC" : "irc://irc.perl.org/#dancer",
       "x_WebIRC" : "https://chat.mibbit.com/#dancer@irc.perl.org"
    },
-   "version" : "0.151000"
+   "version" : "0.152000"
 }
 
@@ -15,6 +15,7 @@ build_requires:
   IPC::Open3: 0
   LWP::Protocol::PSGI: 0.06
   Module::Build: 0.3601
+  Plack::Response: 0
   Plack::Test: 0
   Test::Fatal: 0
   Test::Memory::Cycle: 1.04
@@ -41,178 +42,178 @@ name: Dancer2
 provides:
   Dancer2:
     file: lib/Dancer2.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::CLI:
     file: lib/Dancer2/CLI.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::CLI::Command::gen:
     file: lib/Dancer2/CLI/Command/gen.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::CLI::Command::version:
     file: lib/Dancer2/CLI/Command/version.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core:
     file: lib/Dancer2/Core.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::App:
     file: lib/Dancer2/Core/App.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Cookie:
     file: lib/Dancer2/Core/Cookie.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::DSL:
     file: lib/Dancer2/Core/DSL.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Dispatcher:
     file: lib/Dancer2/Core/Dispatcher.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Error:
     file: lib/Dancer2/Core/Error.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Factory:
     file: lib/Dancer2/Core/Factory.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::HTTP:
     file: lib/Dancer2/Core/HTTP.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Hook:
     file: lib/Dancer2/Core/Hook.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::MIME:
     file: lib/Dancer2/Core/MIME.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Request:
     file: lib/Dancer2/Core/Request.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Request::Upload:
     file: lib/Dancer2/Core/Request/Upload.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Response:
     file: lib/Dancer2/Core/Response.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Role::ConfigReader:
     file: lib/Dancer2/Core/Role/ConfigReader.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Role::DSL:
     file: lib/Dancer2/Core/Role/DSL.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Role::Engine:
     file: lib/Dancer2/Core/Role/Engine.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Role::Handler:
     file: lib/Dancer2/Core/Role/Handler.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Role::HasLocation:
     file: lib/Dancer2/Core/Role/HasLocation.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Role::Headers:
     file: lib/Dancer2/Core/Role/Headers.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Role::Hookable:
     file: lib/Dancer2/Core/Role/Hookable.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Role::Logger:
     file: lib/Dancer2/Core/Role/Logger.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Role::Serializer:
     file: lib/Dancer2/Core/Role/Serializer.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Role::SessionFactory:
     file: lib/Dancer2/Core/Role/SessionFactory.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Role::SessionFactory::File:
     file: lib/Dancer2/Core/Role/SessionFactory/File.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Role::StandardResponses:
     file: lib/Dancer2/Core/Role/StandardResponses.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Role::Template:
     file: lib/Dancer2/Core/Role/Template.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Route:
     file: lib/Dancer2/Core/Route.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Runner:
     file: lib/Dancer2/Core/Runner.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Session:
     file: lib/Dancer2/Core/Session.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Time:
     file: lib/Dancer2/Core/Time.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Core::Types:
     file: lib/Dancer2/Core/Types.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::FileUtils:
     file: lib/Dancer2/FileUtils.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Handler::AutoPage:
     file: lib/Dancer2/Handler/AutoPage.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Handler::File:
     file: lib/Dancer2/Handler/File.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Logger::Capture:
     file: lib/Dancer2/Logger/Capture.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Logger::Capture::Trap:
     file: lib/Dancer2/Logger/Capture/Trap.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Logger::Console:
     file: lib/Dancer2/Logger/Console.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Logger::Diag:
     file: lib/Dancer2/Logger/Diag.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Logger::File:
     file: lib/Dancer2/Logger/File.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Logger::Note:
     file: lib/Dancer2/Logger/Note.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Logger::Null:
     file: lib/Dancer2/Logger/Null.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Plugin:
     file: lib/Dancer2/Plugin.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Plugin::Ajax:
     file: lib/Dancer2/Plugin/Ajax.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Serializer::Dumper:
     file: lib/Dancer2/Serializer/Dumper.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Serializer::JSON:
     file: lib/Dancer2/Serializer/JSON.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Serializer::Mutable:
     file: lib/Dancer2/Serializer/Mutable.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Serializer::YAML:
     file: lib/Dancer2/Serializer/YAML.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Session::Simple:
     file: lib/Dancer2/Session/Simple.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Session::YAML:
     file: lib/Dancer2/Session/YAML.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Template::Implementation::ForkedTiny:
     file: lib/Dancer2/Template/Implementation/ForkedTiny.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Template::Simple:
     file: lib/Dancer2/Template/Simple.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Template::TemplateToolkit:
     file: lib/Dancer2/Template/TemplateToolkit.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Template::Tiny:
     file: lib/Dancer2/Template/Tiny.pm
-    version: 0.151000
+    version: 0.152000
   Dancer2::Test:
     file: lib/Dancer2/Test.pm
-    version: 0.151000
+    version: 0.152000
 recommends:
   CGI::Deurl::XS: 0
   Crypt::URandom: 0
@@ -287,4 +288,4 @@ resources:
   bugtracker: https://github.com/PerlDancer/Dancer2/issues
   homepage: http://perldancer.org/
   repository: https://github.com/PerlDancer/Dancer2
-version: 0.151000
+version: 0.152000
@@ -99,6 +99,7 @@ my %WriteMakefileArgs = (
     "IO::Handle" => 0,
     "IPC::Open3" => 0,
     "LWP::Protocol::PSGI" => "0.06",
+    "Plack::Response" => 0,
     "Plack::Test" => 0,
     "Test::Fatal" => 0,
     "Test::Memory::Cycle" => "1.04",
@@ -111,9 +112,9 @@ my %WriteMakefileArgs = (
     "utf8" => 0,
     "vars" => 0
   },
-  "VERSION" => "0.151000",
+  "VERSION" => "0.152000",
   "test" => {
-    "TESTS" => "t/*.t t/dsl/*.t t/logger/*.t t/roles/*.t t/route-pod-coverage/*.t t/template_tiny/*.t"
+    "TESTS" => "t/*.t t/classes/Dancer2-Core-Factory/*.t t/classes/Dancer2-Core-Hook/*.t t/classes/Dancer2-Core-Response/*.t t/classes/Dancer2-Core-Role-Engine/*.t t/classes/Dancer2-Core-Role-Handler/*.t t/classes/Dancer2-Core-Role-HasLocation/*.t t/classes/Dancer2-Core-Role-StandardResponses/*.t t/classes/Dancer2-Core-Runner/*.t t/classes/Dancer2-Core/*.t t/classes/Dancer2/*.t t/dsl/*.t t/issues/*.t t/logger/*.t t/roles/*.t t/route-pod-coverage/*.t t/template_tiny/*.t"
   }
 );
 
@@ -165,6 +166,7 @@ my %FallbackPrereqs = (
   "POSIX" => 0,
   "Plack" => "1.0016",
   "Plack::Builder" => 0,
+  "Plack::Response" => 0,
   "Plack::Test" => 0,
   "Pod::Simple::Search" => 0,
   "Pod::Simple::SimpleTree" => 0,
@@ -1,6 +1,6 @@
 # ABSTRACT: create new Dancer2 application
 package Dancer2::CLI::Command::gen;
-$Dancer2::CLI::Command::gen::VERSION = '0.151000';
+$Dancer2::CLI::Command::gen::VERSION = '0.152000';
 use strict;
 use warnings;
 
@@ -279,7 +279,7 @@ Dancer2::CLI::Command::gen - create new Dancer2 application
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 AUTHOR
 
@@ -1,6 +1,6 @@
 package Dancer2::CLI::Command::version;
 # ABSTRACT: display version
-$Dancer2::CLI::Command::version::VERSION = '0.151000';
+$Dancer2::CLI::Command::version::VERSION = '0.152000';
 use App::Cmd::Setup -command;
 
 sub description { 'Display version of Dancer2' }
@@ -29,7 +29,7 @@ Dancer2::CLI::Command::version - display version
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 AUTHOR
 
@@ -1,6 +1,6 @@
 package Dancer2::CLI;
 # ABSTRACT: Dancer2 cli application
-$Dancer2::CLI::VERSION = '0.151000';
+$Dancer2::CLI::VERSION = '0.152000';
 use App::Cmd::Setup -app;
 
 1;
@@ -17,7 +17,7 @@ Dancer2::CLI - Dancer2 cli application
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 AUTHOR
 
@@ -1,6 +1,6 @@
 package Dancer2::Config;
 # ABSTRACT: Configure Dancer2 to suit your needs
-$Dancer2::Config::VERSION = '0.151000';
+$Dancer2::Config::VERSION = '0.152000';
 __END__
 
 =pod
@@ -13,7 +13,7 @@ Dancer2::Config - Configure Dancer2 to suit your needs
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Cookbook;
 # ABSTRACT: Example-driven quick-start to the Dancer2 web framework
-$Dancer2::Cookbook::VERSION = '0.151000';
+$Dancer2::Cookbook::VERSION = '0.152000';
 __END__
 
 =pod
@@ -13,7 +13,7 @@ Dancer2::Cookbook - Example-driven quick-start to the Dancer2 web framework
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 # ABSTRACT: encapsulation of Dancer2 packages
 package Dancer2::Core::App;
-$Dancer2::Core::App::VERSION = '0.151000';
+$Dancer2::Core::App::VERSION = '0.152000';
 use Moo;
 use Carp               'croak';
 use Scalar::Util       'blessed';
@@ -17,7 +17,7 @@ use Dancer2::Core::Types;
 use Dancer2::Core::Route;
 use Dancer2::Core::Hook;
 use Dancer2::Core::Request;
-
+use Dancer2::Core::Factory;
 
 # we have hooks here
 with 'Dancer2::Core::Role::Hookable';
@@ -25,6 +25,13 @@ with 'Dancer2::Core::Role::ConfigReader';
 
 sub supported_engines { [ qw<logger serializer session template> ] }
 
+has _factory => (
+    is      => 'ro',
+    isa     => Object['Dancer2::Core::Factory'],
+    lazy    => 1,
+    default => sub { Dancer2::Core::Factory->new },
+);
+
 has logger_engine => (
     is      => 'ro',
     isa     => Maybe[ConsumerOf['Dancer2::Core::Role::Logger']],
@@ -126,7 +133,7 @@ sub _build_logger_engine {
     my $engine_options =
         $self->_get_config_for_engine( logger => $value, $config );
 
-    my $logger = Dancer2::Core::Factory->create(
+    my $logger = $self->_factory->create(
         logger => $value,
         %{$engine_options},
         app_name        => $self->name,
@@ -154,7 +161,7 @@ sub _build_session_engine {
     my $engine_options =
           $self->_get_config_for_engine( session => $value, $config );
 
-    return Dancer2::Core::Factory->create(
+    return $self->_factory->create(
         session => $value,
         %{$engine_options},
         postponed_hooks => $self->get_postponed_hooks,
@@ -183,7 +190,7 @@ sub _build_template_engine {
     $engine_attrs->{views}  ||= $config->{views}
         || path( $self->location, 'views' );
 
-    return Dancer2::Core::Factory->create(
+    return $self->_factory->create(
         template => $value,
         %{$engine_attrs},
         postponed_hooks => $self->get_postponed_hooks,
@@ -204,7 +211,7 @@ sub _build_serializer_engine {
     my $engine_options =
         $self->_get_config_for_engine( serializer => $value, $config );
 
-    return Dancer2::Core::Factory->create(
+    return $self->_factory->create(
         serializer      => $value,
         config          => $engine_options,
         postponed_hooks => $self->get_postponed_hooks,
@@ -518,10 +525,23 @@ sub _init_hooks {
                 # session, first flush the session so cookie-based sessions can
                 # update the session ID if needed, then set the session cookie
                 # in the response
+                #
+                # if there is NO session object but the request has a cookie with
+                # a session key, create a dummy session with the same ID (without
+                # actually retrieving and flushing immediately) and generate the
+                # cookie header from the dummy session. Lazy Sessions FTW!
 
                 if ( $app->has_session ) {
-                    my $session = $app->session;
-                    $session->is_dirty and $engine->flush( session => $session );
+                    my $session;
+                    if ( $app->_has_session ) { # Session object exists
+                        $session = $app->session;
+                        $session->is_dirty and $engine->flush( session => $session );
+                    }
+                    else { # Cookie header exists. Create a dummy session object
+                        my $cookie = $app->cookie( $engine->cookie_name );
+                        my $session_id = $cookie->value;
+                        $session = Dancer2::Core::Session->new( id => $session_id );
+                    }
                     $engine->set_cookie_header(
                         response => $response,
                         session  => $session
@@ -575,6 +595,13 @@ sub cleanup {
     $self->clear_response;
     $self->clear_session;
     $self->clear_destroyed_session;
+    # Clear engine attributes
+    for my $type ( @{ $self->supported_engines } ) {
+        my $attr   = "${type}_engine";
+        my $engine = $self->$attr or next;
+        $engine->has_session && $engine->clear_session;
+        $engine->has_request && $engine->clear_request;
+    }
 }
 
 sub engine {
@@ -595,7 +622,7 @@ sub template {
     $template->set_settings( $self->config );
 
     # return content
-    return $template->process( $self->request, @_ );
+    return $template->process( @_ );
 }
 
 sub hook_candidates {
@@ -675,7 +702,7 @@ sub send_file {
     # pretending it's a file (on-the-fly file sending)
     ref $path eq 'SCALAR' and return $$path;
 
-    my $file_handler = Dancer2::Core::Factory->create(
+    my $file_handler = $self->_factory->create(
         Handler => 'File',
         app     => $self,
         postponed_hooks => $self->postponed_hooks,
@@ -718,7 +745,7 @@ sub init_route_handlers {
         my ($handler_name, $config) = @{$handler_data};
         $config = {} if !ref($config);
 
-        my $handler = Dancer2::Core::Factory->create(
+        my $handler = $self->_factory->create(
             Handler => $handler_name,
             app     => $self,
             %$config,
@@ -1008,7 +1035,13 @@ DISPATCH:
 
             $request->_set_route_params($match);
 
+            # Add request to app and engines
             $self->set_request($request);
+            for my $type ( @{ $self->supported_engines } ) {
+                my $attr   = "${type}_engine";
+                my $engine = $self->$attr or next;
+                $engine->set_request( $request );
+            }
 
             # Add session to app *if* we have a session and the request
             # has the appropriate cookie header for _this_ app.
@@ -1072,6 +1105,10 @@ DISPATCH:
                     and delete $request->{_params}{splat};
 
                 $response->has_passed(0); # clear for the next round
+
+                # clear the content because if you pass it,
+                # the next route is in charge of catching it
+                $response->clear_content;
                 next ROUTE;
             }
 
@@ -1091,7 +1128,13 @@ DISPATCH:
 
     # make sure Core::Dispatcher recognizes this failure
     # so it can try the next Core::App
-    Dancer2->runner->{'internal_404'} = 1;
+    # and set the created request so we don't create it again
+    # (this is important so we don't ignore the previous body)
+    if ( Dancer2->runner->{'internal_dispatch'} ) {
+        Dancer2->runner->{'internal_404'}     = 1;
+        Dancer2->runner->{'internal_request'} = $request;
+    }
+
     return $self->response_not_found($request);
 }
 
@@ -1106,15 +1149,6 @@ sub build_request {
         ( serializer      => $engine )x!! $engine,
     );
 
-    # if it's a mutable serializer, we add more headers
-    # so it can be set properly
-    # I don't like doing this... -- Sawyer
-    if ( $engine->$_isa('Dancer2::Serializer::Mutable') ) {
-        $engine->{'extra_headers'} = {
-            map +( $_ => $request->$_ ), qw<content_type accept accept_type>
-        }
-    }
-
     # Log deserialization errors
     if ($engine) {
         $engine->has_error and $self->log(
@@ -1130,9 +1164,6 @@ sub build_request {
 sub _dispatch_route {
     my ( $self, $route ) = @_;
 
-    # FIXME: check for memory leak here
-    # perhaps we need to weaken $self, perhaps not
-    # would it matter if we do? could it be a problem?
     $self->execute_hook( 'core.app.before_request', $self );
     my $response = $self->response;
 
@@ -1142,22 +1173,19 @@ sub _dispatch_route {
         $content = $response->content;
     }
     else {
-        # FIXME: check for memory leak here
-        # perhaps we need to weaken $self, perhaps not
-        # would it matter if we do? could it be a problem?
         $content = eval { $route->execute($self) };
 
         my $error = $@;
         if ($error) {
             $self->log( error => "Route exception: $error" );
-            # FIXME: check for memory leak here
-            # perhaps we need to weaken $self, perhaps not
-            # would it matter if we do? could it be a problem?
             $self->execute_hook( 'core.app.route_exception', $self, $error );
             return $self->response_internal_error($error);
         }
     }
 
+    $response->has_content
+        and $content = $response->content;
+
     if ( ref $content eq 'Dancer2::Core::Response' ) {
         $response = $self->set_response($content);
     }
@@ -1219,7 +1247,7 @@ Dancer2::Core::App - encapsulation of Dancer2 packages
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Core::Cookie;
 # ABSTRACT: A cookie representing class
-$Dancer2::Core::Cookie::VERSION = '0.151000';
+$Dancer2::Core::Cookie::VERSION = '0.152000';
 use Moo;
 use URI::Escape;
 use Dancer2::Core::Types;
@@ -106,7 +106,7 @@ Dancer2::Core::Cookie - A cookie representing class
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 SYNOPSIS
 
@@ -1,7 +1,7 @@
 # ABSTRACT: Dancer2's Domain Specific Language (DSL)
 
 package Dancer2::Core::DSL;
-$Dancer2::Core::DSL::VERSION = '0.151000';
+$Dancer2::Core::DSL::VERSION = '0.152000';
 use Moo;
 use Carp;
 use Class::Load 'load_class';
@@ -20,6 +20,7 @@ sub dsl_keywords {
         app                  => { is_global => 1 },
         captures             => { is_global => 0 },
         config               => { is_global => 1 },
+        content              => { is_global => 0 },
         content_type         => { is_global => 0 },
         context              => { is_global => 0 },
         cookie               => { is_global => 0 },
@@ -291,6 +292,7 @@ sub status       { shift->response->status(@_) }
 sub push_header  { shift->response->push_header(@_) }
 sub header       { shift->response->header(@_) }
 sub headers      { shift->response->header(@_) }
+sub content      { shift->response->content(@_) }
 sub content_type { shift->response->content_type(@_) }
 sub pass         { shift->app->pass }
 
@@ -415,7 +417,7 @@ Dancer2::Core::DSL - Dancer2's Domain Specific Language (DSL)
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 FUNCTIONS
 
@@ -1,6 +1,6 @@
 package Dancer2::Core::Dispatcher;
 # ABSTRACT: Class for dispatching request to the appropriate route handler
-$Dancer2::Core::Dispatcher::VERSION = '0.151000';
+$Dancer2::Core::Dispatcher::VERSION = '0.152000';
 use Moo;
 
 use Dancer2::Core::Types;
@@ -46,6 +46,7 @@ sub dispatch {
         }
 
         # don't run anymore
+        delete Dancer2->runner->{'internal_request'};
         last;
     } # while
 
@@ -69,7 +70,7 @@ Dancer2::Core::Dispatcher - Class for dispatching request to the appropriate rou
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 SYNOPSIS
 
@@ -1,6 +1,6 @@
 package Dancer2::Core::Error;
 # ABSTRACT: Class representing fatal errors
-$Dancer2::Core::Error::VERSION = '0.151000';
+$Dancer2::Core::Error::VERSION = '0.152000';
 use Moo;
 use Carp;
 use Dancer2::Core::Types;
@@ -488,7 +488,7 @@ Dancer2::Core::Error - Class representing fatal errors
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 SYNOPSIS
 
@@ -1,9 +1,7 @@
 package Dancer2::Core::Factory;
 # ABSTRACT: Instantiate components by type and name
-$Dancer2::Core::Factory::VERSION = '0.151000';
-use strict;
-use warnings;
-
+$Dancer2::Core::Factory::VERSION = '0.152000';
+use Moo;
 use Dancer2::Core;
 use Class::Load 'try_load_class';
 use Carp 'croak';
@@ -35,7 +33,7 @@ Dancer2::Core::Factory - Instantiate components by type and name
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 AUTHOR
 
@@ -1,7 +1,7 @@
 # ABSTRACT: helper for rendering HTTP status codes for Dancer2
 
 package Dancer2::Core::HTTP;
-$Dancer2::Core::HTTP::VERSION = '0.151000';
+$Dancer2::Core::HTTP::VERSION = '0.152000';
 use strict;
 use warnings;
 
@@ -134,7 +134,7 @@ Dancer2::Core::HTTP - helper for rendering HTTP status codes for Dancer2
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 FUNCTIONS
 
@@ -1,6 +1,6 @@
 package Dancer2::Core::Hook;
 # ABSTRACT: Manipulate hooks with Dancer2
-$Dancer2::Core::Hook::VERSION = '0.151000';
+$Dancer2::Core::Hook::VERSION = '0.152000';
 use Moo;
 use Dancer2::Core::Types;
 use Carp;
@@ -51,7 +51,7 @@ Dancer2::Core::Hook - Manipulate hooks with Dancer2
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 SYNOPSIS
 
@@ -1,7 +1,7 @@
 # ABSTRACT: Class to ease manipulation of MIME types
 
 package Dancer2::Core::MIME;
-$Dancer2::Core::MIME::VERSION = '0.151000';
+$Dancer2::Core::MIME::VERSION = '0.152000';
 use Moo;
 
 use MIME::Types;
@@ -90,7 +90,7 @@ Dancer2::Core::MIME - Class to ease manipulation of MIME types
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 SYNOPSIS
 
@@ -1,6 +1,6 @@
 package Dancer2::Core::Request::Upload;
 # ABSTRACT: Class representing file upload requests
-$Dancer2::Core::Request::Upload::VERSION = '0.151000';
+$Dancer2::Core::Request::Upload::VERSION = '0.152000';
 use Moo;
 
 use Carp;
@@ -91,7 +91,7 @@ Dancer2::Core::Request::Upload - Class representing file upload requests
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,5 +1,5 @@
 package Dancer2::Core::Request;
-$Dancer2::Core::Request::VERSION = '0.151000';
+$Dancer2::Core::Request::VERSION = '0.152000';
 # ABSTRACT: Interface for accessing incoming requests
 
 use Moo;
@@ -714,7 +714,7 @@ Dancer2::Core::Request - Interface for accessing incoming requests
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 SYNOPSIS
 
@@ -1,7 +1,7 @@
 # ABSTRACT: Response object for Dancer2
 
 package Dancer2::Core::Response;
-$Dancer2::Core::Response::VERSION = '0.151000';
+$Dancer2::Core::Response::VERSION = '0.152000';
 use Moo;
 
 use Encode;
@@ -69,7 +69,6 @@ has status => (
 has content => (
     is      => 'rw',
     isa     => Str,
-    default => sub {''},
     coerce  => sub {
         my $value = shift;
         return "$value";
@@ -82,6 +81,9 @@ has content => (
         $self->has_passed or $self->header( 'Content-Length' => length($value) );
         return $value;
     },
+
+    predicate => 'has_content',
+    clearer   => 'clear_content',
 );
 
 before content => sub {
@@ -118,6 +120,26 @@ sub encode_content {
     return $content;
 }
 
+sub new_from_plack {
+    my ($self, $psgi_res) = @_;
+
+    return Dancer2::Core::Response->new(
+        status  => $psgi_res->status,
+        headers => $psgi_res->headers,
+        content => $psgi_res->body,
+    );
+}
+
+sub new_from_array {
+    my ($self, $arrayref) = @_;
+
+    return Dancer2::Core::Response->new(
+        status  => $arrayref->[0],
+        headers => $arrayref->[1],
+        content => $arrayref->[2][0],
+    );
+}
+
 sub to_psgi {
     my ($self) = @_;
     # It is possible to have no content and/or no content type set
@@ -201,7 +223,7 @@ Dancer2::Core::Response - Response object for Dancer2
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 ATTRIBUTES
 
@@ -254,6 +276,14 @@ Interally, it uses the L<is_encoded> flag to make sure that content is not encod
 If it encodes the content, then it will return the encoded content.  In all other
 cases it returns C<false>.
 
+=head2 new_from_plack
+
+Creates a new response object from a L<Plack::Response> object.
+
+=head2 new_from_array
+
+Creates a new response object from a PSGI arrayref.
+
 =head2 to_psgi
 
 Converts the response object to a PSGI array.
@@ -1,6 +1,6 @@
 # ABSTRACT: Config role for Dancer2 core objects
 package Dancer2::Core::Role::ConfigReader;
-$Dancer2::Core::Role::ConfigReader::VERSION = '0.151000';
+$Dancer2::Core::Role::ConfigReader::VERSION = '0.152000';
 use Moo::Role;
 
 use File::Spec;
@@ -274,7 +274,7 @@ Dancer2::Core::Role::ConfigReader - Config role for Dancer2 core objects
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Core::Role::DSL;
 # ABSTRACT: Role for DSL
-$Dancer2::Core::Role::DSL::VERSION = '0.151000';
+$Dancer2::Core::Role::DSL::VERSION = '0.152000';
 use Moo::Role;
 use Dancer2::Core::Types;
 use Carp 'croak';
@@ -106,7 +106,7 @@ Dancer2::Core::Role::DSL - Role for DSL
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 AUTHOR
 
@@ -1,6 +1,6 @@
 package Dancer2::Core::Role::Engine;
 # ABSTRACT: Role for engines
-$Dancer2::Core::Role::Engine::VERSION = '0.151000';
+$Dancer2::Core::Role::Engine::VERSION = '0.152000';
 use Moo::Role;
 use Dancer2::Core::Types;
 
@@ -15,11 +15,19 @@ has session => (
 );
 
 has config => (
-    is      => 'rw',
+    is      => 'ro',
     isa     => HashRef,
     default => sub { {} },
 );
 
+has request => (
+    is        => 'ro',
+    isa       => InstanceOf['Dancer2::Core::Request'],
+    writer    => 'set_request',
+    clearer   => 'clear_request',
+    predicate => 'has_request',
+);
+
 1;
 
 __END__
@@ -34,7 +42,7 @@ Dancer2::Core::Role::Engine - Role for engines
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Core::Role::Handler;
 # ABSTRACT: Role for Handlers
-$Dancer2::Core::Role::Handler::VERSION = '0.151000';
+$Dancer2::Core::Role::Handler::VERSION = '0.152000';
 use Moo::Role;
 use Dancer2::Core::Types;
 
@@ -26,7 +26,7 @@ Dancer2::Core::Role::Handler - Role for Handlers
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 ATTRIBUTES
 
@@ -1,6 +1,6 @@
 package Dancer2::Core::Role::HasLocation;
 # ABSTRACT: Role for application location "guessing"
-$Dancer2::Core::Role::HasLocation::VERSION = '0.151000';
+$Dancer2::Core::Role::HasLocation::VERSION = '0.152000';
 use Moo::Role;
 use Dancer2::Core::Types;
 use Dancer2::FileUtils;
@@ -84,7 +84,7 @@ Dancer2::Core::Role::HasLocation - Role for application location "guessing"
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 AUTHOR
 
@@ -1,7 +1,7 @@
 # ABSTRACT: Role for handling headers
 
 package Dancer2::Core::Role::Headers;
-$Dancer2::Core::Role::Headers::VERSION = '0.151000';
+$Dancer2::Core::Role::Headers::VERSION = '0.152000';
 use Moo::Role;
 use Dancer2::Core::Types;
 use HTTP::Headers;
@@ -77,7 +77,7 @@ Dancer2::Core::Role::Headers - Role for handling headers
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Core::Role::Hookable;
 # ABSTRACT: Role for hookable objects
-$Dancer2::Core::Role::Hookable::VERSION = '0.151000';
+$Dancer2::Core::Role::Hookable::VERSION = '0.152000';
 use Moo::Role;
 use Dancer2::Core;
 use Dancer2::Core::Types;
@@ -156,7 +156,7 @@ Dancer2::Core::Role::Hookable - Role for hookable objects
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 AUTHOR
 
@@ -1,6 +1,6 @@
 package Dancer2::Core::Role::Logger;
 # ABSTRACT: Role for logger engines
-$Dancer2::Core::Role::Logger::VERSION = '0.151000';
+$Dancer2::Core::Role::Logger::VERSION = '0.152000';
 use Dancer2::Core::Types;
 
 use Moo::Role;
@@ -177,7 +177,7 @@ Dancer2::Core::Role::Logger - Role for logger engines
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -302,7 +302,7 @@ You can change it either in your config.yml file:
     logger: "console"
 
 The log format can also be configured,
-please see L<Dancer2::Core::Role::Logger/"logger_format"> for details.
+please see L<Dancer2::Core::Role::Logger/"log_format"> for details.
 
 =head1 METHODS
 
@@ -1,6 +1,6 @@
 package Dancer2::Core::Role::Serializer;
 # ABSTRACT: Role for Serializer engines
-$Dancer2::Core::Role::Serializer::VERSION = '0.151000';
+$Dancer2::Core::Role::Serializer::VERSION = '0.152000';
 use Dancer2::Core::Types;
 use Moo::Role;
 
@@ -78,7 +78,7 @@ Dancer2::Core::Role::Serializer - Role for Serializer engines
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Core::Role::SessionFactory::File;
 #ABSTRACT: Role for file-based session factories
-$Dancer2::Core::Role::SessionFactory::File::VERSION = '0.151000';
+$Dancer2::Core::Role::SessionFactory::File::VERSION = '0.152000';
 use strict;
 use warnings;
 use Carp 'croak';
@@ -113,7 +113,7 @@ Dancer2::Core::Role::SessionFactory::File - Role for file-based session factorie
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Core::Role::SessionFactory;
 #ABSTRACT: Role for session factories
-$Dancer2::Core::Role::SessionFactory::VERSION = '0.151000';
+$Dancer2::Core::Role::SessionFactory::VERSION = '0.152000';
 use strict;
 use warnings;
 use Carp 'croak';
@@ -254,7 +254,7 @@ Dancer2::Core::Role::SessionFactory - Role for session factories
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Core::Role::StandardResponses;
 # ABSTRACT: Role to provide commonly used responses
-$Dancer2::Core::Role::StandardResponses::VERSION = '0.151000';
+$Dancer2::Core::Role::StandardResponses::VERSION = '0.152000';
 use Moo::Role;
 
 sub response {
@@ -39,7 +39,7 @@ Dancer2::Core::Role::StandardResponses - Role to provide commonly used responses
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 METHODS
 
@@ -1,7 +1,7 @@
 # ABSTRACT: Role for template engines
 
 package Dancer2::Core::Role::Template;
-$Dancer2::Core::Role::Template::VERSION = '0.151000';
+$Dancer2::Core::Role::Template::VERSION = '0.152000';
 use Dancer2::Core::Types;
 use Dancer2::FileUtils qw'path';
 use Carp 'croak';
@@ -101,9 +101,9 @@ sub render_layout {
 }
 
 sub apply_renderer {
-    my ( $self, $request, $view, $tokens ) = @_;
+    my ( $self, $view, $tokens ) = @_;
     $view = $self->view_pathname($view) if !ref $view;
-    $tokens = $self->_prepare_tokens_options($request,$tokens);
+    $tokens = $self->_prepare_tokens_options( $tokens );
 
     $self->execute_hook( 'engine.template.before_render', $tokens );
 
@@ -116,9 +116,9 @@ sub apply_renderer {
 }
 
 sub apply_layout {
-    my ( $self, $request, $content, $tokens, $options ) = @_;
+    my ( $self, $content, $tokens, $options ) = @_;
 
-    $tokens = $self->_prepare_tokens_options( $request, $tokens );
+    $tokens = $self->_prepare_tokens_options( $tokens );
 
    # If 'layout' was given in the options hashref, use it if it's a true value,
    # or don't use a layout if it was false (0, or undef); if layout wasn't
@@ -150,7 +150,7 @@ sub apply_layout {
 }
 
 sub _prepare_tokens_options {
-    my ( $self, $request, $tokens ) = @_;
+    my ( $self, $tokens ) = @_;
 
     # these are the default tokens provided for template processing
     $tokens ||= {};
@@ -158,9 +158,9 @@ sub _prepare_tokens_options {
     $tokens->{dancer_version} = Dancer2->VERSION;
 
     $tokens->{settings} = $self->settings;
-    $tokens->{request}  = $request;
-    $tokens->{params}   = $request->params;
-    $tokens->{vars}     = $request->vars;
+    $tokens->{request}  = $self->request;
+    $tokens->{params}   = $self->request->params;
+    $tokens->{vars}     = $self->request->vars;
 
     $tokens->{session} = $self->session->data
       if $self->has_session;
@@ -169,7 +169,7 @@ sub _prepare_tokens_options {
 }
 
 sub process {
-    my ( $self, $request, $view, $tokens, $options ) = @_;
+    my ( $self, $view, $tokens, $options ) = @_;
     my ( $content, $full_content );
 
     # it's important that $tokens is not undef, so that things added to it via
@@ -181,11 +181,11 @@ sub process {
 
     $content =
         $view
-      ? $self->apply_renderer( $request, $view, $tokens )
+      ? $self->apply_renderer( $view, $tokens )
       : delete $options->{content};
 
     defined $content
-      and $full_content = $self->apply_layout( $request, $content, $tokens, $options );
+      and $full_content = $self->apply_layout( $content, $tokens, $options );
 
     defined $full_content
       and return $full_content;
@@ -207,7 +207,7 @@ Dancer2::Core::Role::Template - Role for template engines
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,7 +1,7 @@
 # ABSTRACT: Dancer2's route handler
 
 package Dancer2::Core::Route;
-$Dancer2::Core::Route::VERSION = '0.151000';
+$Dancer2::Core::Route::VERSION = '0.152000';
 use strict;
 use warnings;
 
@@ -228,7 +228,7 @@ Dancer2::Core::Route - Dancer2's route handler
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 ATTRIBUTES
 
@@ -1,6 +1,6 @@
 package Dancer2::Core::Runner;
 # ABSTRACT: Top-layer class to start a dancer app
-$Dancer2::Core::Runner::VERSION = '0.151000';
+$Dancer2::Core::Runner::VERSION = '0.152000';
 use Moo;
 use Carp 'croak';
 use Dancer2::Core::MIME;
@@ -260,7 +260,7 @@ Dancer2::Core::Runner - Top-layer class to start a dancer app
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 AUTHOR
 
@@ -1,5 +1,5 @@
 package Dancer2::Core::Session;
-$Dancer2::Core::Session::VERSION = '0.151000';
+$Dancer2::Core::Session::VERSION = '0.152000';
 #ABSTRACT: class to represent any session object
 
 use strict;
@@ -71,7 +71,7 @@ Dancer2::Core::Session - class to represent any session object
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Core::Time;
 #ABSTRACT: class to handle common helpers for time manipulations
-$Dancer2::Core::Time::VERSION = '0.151000';
+$Dancer2::Core::Time::VERSION = '0.152000';
 use Moo;
 
 has seconds => (
@@ -134,7 +134,7 @@ Dancer2::Core::Time - class to handle common helpers for time manipulations
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 SYNOPSIS
 
@@ -1,6 +1,6 @@
 package Dancer2::Core::Types;
 # ABSTRACT: Moo types for Dancer2 core.
-$Dancer2::Core::Types::VERSION = '0.151000';
+$Dancer2::Core::Types::VERSION = '0.152000';
 use strict;
 use warnings;
 use Scalar::Util 'blessed', 'looks_like_number';
@@ -148,7 +148,7 @@ Dancer2::Core::Types - Moo types for Dancer2 core.
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Core;
 # ABSTRACT: Core libraries for Dancer2 2.0
-$Dancer2::Core::VERSION = '0.151000';
+$Dancer2::Core::VERSION = '0.152000';
 use strict;
 use warnings;
 
@@ -29,7 +29,7 @@ Dancer2::Core - Core libraries for Dancer2 2.0
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 FUNCTIONS
 
@@ -1,6 +1,6 @@
 package Dancer2::FileUtils;
 # ABSTRACT: File utility helpers
-$Dancer2::FileUtils::VERSION = '0.151000';
+$Dancer2::FileUtils::VERSION = '0.152000';
 use strict;
 use warnings;
 
@@ -101,7 +101,7 @@ Dancer2::FileUtils - File utility helpers
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 SYNOPSIS
 
@@ -1,6 +1,6 @@
 package Dancer2::Handler::AutoPage;
 # ABSTRACT: Class for handling the AutoPage feature
-$Dancer2::Handler::AutoPage::VERSION = '0.151000';
+$Dancer2::Handler::AutoPage::VERSION = '0.152000';
 use Moo;
 use Carp 'croak';
 use Dancer2::Core::Types;
@@ -40,7 +40,7 @@ sub code {
             return;
         }
 
-        my $ct = $template->process( $app->request, $page );
+        my $ct = $template->process( $page );
         $app->response->header( 'Content-Length', length($ct) );
         return ( $app->request->method eq 'GET' ) ? $ct : '';
     };
@@ -64,7 +64,7 @@ Dancer2::Handler::AutoPage - Class for handling the AutoPage feature
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Handler::File;
 # ABSTRACT: class for handling file content rendering
-$Dancer2::Handler::File::VERSION = '0.151000';
+$Dancer2::Handler::File::VERSION = '0.152000';
 use Carp 'croak';
 use Moo;
 use HTTP::Date;
@@ -147,7 +147,7 @@ Dancer2::Handler::File - class for handling file content rendering
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 AUTHOR
 
@@ -1,6 +1,6 @@
 package Dancer2::Logger::Capture::Trap;
 # ABSTRACT: a place to store captured Dancer2 logs
-$Dancer2::Logger::Capture::Trap::VERSION = '0.151000';
+$Dancer2::Logger::Capture::Trap::VERSION = '0.152000';
 use Moo;
 use Dancer2::Core::Types;
 
@@ -37,7 +37,7 @@ Dancer2::Logger::Capture::Trap - a place to store captured Dancer2 logs
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 SYNOPSIS
 
@@ -1,6 +1,6 @@
 package Dancer2::Logger::Capture;
 # ABSTRACT: Capture dancer logs
-$Dancer2::Logger::Capture::VERSION = '0.151000';
+$Dancer2::Logger::Capture::VERSION = '0.152000';
 use Moo;
 use Dancer2::Logger::Capture::Trap;
 
@@ -35,7 +35,7 @@ Dancer2::Logger::Capture - Capture dancer logs
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 SYNOPSIS
 
@@ -1,6 +1,6 @@
 package Dancer2::Logger::Console;
 # ABSTRACT: Console logger
-$Dancer2::Logger::Console::VERSION = '0.151000';
+$Dancer2::Logger::Console::VERSION = '0.152000';
 use Moo;
 
 with 'Dancer2::Core::Role::Logger';
@@ -24,7 +24,7 @@ Dancer2::Logger::Console - Console logger
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Logger::Diag;
 # ABSTRACT: Test::More diag() logging engine for Dancer2
-$Dancer2::Logger::Diag::VERSION = '0.151000';
+$Dancer2::Logger::Diag::VERSION = '0.152000';
 use Moo;
 use Test::More;
 
@@ -26,7 +26,7 @@ Dancer2::Logger::Diag - Test::More diag() logging engine for Dancer2
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Logger::File;
 # ABSTRACT: file-based logging engine for Dancer2
-$Dancer2::Logger::File::VERSION = '0.151000';
+$Dancer2::Logger::File::VERSION = '0.152000';
 use Carp 'carp';
 use Moo;
 use Dancer2::Core::Types;
@@ -114,7 +114,7 @@ Dancer2::Logger::File - file-based logging engine for Dancer2
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Logger::Note;
 # ABSTRACT: Test::More note() logging engine for Dancer2
-$Dancer2::Logger::Note::VERSION = '0.151000';
+$Dancer2::Logger::Note::VERSION = '0.152000';
 use Moo;
 use Test::More;
 
@@ -26,7 +26,7 @@ Dancer2::Logger::Note - Test::More note() logging engine for Dancer2
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Logger::Null;
 # ABSTRACT: Blackhole-like silent logging engine for Dancer2
-$Dancer2::Logger::Null::VERSION = '0.151000';
+$Dancer2::Logger::Null::VERSION = '0.152000';
 use Moo;
 with 'Dancer2::Core::Role::Logger';
 
@@ -20,7 +20,7 @@ Dancer2::Logger::Null - Blackhole-like silent logging engine for Dancer2
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Manual::Migration;
 # ABSTRACT: Migrating from Dancer to Dancer2
-$Dancer2::Manual::Migration::VERSION = '0.151000';
+$Dancer2::Manual::Migration::VERSION = '0.152000';
 use strict;
 use warnings;
 
@@ -18,7 +18,7 @@ Dancer2::Manual::Migration - Migrating from Dancer to Dancer2
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head2 Migration from Dancer1 to Dancer2
 
@@ -151,6 +151,9 @@ Other modules that could be used for testing are:
 
 =head4 Logs
 
+The C<logger_format> in the Logger role (L<Dancer2::Core::Role::Logger>)
+is now C<log_format>.
+
 C<read_logs> can no longer be used, as with L<Dancer2::Test>. Instead,
 L<Dancer2::Logger::Capture> could be used for testing, to capture all
 logs to an object.
@@ -1,6 +1,6 @@
 # ABSTRACT: A gentle introduction to Dancer2
 package Dancer2::Manual;
-$Dancer2::Manual::VERSION = '0.151000';
+$Dancer2::Manual::VERSION = '0.152000';
 __END__
 
 =pod
@@ -13,7 +13,7 @@ Dancer2::Manual - A gentle introduction to Dancer2
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -885,6 +885,23 @@ Accesses the configuration of the application:
         return "This is " . config->{appname};
     };
 
+=head2 content
+
+Sets the content for the response.
+
+    get '/' => sub {
+        content 'Hello, world!';
+
+        # the return value of the route is ignored
+        return 'Ignored String';
+    };
+
+Once you set the content using the keyword, your return value (which
+is usually the content) is ignored.
+
+B<WARNING> : If you are using the C<pass> keyword, the last route will be
+in charge of setting the content.
+
 =head2 content_type
 
 Sets the B<content-type> rendered, for the current route handler:
@@ -1181,6 +1198,10 @@ route.  So it's not necessary anymore to use C<return> with pass.
         }
     };
 
+B<WARNING> : You cannot set the content before passing and have it remain,
+even if you use the C<content> keyword or set it directly in the response
+object.
+
 =head2 patch
 
 Defines a route for HTTP B<PATCH> requests to the given URL:
@@ -1,7 +1,7 @@
 # ABSTRACT: a plugin for adding Ajax route handlers
 
 package Dancer2::Plugin::Ajax;
-$Dancer2::Plugin::Ajax::VERSION = '0.151000';
+$Dancer2::Plugin::Ajax::VERSION = '0.152000';
 use strict;
 use warnings;
 
@@ -63,7 +63,7 @@ Dancer2::Plugin::Ajax - a plugin for adding Ajax route handlers
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 SYNOPSIS
 
@@ -1,6 +1,6 @@
 package Dancer2::Plugin;
 # ABSTRACT: Extending Dancer2's DSL with plugins
-$Dancer2::Plugin::VERSION = '0.151000';
+$Dancer2::Plugin::VERSION = '0.152000';
 use Moo::Role;
 use Carp 'croak', 'carp';
 use Dancer2::Core::DSL;
@@ -251,7 +251,7 @@ Dancer2::Plugin - Extending Dancer2's DSL with plugins
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Plugins;
 # ABSTRACT: Recommended Dancer2 plugins
-$Dancer2::Plugins::VERSION = '0.151000';
+$Dancer2::Plugins::VERSION = '0.152000';
 __END__
 
 =pod
@@ -13,7 +13,7 @@ Dancer2::Plugins - Recommended Dancer2 plugins
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -0,0 +1,119 @@
+package Dancer2::Policy;
+# ABSTRACT: Dancer core and community policy and standards of conduct
+$Dancer2::Policy::VERSION = '0.152000';
+use strict;
+use warnings;
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Dancer2::Policy - Dancer core and community policy and standards of conduct
+
+=head1 VERSION
+
+version 0.152000
+
+=head1 DESCRIPTION
+
+This document describes various policies (most notably, the standards
+of conduct) for the Dancer core developers and broad community.
+
+This is what we expect from our community and ourselves and these are
+the standards of behavior we set forth in order to make sure the community
+remains a safe space for all of its members, without exception.
+
+=head1 STANDARDS OF CONDUCT
+
+These standards applies anywhere the community comes together as a group.
+This includes, but is not limited to, the Dancer IRC channel, the Dancer
+mailing list, Dancer hackathons, and Dancer conferences.
+
+=over 4
+
+=item *
+
+Always be civil.
+
+=item *
+
+Heed the moderators.
+
+=item *
+
+Abuse is not tolerated.
+
+=back
+
+Civility is simple: stick to the facts while avoiding demeaning remarks and
+sarcasm. It is not enough to be factual. You must also be civil. Responding
+in kind to incivility is not acceptable.
+
+If the list moderators tell you that you are not being civil, carefully
+consider how your words have appeared before responding in any way. You may
+protest, but repeated protest in the face of a repeatedly reaffirmed decision
+is not acceptable.
+
+Unacceptable behavior will result in a public and clearly identified warning.
+Repeated unacceptable behavior will result in removal from the mailing list and
+revocation of any commit bit. The first removal is for one month. Subsequent
+removals will double in length. After six months with no warning, a user's ban
+length is reset. Removals, like warnings, are public.
+
+The list of moderators consists of all active core developers. This includes,
+in alphabetical order, Alberto Simões, David Precious, Mickey Nasriachi,
+Russell Jenkins, Sawyer X, Stefan Hornburg (Racke), Steven Humphrey, and Yanick
+Champoux.
+
+This list might additionally grow to active members of the community who have
+stepped up to help handle abusive behavior. If this should happen, this
+document would be updated to include their names.
+
+Additionally, it's important to understand the self-regulating nature we
+foster at the Dancer community. This means anyone and everyone in the
+community - in the channel, on the list, at an event - has the ability to
+call out unacceptable behavior and incivility to others in the community.
+
+Moderators are responsibe for issuing warnings and take disciplenary actions,
+but anyone may - and is encouraged - to publicly make note of unacceptable
+treatment of others.
+
+As a core principle, abuse is never tolerated. One cannot berate, insult,
+debase, deride, put-down, or vilify anyone, or act towards anyone in a way
+intending to hurt them.
+
+The community specifically considers as abuse any attempts to otherize anyone,
+whether by their technical skill, knowledge, gender, sexual orientation,
+or any other characteristic.
+
+The community aims to maintain a safe space for everyone, in any forum it
+has. If you ever feel this core principle has been compromised, you are strongly
+urged to contact a moderator. We are always here.
+
+Remember, this is B<your> community, as much as it is anyone else's.
+
+=head1 CREDITS
+
+This policy has been adopted and adapted from the policy available for
+the Perl language development, provided by B<p5p> (the Perl 5 Porters).
+
+The original inspiration policy document can be read at L<perlpolicy>.
+
+=head1 AUTHOR
+
+Dancer Core Developers
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2014 by Alexis Sukrieh.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
@@ -1,7 +1,7 @@
 # ABSTRACT: Serializer for handling Dumper data
 
 package Dancer2::Serializer::Dumper;
-$Dancer2::Serializer::Dumper::VERSION = '0.151000';
+$Dancer2::Serializer::Dumper::VERSION = '0.152000';
 use Moo;
 use Carp 'croak';
 use Data::Dumper;
@@ -55,7 +55,7 @@ Dancer2::Serializer::Dumper - Serializer for handling Dumper data
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Serializer::JSON;
 # ABSTRACT: Serializer for handling JSON data
-$Dancer2::Serializer::JSON::VERSION = '0.151000';
+$Dancer2::Serializer::JSON::VERSION = '0.152000';
 use Moo;
 use JSON ();
 
@@ -57,7 +57,7 @@ Dancer2::Serializer::JSON - Serializer for handling JSON data
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Serializer::Mutable;
 # ABSTRACT: Serialize and deserialize content based on HTTP header
-$Dancer2::Serializer::Mutable::VERSION = '0.151000';
+$Dancer2::Serializer::Mutable::VERSION = '0.152000';
 use Moo;
 use Carp 'croak';
 use Encode;
@@ -77,13 +77,12 @@ sub deserialize {
 
 sub _get_content_type {
     my $self    = shift;
-    my $headers = $self->{'extra_headers'}
-        or return;
+    $self->has_request or return;
 
     # Search for the first HTTP header variable which
     # specifies supported content.
     foreach my $method ( qw<content_type accept accept_type> ) {
-        if ( my $value = $headers->{$method} ) {
+        if ( my $value = $self->request->header($method) ) {
             if ( exists $formats->{$value} ) {
                 $self->set_content_type($value);
                 return $formats->{$value};
@@ -109,7 +108,7 @@ Dancer2::Serializer::Mutable - Serialize and deserialize content based on HTTP h
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 SYNOPSIS
 
@@ -1,6 +1,6 @@
 package Dancer2::Serializer::YAML;
 # ABSTRACT: Serializer for handling YAML data
-$Dancer2::Serializer::YAML::VERSION = '0.151000';
+$Dancer2::Serializer::YAML::VERSION = '0.152000';
 use Moo;
 use Carp 'croak';
 use Encode;
@@ -51,7 +51,7 @@ Dancer2::Serializer::YAML - Serializer for handling YAML data
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Session::Simple;
 # ABSTRACT: in-memory session backend for Dancer2
-$Dancer2::Session::Simple::VERSION = '0.151000';
+$Dancer2::Session::Simple::VERSION = '0.152000';
 use Moo;
 use Dancer2::Core::Types;
 use Carp;
@@ -49,7 +49,7 @@ Dancer2::Session::Simple - in-memory session backend for Dancer2
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,5 +1,5 @@
 package Dancer2::Session::YAML;
-$Dancer2::Session::YAML::VERSION = '0.151000';
+$Dancer2::Session::YAML::VERSION = '0.152000';
 # ABSTRACT: YAML-file-based session backend for Dancer2
 
 use Moo;
@@ -39,7 +39,7 @@ Dancer2::Session::YAML - YAML-file-based session backend for Dancer2
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,5 +1,5 @@
 package Dancer2::Template::Implementation::ForkedTiny;
-$Dancer2::Template::Implementation::ForkedTiny::VERSION = '0.151000';
+$Dancer2::Template::Implementation::ForkedTiny::VERSION = '0.152000';
 # ABSTRACT: Dancer2 own implementation of Template::Tiny
 
 use 5.00503;
@@ -229,7 +229,7 @@ Dancer2::Template::Implementation::ForkedTiny - Dancer2 own implementation of Te
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 SYNOPSIS
 
@@ -1,6 +1,6 @@
 package Dancer2::Template::Simple;
 # ABSTRACT: Pure Perl 5 template engine for Dancer2
-$Dancer2::Template::Simple::VERSION = '0.151000';
+$Dancer2::Template::Simple::VERSION = '0.152000';
 use strict;
 use warnings;
 use Moo;
@@ -156,7 +156,7 @@ Dancer2::Template::Simple - Pure Perl 5 template engine for Dancer2
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 SYNOPSIS
 
@@ -1,7 +1,7 @@
 # ABSTRACT: Template toolkit engine for Dancer2
 
 package Dancer2::Template::TemplateToolkit;
-$Dancer2::Template::TemplateToolkit::VERSION = '0.151000';
+$Dancer2::Template::TemplateToolkit::VERSION = '0.152000';
 use strict;
 use warnings;
 use Carp qw/croak/;
@@ -63,7 +63,7 @@ Dancer2::Template::TemplateToolkit - Template toolkit engine for Dancer2
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 SYNOPSIS
 
@@ -1,6 +1,6 @@
 package Dancer2::Template::Tiny;
 # ABSTRACT: Template::Tiny engine for Dancer2
-$Dancer2::Template::Tiny::VERSION = '0.151000';
+$Dancer2::Template::Tiny::VERSION = '0.152000';
 use Moo;
 use Carp qw/croak/;
 use Dancer2::Core::Types;
@@ -50,7 +50,7 @@ Dancer2::Template::Tiny - Template::Tiny engine for Dancer2
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 SYNOPSIS
 
@@ -1,6 +1,6 @@
 package Dancer2::Test;
 # ABSTRACT: Useful routines for testing Dancer2 apps
-$Dancer2::Test::VERSION = '0.151000';
+$Dancer2::Test::VERSION = '0.152000';
 use strict;
 use warnings;
 
@@ -621,7 +621,7 @@ Dancer2::Test - Useful routines for testing Dancer2 apps
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -1,6 +1,6 @@
 package Dancer2::Tutorial;
 # ABSTRACT: An example to get you dancing
-$Dancer2::Tutorial::VERSION = '0.151000';
+$Dancer2::Tutorial::VERSION = '0.152000';
 __END__
 
 =pod
@@ -13,7 +13,7 @@ Dancer2::Tutorial - An example to get you dancing
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 What is Dancer2?
 
@@ -1,6 +1,6 @@
 package Dancer2;
 # ABSTRACT: Lightweight yet powerful web application framework
-$Dancer2::VERSION = '0.151000';
+$Dancer2::VERSION = '0.152000';
 use strict;
 use warnings;
 use List::Util  'first';
@@ -118,7 +118,7 @@ Dancer2 - Lightweight yet powerful web application framework
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 DESCRIPTION
 
@@ -33,7 +33,7 @@ dancer2 - Dancer2 command line interface
 
 =head1 VERSION
 
-version 0.151000
+version 0.152000
 
 =head1 SYNOPSIS
 
@@ -112,6 +112,7 @@ do { my $x = {
                                    'IO::Handle' => '0',
                                    'IPC::Open3' => '0',
                                    'LWP::Protocol::PSGI' => '0.06',
+                                   'Plack::Response' => '0',
                                    'Plack::Test' => '0',
                                    'Test::Fatal' => '0',
                                    'Test::Memory::Cycle' => '1.04',
@@ -67,6 +67,7 @@ my @files = (
     'lib/Dancer2/Plugin.pm',
     'lib/Dancer2/Plugin/Ajax.pm',
     'lib/Dancer2/Plugins.pod',
+    'lib/Dancer2/Policy.pod',
     'lib/Dancer2/Serializer/Dumper.pm',
     'lib/Dancer2/Serializer/JSON.pm',
     'lib/Dancer2/Serializer/Mutable.pm',
@@ -97,8 +98,24 @@ my @files = (
     't/auto_page.t',
     't/caller.t',
     't/charset_server.t',
+    't/classes/Dancer2-Core-Factory/create.t',
+    't/classes/Dancer2-Core-Hook/base.t',
+    't/classes/Dancer2-Core-Response/new_from.t',
+    't/classes/Dancer2-Core-Role-Engine/base.t',
+    't/classes/Dancer2-Core-Role-Handler/base.t',
+    't/classes/Dancer2-Core-Role-HasLocation/FakeDancerDir/bin/.exists',
     't/classes/Dancer2-Core-Role-HasLocation/FakeDancerDir/blib/bin/.exists',
     't/classes/Dancer2-Core-Role-HasLocation/FakeDancerDir/blib/lib/fakescript.pl',
+    't/classes/Dancer2-Core-Role-HasLocation/FakeDancerDir/lib/fake/inner/dir/.exists',
+    't/classes/Dancer2-Core-Role-HasLocation/FakeDancerFile/.dancer',
+    't/classes/Dancer2-Core-Role-HasLocation/FakeDancerFile/fakescript.pl',
+    't/classes/Dancer2-Core-Role-HasLocation/base.t',
+    't/classes/Dancer2-Core-Role-StandardResponses/base.t',
+    't/classes/Dancer2-Core-Runner/base.t',
+    't/classes/Dancer2-Core-Runner/environment.t',
+    't/classes/Dancer2-Core-Runner/psgi_app.t',
+    't/classes/Dancer2-Core/camelize.t',
+    't/classes/Dancer2/import.t',
     't/config.yml',
     't/config/config.yml',
     't/config/environments/failure.yml',
@@ -121,6 +138,7 @@ my @files = (
     't/deserialize.t',
     't/dispatcher.t',
     't/dsl.t',
+    't/dsl/content.t',
     't/dsl/extend.t',
     't/dsl/extend_config/config.yml',
     't/dsl/halt.t',
@@ -138,6 +156,7 @@ my @files = (
     't/hooks.t',
     't/http_methods.t',
     't/http_status.t',
+    't/issues/gh-723.t',
     't/lib/App1.pm',
     't/lib/App2.pm',
     't/lib/DancerPlugin.pm',
@@ -191,6 +210,21 @@ my @files = (
     't/session_object.t',
     't/sessions/VBzn5-yKiV0ZEaZqEtEvK_pmMT8n4QQx.yml',
     't/sessions/VDKr30YvCd7R3WEniUv5Re5999E6SJmQ.yml',
+    't/sessions/VDf4nIP4n0A4Ya5vcE7SaaDntyVZj9oB.yml',
+    't/sessions/VDfsgXhalKhiOdSVDEk4iwyf_j3JJ1lU.yml',
+    't/sessions/VDgFcPJynjsERU0GCt8fE9hhT-R3ErKV.yml',
+    't/sessions/VDgH-lQYfi_XUNztQLT-6ebJ_gzwGZKp.yml',
+    't/sessions/VDgHth9A4cXrh0fLlBodXUMnCXkcPlOO.yml',
+    't/sessions/VDsBvbCel9L5vqAA8X12v_IKYwpqtEIb.yml',
+    't/sessions/VDsC67174msADj1P2kEtWWWWqenpf_Gh.yml',
+    't/sessions/VDsdec7YkN_t5HYgYTY4UTO0rGbd3quL.yml',
+    't/sessions/VDskH-mTqVSrtI7vn3Cfjc22M3sDZ4nf.yml',
+    't/sessions/VDxpkwmXPxXgntfDkSbIJIW3-ZmOV6F2.yml',
+    't/sessions/VDxr8vlFwjuihF5Oq6qfdcX_C-sqJFst.yml',
+    't/sessions/VDxsUBz1JAMQos-edO9ShtnKnIqjRugy.yml',
+    't/sessions/VDxszUJNZJrCm2146wLcBL4Tauj5tlx3.yml',
+    't/sessions/VDxtWd3557qlVPhU5y4QeEnoTzopT4XL.yml',
+    't/sessions/VDxuf7UcBT5V58xfDyZ2akeLCE0stVRe.yml',
     't/shared_engines.t',
     't/splat.t',
     't/template.t',
@@ -0,0 +1,248 @@
+#!perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 31;
+use Test::Fatal;
+use Scalar::Util 'refaddr';
+use Plack::Test;
+use HTTP::Request::Common;
+
+BEGIN {
+    require Dancer2;
+    can_ok( Dancer2::, 'runner' );
+    is( Dancer2::->runner, undef, 'No runner by default' );
+}
+
+{
+    package App::CreatingRunner;
+    use Dancer2;
+}
+
+isa_ok( Dancer2->runner, 'Dancer2::Core::Runner', 'Runner created' );
+my $runner_refaddr = refaddr( Dancer2->runner );
+
+{
+    package App::NotRecreatingRunner;
+    use Dancer2;
+}
+
+isa_ok( Dancer2->runner, 'Dancer2::Core::Runner', 'Runner created' );
+is( refaddr( Dancer2->runner ), $runner_refaddr, 'Runner not recreated' );
+
+{
+    {
+        package FakeRunner;
+        sub psgi_app {
+            ::isa_ok( $_[0], 'FakeRunner' );
+            ::is( $_[1], 'psgi_param', 'psgi_app calls Runner->psgi_app' );
+            return 'Got it';
+        }
+    }
+
+    local $Dancer2::runner = bless {}, 'FakeRunner';
+    ::is(
+        Dancer2->psgi_app('psgi_param'),
+        'Got it',
+        'psgi_app works as expected',
+    );
+}
+
+{
+    package App::ScriptAllowed;
+    require Dancer2;
+
+    ::is(
+        ::exception { Dancer2->import(':script') },
+        undef,
+        ':script is allowed',
+    );
+}
+
+{
+    package App::SyntaxAllowed;
+    require Dancer2;
+
+    ::is(
+        ::exception { Dancer2->import(':syntax') },
+        undef,
+        ':syntax is allowed',
+    );
+}
+
+{
+    package App::KeyPairOnly;
+    require Dancer2;
+
+    ::like(
+        ::exception { Dancer2->import('single') },
+        qr{^parameters must be key/value pairs},
+        'Must import key/value pairs',
+    );
+
+    ::like(
+        ::exception { Dancer2->import(qw<three items requested>) },
+        qr{^parameters must be key/value pairs},
+        'Must import key/value pairs',
+    );
+
+    ::is(
+        ::exception { Dancer2->import( '!unless' ) },
+        undef,
+        'Must import key/value pairs unless prefixed by !',
+    );
+
+    ::is(
+        ::exception { Dancer2->import( '!unless', '!prefixed', '!bythis' ) },
+        undef,
+        'Must import key/value pairs unless prefixed by !',
+    );
+}
+
+{
+    package App::GettingDSL;
+    use Dancer2;
+
+    ::can_ok( __PACKAGE__, qw<get post> );
+}
+
+{
+    package App::GettingSelectiveDSL;
+    use Dancer2 '!post';
+
+    # proper way
+    ::can_ok( __PACKAGE__, 'get' );
+
+    # checking this would work too
+    ::ok( __PACKAGE__->can('get'), 'get imported successfully' );
+    ::ok( ! __PACKAGE__->can('post'), 'Can import keywords selectively' );
+}
+
+{
+    package App::Main;
+    use Dancer2;
+    get '/main' => sub {1};
+}
+
+{
+    package App::ComposedToMain;
+    use Dancer2 appname => 'App::Main';
+    get '/alsomain' => sub {1};
+}
+
+{
+    my $runner = Dancer2->runner;
+    isa_ok( $runner, 'Dancer2::Core::Runner' );
+    my $apps = $runner->apps;
+
+    ok( scalar @{$apps} == 10, 'Correct number of Apps created so far' );
+
+    my @names = sort map +( $_->name ), @{$apps};
+
+    # this is the list of all Apps loaded in this test
+    is_deeply(
+        \@names,
+        [qw<
+            App::CreatingRunner
+            App::GettingDSL
+            App::GettingSelectiveDSL
+            App::KeyPairOnly
+            App::Main
+            App::NotRecreatingRunner
+            App::ScriptAllowed
+            App::StrictAndWarningsAndUTF8
+            App::SyntaxAllowed
+            App::WithSettingsChanged
+        >],
+        'All apps accounted for',
+    );
+
+    my $app = App::Main->to_app;
+    isa_ok( $app, 'CODE' );
+    test_psgi $app, sub {
+        my $cb = shift;
+        is(
+            $cb->( GET '/main' )->content,
+            1,
+            'Got original app response',
+        );
+
+        is(
+            $cb->( GET '/alsomain' )->content,
+            1,
+            'Can compose apps with appname',
+        );
+    };
+}
+
+{
+    package App::WithSettingsChanged;
+    use Dancer2;
+}
+
+{
+    App::WithSettingsChanged->import( with => { layout => 'mobile' } );
+
+    my ($app) = grep +( $_->name eq 'App::WithSettingsChanged' ),
+        @{ Dancer2->runner->{'apps'} };
+
+    ::isa_ok( $app, 'Dancer2::Core::App' );
+    ::is(
+        $app->template_engine->{'layout'},
+        'mobile',
+        'Changed settings using with keyword',
+    );
+}
+
+{
+    package NoStrictNoWarningsNoUTF8;
+    no strict;
+    no warnings;
+    no utf8;
+
+    local $@ = undef;
+
+    eval '$var = 30';
+
+    ::is(
+        $@,
+        '',
+        'no strict (control test)',
+    );
+
+    local $SIG{'__WARN__'} = sub {
+        ::is(
+            $_[0],
+            undef,
+            'no warning (control test)',
+        );
+    };
+
+    eval 'my $var; my $var;';
+}
+
+{
+    package App::StrictAndWarningsAndUTF8;
+    use Dancer2;
+
+    local $@ = undef;
+
+    local $SIG{'__WARN__'} = sub {
+        ::ok(
+            $_[0],
+            'warnings pragma imported',
+        );
+    };
+
+    eval '$var = 30;';
+
+    ::like(
+        $@,
+        qr/^Global symbol/,
+        'strict pragma imported',
+    );
+
+    eval 'my $var; my $var;';
+}
+
@@ -0,0 +1,24 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use Dancer2::Core;
+use Test::More tests => 4;
+
+my %tests = (
+    'test'       => 'Test',
+    'class_name' => 'ClassName',
+    'class_nAME' => 'ClassNAME',
+    'class_NAME' => 'ClassNAME',
+);
+
+foreach my $test ( keys %tests ) {
+    my $value = $tests{$test};
+
+    is(
+        Dancer2::Core::camelize($test),
+        $value,
+        "$test camelized as $value",
+    );
+}
+
@@ -0,0 +1,17 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use Test::More tests => 4;
+use Dancer2::Core::Factory;
+
+my $factory = Dancer2::Core::Factory->new;
+isa_ok( $factory, 'Dancer2::Core::Factory' );
+can_ok( $factory, 'create' );
+
+my $template = Dancer2::Core::Factory->create(
+    'template', 'template_toolkit', layout => 'mylayout'
+);
+
+isa_ok( $template, 'Dancer2::Template::TemplateToolkit' );
+is( $template->{'layout'}, 'mylayout', 'Correct layout set in the template' );
@@ -0,0 +1,70 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use Test::More tests => 11;
+use Test::Fatal;
+use Dancer2::Core::Hook;
+
+like(
+    exception { Dancer2::Core::Hook->new( name => 'myname' ) },
+    qr/^Missing required arguments: code/,
+    'Must provide code attribute',
+);
+
+like(
+    exception { Dancer2::Core::Hook->new( code => sub {1} ) },
+    qr/^Missing required arguments: name/,
+    'Must provide name attribute',
+);
+
+is(
+    exception {
+        Dancer2::Core::Hook->new( name => 'myname', code => sub {1} )
+    },
+    undef,
+    'Can create hook with name and code',
+);
+
+{
+    my $hook = Dancer2::Core::Hook->new(
+        name => 'before_template',
+        code => sub {
+            my $input = shift;
+            ::is( $input, 'input', 'Correct input for hook' );
+            return 'output';
+        },
+    );
+
+    isa_ok( $hook, 'Dancer2::Core::Hook' );
+    can_ok( $hook, qw<name code> );
+
+    is(
+        $hook->name,
+        'before_template_render',
+        'before_template becomes before_template_render',
+    );
+
+    isa_ok( $hook->code, 'CODE' );
+
+    is(
+        $hook->code->('input'),
+        'output',
+        'Hook returned proper output',
+    );
+}
+
+{
+    my $hook = Dancer2::Core::Hook->new(
+        name => 'CrashingHook',
+        code => sub { die 'dying' },
+    );
+
+    isa_ok( $hook, 'Dancer2::Core::Hook' );
+
+    like(
+        exception { $hook->code->() },
+        qr/^Hook error: dying/,
+        'Hook crashing caught',
+    );
+}
@@ -0,0 +1,80 @@
+#!perl
+
+use strict;
+use warnings;
+use Test::More tests => 3;
+
+use Plack::Response;
+use Dancer2::Core::Response;
+
+sub normalize_headers {
+    my $headers = shift;
+
+    my %headers = ();
+    while ( my ( $key, $val ) = splice @{$headers}, 0, 2 ) {
+        $headers{$key} = $val;
+    }
+
+    return %headers;
+}
+
+can_ok( Dancer2::Core::Response::, qw<new_from_array new_from_plack> );
+
+my %default_headers = (
+    'Content-Type' => 'text/plain',
+    'X-Test'       => 'Val',
+);
+
+subtest 'new_from_array' => sub {
+    plan tests => 4;
+
+    my $array    = [ 200, [%default_headers], ['Foo'] ];
+    my $response = Dancer2::Core::Response->new_from_array($array);
+
+    isa_ok( $response, 'Dancer2::Core::Response' );
+    is( $response->status,  200,   'Correct status' );
+    is( $response->content, 'Foo', 'Correct content' );
+
+    # hash randomization
+    my %headers = normalize_headers( $response->headers_to_array );
+
+    is_deeply(
+        \%headers,
+        {
+            'Server' => "Perl Dancer2 $Dancer2::VERSION",
+            %default_headers,
+        },
+        'All headers correct',
+    );
+};
+
+subtest 'new_from_plack' => sub {
+    plan tests => 5;
+
+    my $plack = Plack::Response->new();
+    isa_ok( $plack, 'Plack::Response' );
+
+    $plack->status(200);
+    $plack->body('Bar');
+    foreach my $header_name ( keys %default_headers ) {
+        $plack->header( $header_name => $default_headers{$header_name} );
+    }
+
+    my $response = Dancer2::Core::Response->new_from_plack($plack);
+    isa_ok( $response, 'Dancer2::Core::Response' );
+    is( $response->status,  200,   'Correct status' );
+    is( $response->content, 'Bar', 'Correct content' );
+
+    # hash randomization
+    my %headers = normalize_headers( $response->headers_to_array );
+
+    is_deeply(
+        \%headers,
+        {
+            'Server' => "Perl Dancer2 $Dancer2::VERSION",
+            %default_headers,
+        },
+        'All headers correct',
+    );
+};
+
@@ -0,0 +1,22 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use Test::More tests => 4;
+
+{
+    package App;
+    use Moo;
+    with 'Dancer2::Core::Role::Engine';
+    sub supported_hooks {}
+}
+
+my $app = App->new;
+isa_ok( $app, 'App' );
+can_ok( $app, qw<session config> ); # attributes
+can_ok( $app, qw<set_session clear_session has_session> ); # methods
+ok(
+    $app->DOES('Dancer2::Core::Role::Hookable'),
+    'App consumes Dancer2::Core::Role::Hookable',
+);
+
@@ -0,0 +1,21 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use Test::More tests => 3;
+
+{
+    package Handler;
+    use Moo;
+    with 'Dancer2::Core::Role::Handler';
+    sub register {}
+}
+
+my $handler = Handler->new;
+isa_ok( $handler, 'Handler' );
+can_ok( $handler, qw<app>   ); # attributes
+ok(
+    $handler->DOES('Dancer2::Core::Role::Handler'),
+    'Handler consumes Dancer2::Core::Role::Handler',
+);
+
diff --git a/var/tmp/source/XSAWYERX/Dancer2-0.152000/Dancer2-0.152000/t/classes/Dancer2-Core-Role-HasLocation/FakeDancerDir/bin/.exists b/var/tmp/source/XSAWYERX/Dancer2-0.152000/Dancer2-0.152000/t/classes/Dancer2-Core-Role-HasLocation/FakeDancerDir/bin/.exists
new file mode 100644
index 00000000..e69de29b
diff --git a/var/tmp/source/XSAWYERX/Dancer2-0.152000/Dancer2-0.152000/t/classes/Dancer2-Core-Role-HasLocation/FakeDancerDir/lib/fake/inner/dir/.exists b/var/tmp/source/XSAWYERX/Dancer2-0.152000/Dancer2-0.152000/t/classes/Dancer2-Core-Role-HasLocation/FakeDancerDir/lib/fake/inner/dir/.exists
new file mode 100644
index 00000000..e69de29b
diff --git a/var/tmp/source/XSAWYERX/Dancer2-0.152000/Dancer2-0.152000/t/classes/Dancer2-Core-Role-HasLocation/FakeDancerFile/.dancer b/var/tmp/source/XSAWYERX/Dancer2-0.152000/Dancer2-0.152000/t/classes/Dancer2-Core-Role-HasLocation/FakeDancerFile/.dancer
new file mode 100644
index 00000000..e69de29b
diff --git a/var/tmp/source/XSAWYERX/Dancer2-0.152000/Dancer2-0.152000/t/classes/Dancer2-Core-Role-HasLocation/FakeDancerFile/fakescript.pl b/var/tmp/source/XSAWYERX/Dancer2-0.152000/Dancer2-0.152000/t/classes/Dancer2-Core-Role-HasLocation/FakeDancerFile/fakescript.pl
new file mode 100644
index 00000000..e69de29b
@@ -0,0 +1,90 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use File::Spec;
+use File::Basename;
+use Test::More tests => 11;
+
+{
+    package App;
+    use Moo;
+    with 'Dancer2::Core::Role::HasLocation';
+}
+
+note 'Defaults:'; {
+    my $app = App->new();
+    isa_ok( $app, 'App' );
+    can_ok( $app, qw<caller location> ); # attributes
+    can_ok( $app, '_build_location'   ); # methods
+
+    ok(
+        $app->DOES('Dancer2::Core::Role::HasLocation'),
+        'App consumes Dancer2::Core::Role::HasLocation',
+    );
+
+    is(
+        $app->caller,
+        't/classes/Dancer2-Core-Role-HasLocation/base.t',
+        'Default caller',
+    );
+}
+
+my $basedir = dirname( File::Spec->rel2abs(__FILE__) );
+
+note 'With lib/ and bin/:'; {
+    my $app = App->new(
+        caller => File::Spec->catfile(
+            $basedir, qw<FakeDancerDir fake inner dir fakescript.pl>
+        )
+    );
+
+    isa_ok( $app, 'App' );
+
+    my $location = $app->location;
+    $location =~ s/$basedir//;
+
+    is(
+        $location,
+        '/FakeDancerDir/',
+        'Got correct location with lib/ and bin/',
+    );
+}
+
+note 'With .dancer file:'; {
+    my $app = App->new(
+        caller => File::Spec->catfile(
+            $basedir, qw<FakeDancerFile script.pl>
+        )
+    );
+
+    isa_ok( $app, 'App' );
+
+    my $location = $app->location;
+    $location =~ s/$basedir//;
+
+    is(
+        $location,
+        '/FakeDancerFile',
+        'Got correct location with .dancer file',
+    );
+}
+
+note 'blib/ ignored:'; {
+    my $app = App->new(
+        caller => File::Spec->catfile(
+            $basedir, qw<FakeDancerDir blib lib fakescript.pl>
+        )
+    );
+
+    isa_ok( $app, 'App' );
+
+    my $location = $app->location;
+    $location =~ s/$basedir//;
+
+    is(
+        $location,
+        '/FakeDancerDir/',
+        'blib/ dir is ignored',
+    );
+}
@@ -0,0 +1,171 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use Test::More tests => 36;
+
+{
+    package Handler;
+    use Moo;
+    with 'Dancer2::Core::Role::StandardResponses';
+}
+
+{
+    package App;
+    use Moo;
+    has response => ( is => 'ro', default => sub { Response->new } );
+}
+
+{
+    package Response;
+    use Moo;
+    sub status { shift->{'status'}->(@_) }
+    sub header { shift->{'header'}->(@_) }
+}
+
+note 'Checking our fake app'; {
+    my $app = App->new;
+    isa_ok( $app, 'App'      );
+    can_ok( $app, 'response' );
+    isa_ok( $app->response, 'Response' );
+}
+
+note 'Checking our fake response'; {
+    my $response = Response->new(
+        status => sub {
+            my ( $self, $input ) = @_;
+            ::isa_ok( $self, 'Response' );
+            ::is( $input, 'calling status', 'status called' );
+            return 'foo';
+        },
+
+        header => sub {
+            my ( $self, $input ) = @_;
+            ::isa_ok( $self, 'Response' );
+            ::is( $input, 'calling header', 'header called' );
+            return qw<bar baz>;
+        },
+    );
+
+    isa_ok( $response, 'Response' );
+
+    is_deeply(
+        [ $response->status('calling status') ],
+        [ 'foo' ],
+        'status() works',
+    );
+
+    is_deeply(
+        [ $response->header('calling header') ],
+        [ qw<bar baz> ],
+        'header() works',
+    );
+}
+
+my $handler = Handler->new;
+isa_ok( $handler, 'Handler' );
+can_ok( $handler, qw<response response_400 response_403 response_404> );
+
+note '->response'; {
+    # set up status and header
+    my $app = App->new(
+        response => Response->new(
+            status => sub {
+                my ( $self, $code ) = @_;
+                ::isa_ok( $self, 'Response' );
+                ::is( $code, '400', 'Correct status code' );
+            },
+
+            header => sub {
+                my ( $self, $hdr_name, $hdr_content ) = @_;
+                ::isa_ok( $self, 'Response' );
+                ::is( $hdr_name, 'Content-Type', 'Correct header name' );
+                ::is( $hdr_content, 'text/plain', 'Correct header value' );
+            },
+        )
+    );
+
+    is(
+        $handler->response( $app, 400, 'Some Message' ),
+        'Some Message',
+        'Correct response created',
+    );
+}
+
+note '->response_400'; {
+    # set up status and header
+    my $app = App->new(
+        response => Response->new(
+            status => sub {
+                my ( $self, $code ) = @_;
+                ::isa_ok( $self, 'Response' );
+                ::is( $code, '400', 'Correct status code' );
+            },
+
+            header => sub {
+                my ( $self, $hdr_name, $hdr_content ) = @_;
+                ::isa_ok( $self, 'Response' );
+                ::is( $hdr_name, 'Content-Type', 'Correct header name' );
+                ::is( $hdr_content, 'text/plain', 'Correct header value' );
+            },
+        )
+    );
+
+    is(
+        $handler->response_400($app),
+        'Bad Request',
+        'Correct response 400 created',
+    );
+}
+
+note '->response_403'; {
+    # set up status and header
+    my $app = App->new(
+        response => Response->new(
+            status => sub {
+                my ( $self, $code ) = @_;
+                ::isa_ok( $self, 'Response' );
+                ::is( $code, '403', 'Correct status code' );
+            },
+
+            header => sub {
+                my ( $self, $hdr_name, $hdr_content ) = @_;
+                ::isa_ok( $self, 'Response' );
+                ::is( $hdr_name, 'Content-Type', 'Correct header name' );
+                ::is( $hdr_content, 'text/plain', 'Correct header value' );
+            },
+        )
+    );
+
+    is(
+        $handler->response_403($app),
+        'Unauthorized',
+        'Correct response 403 created',
+    );
+}
+
+note '->response_404'; {
+    # set up status and header
+    my $app = App->new(
+        response => Response->new(
+            status => sub {
+                my ( $self, $code ) = @_;
+                ::isa_ok( $self, 'Response' );
+                ::is( $code, '404', 'Correct status code' );
+            },
+
+            header => sub {
+                my ( $self, $hdr_name, $hdr_content ) = @_;
+                ::isa_ok( $self, 'Response' );
+                ::is( $hdr_name, 'Content-Type', 'Correct header name' );
+                ::is( $hdr_content, 'text/plain', 'Correct header value' );
+            },
+        )
+    );
+
+    is(
+        $handler->response_404($app),
+        'Not Found',
+        'Correct response 404 created',
+    );
+}
@@ -0,0 +1,246 @@
+use strict;
+use warnings;
+use Test::More tests => 40;
+use Dancer2::Core::Runner;
+
+is( $Dancer2::runner, undef, 'No runner defined in Dancer2 yet' );
+
+{
+    my $runner = Dancer2::Core::Runner->new();
+    isa_ok( $runner, 'Dancer2::Core::Runner' );
+}
+
+note 'MIME types'; {
+    my $runner = Dancer2::Core::Runner->new();
+    can_ok( $runner, 'mime_type' );
+    isa_ok( $runner->mime_type, 'Dancer2::Core::MIME' );
+}
+
+ok( $Dancer2::runner, 'Have a runner (probably) in $Dancer2::runner' );
+isa_ok( $Dancer2::runner, 'Dancer2::Core::Runner', 'Runner now defined' );
+
+note 'BUILD setting $Carp::Verbose';
+{
+    my $runner = Dancer2::Core::Runner->new();
+    is( $runner->config->{'traces'}, 0, 'traces not turned on (default' );
+    is( $Carp::Verbose, 0, 'Carp Verbose not turned on (default)' );
+}
+
+{
+    local $ENV{DANCER_TRACES} = 1;
+    my $runner = Dancer2::Core::Runner->new();
+    is( $runner->config->{'traces'}, 1, 'traces turned on' );
+    is( $Carp::Verbose, 1, 'Carp Verbose turned on (using DANCER_TRACES)' );
+}
+
+note 'server'; {
+    my $runner = Dancer2::Core::Runner->new(
+        host => '1.2.3.4', port => 9543, timeout => 3,
+    );
+    can_ok( $runner, qw<server _build_server run> );
+
+    my $server = $runner->server;
+    isa_ok( $server, 'HTTP::Server::PSGI' );
+    can_ok( $server, 'run' );
+    foreach my $attr ( qw<host port timeout> ) {
+        is( $server->{$attr}, $runner->$attr, "$attr set correctly in Server" );
+    }
+
+    is(
+        $server->{'server_software'},
+        "Perl Dancer2 $Dancer2::VERSION",
+        'server_software set correctly in Server',
+    );
+}
+
+note 'Environment';
+{
+    my $runner = Dancer2::Core::Runner->new();
+
+    is(
+        $runner->environment,
+        'development',
+        'Default environment',
+    );
+}
+
+{
+    local $ENV{DANCER_ENVIRONMENT} = 'foo';
+    my $runner = Dancer2::Core::Runner->new();
+    is(
+        $runner->environment,
+        'foo',
+        'Successfully set envinronment using DANCER_ENVIRONMENT',
+    );
+
+    $runner->config->{'apphandler'} = 'Standalone';
+}
+
+{
+    local $ENV{PLACK_ENV} = 'bar';
+    my $runner = Dancer2::Core::Runner->new();
+    is(
+        $runner->environment,
+        'bar',
+        'Successfully set environment using PLACK_ENV',
+    );
+
+    is(
+        $runner->config->{'apphandler'},
+        'PSGI',
+        'apphandler set to PSGI under PLACK_ENV',
+    );
+}
+
+{
+    local $ENV{DANCER_APPHANDLER} = 'baz';
+    my $runner = Dancer2::Core::Runner->new();
+    is(
+        $runner->config->{'apphandler'},
+        'baz',
+        'apphandler set via DANCER_APPHANDLER',
+    );
+}
+
+note 'Server tokens';
+{
+    my $runner = Dancer2::Core::Runner->new();
+    is(
+        $runner->config->{'server_tokens'},
+        1,
+        'Default server_tokens',
+    );
+}
+
+{
+    local $ENV{DANCER_SERVER_TOKENS} = 0;
+    my $runner = Dancer2::Core::Runner->new();
+    is(
+        $runner->config->{'server_tokens'},
+        0,
+        'Successfully set server_tokens using DANCER_SERVER_TOKENS',
+    );
+}
+
+note 'Startup info';
+{
+    my $runner = Dancer2::Core::Runner->new();
+    is(
+        $runner->config->{'startup_info'},
+        1,
+        'Default startup_info',
+    );
+}
+
+{
+    local $ENV{DANCER_STARTUP_INFO} = 0;
+    my $runner = Dancer2::Core::Runner->new();
+    is(
+        $runner->config->{'startup_info'},
+        0,
+        'Successfully set startup_info using DANCER_STARTUP_INFO',
+    );
+}
+
+note 'Warnings';
+{
+    my $runner = Dancer2::Core::Runner->new();
+    is(
+        $runner->config->{'warnings'},
+        0,
+        'Default warnings',
+    );
+}
+
+{
+    local $ENV{DANCER_WARNINGS} = 1;
+    my $runner = Dancer2::Core::Runner->new();
+    is(
+        $runner->config->{'warnings'},
+        1,
+        'Successfully set warnings using DANCER_WARNINGS',
+    );
+}
+
+{
+    {
+        package App::Fake;
+        use Moo;
+        has name => (
+            is      => 'ro',
+            default => sub {__PACKAGE__},
+        );
+
+        has postponed_hooks => (
+            is      => 'ro',
+            default => sub { +{
+                before => 'that',
+                after  => 'this',
+            } },
+        );
+    }
+    my $runner = Dancer2::Core::Runner->new();
+    my $app    = App::Fake->new();
+    can_ok( $runner, qw<register_application add_postponed_hooks> );
+
+    is_deeply(
+        $runner->apps,
+        [],
+        'Apps are empty at first',
+    );
+
+    is_deeply(
+        $runner->postponed_hooks,
+        +{},
+        'No postponed hooks at first',
+    );
+
+    $runner->register_application($app);
+
+    is_deeply(
+        $runner->apps,
+        [$app],
+        'Runner registered application',
+    );
+
+    is_deeply(
+        $runner->postponed_hooks,
+        { 'App::Fake' => $app->postponed_hooks },
+        'Runner registered the App\'s postponed hooks',
+    );
+}
+
+{
+    my $runner = Dancer2::Core::Runner->new();
+    can_ok( $runner, qw<start start_server> );
+
+    $runner->config->{'apphandler'} = 'PSGI';
+    my $app = $runner->start;
+    isa_ok( $app, 'CODE' );
+
+    {
+        package Server::Fake;
+        sub new { bless {}, 'Server::Fake' }
+        sub run {
+            my ( $self, $app ) = @_;
+            ::isa_ok( $self, 'Server::Fake' );
+            ::isa_ok( $app, 'CODE' );
+
+            return 'OK';
+        }
+    }
+
+    $runner->{'server'} = Server::Fake->new;
+    my $res = $runner->start_server($app);
+    is( $res, 'OK', 'start_server works' );
+}
+
+{
+    my $runner = Dancer2::Core::Runner->new();
+    can_ok( $runner, 'start' );
+
+    $runner->config->{'apphandler'} = 'PSGI';
+    my $app = $runner->start;
+    isa_ok( $app, 'CODE' );
+}
+
@@ -0,0 +1,38 @@
+use strict;
+use warnings;
+use Test::More tests => 6;
+use Dancer2::Core::Runner;
+
+{
+    my $runner = Dancer2::Core::Runner->new();
+    isa_ok( $runner, 'Dancer2::Core::Runner' );
+
+    is(
+        $runner->environment,
+        'development',
+        'Default environment',
+    );
+}
+
+{
+    local $ENV{DANCER_ENVIRONMENT} = 'foo';
+    my $runner = Dancer2::Core::Runner->new();
+    isa_ok( $runner, 'Dancer2::Core::Runner' );
+    is(
+        $runner->environment,
+        'foo',
+        'Successfully set envinronment using DANCER_ENVIRONMENT',
+    );
+}
+
+{
+    local $ENV{PLACK_ENV} = 'bar';
+    my $runner = Dancer2::Core::Runner->new();
+    isa_ok( $runner, 'Dancer2::Core::Runner' );
+    is(
+        $runner->environment,
+        'bar',
+        'Successfully set environment using PLACK_ENV',
+    );
+}
+
@@ -0,0 +1,92 @@
+#!perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 25;
+use Plack::Test;
+use HTTP::Request::Common;
+
+{ package App1; use Dancer2; get '/1' => sub {1}; }
+{ package App2; use Dancer2; get '/2' => sub {2}; }
+{ package App3; use Dancer2; get '/3' => sub {3}; }
+
+sub is_available {
+    my ( $cb, @apps ) = @_;
+    foreach my $app (@apps) {
+        is( $cb->( GET "/$app" )->content, $app, "App$app available" );
+    }
+}
+
+sub isnt_available {
+    my ( $cb, @apps ) = @_;
+    foreach my $app (@apps) {
+        is(
+            $cb->( GET "/$app" )->code,
+            404,
+            "App$app is not available",
+        );
+    }
+}
+
+note 'All Apps'; {
+    my $app = Dancer2->psgi_app;
+    isa_ok( $app, 'CODE', 'Got PSGI app' );
+    test_psgi $app, sub {
+        my $cb = shift;
+        is_available( $cb, 1, 2, 3 );
+    };
+}
+
+note 'Specific Apps by parameters'; {
+    my @apps = @{ Dancer2->runner->apps }[ 0, 2 ];
+    is( scalar @apps, 2, 'Took two apps from the Runner' );
+    my $app = Dancer2->psgi_app(\@apps);
+    isa_ok( $app, 'CODE', 'Got PSGI app' );
+    test_psgi $app, sub {
+        my $cb = shift;
+        is_available( $cb, 1, 3 );
+        isnt_available( $cb, 2 );
+    };
+}
+
+note 'Specific Apps via App objects'; {
+    my $app = App2->psgi_app;
+    isa_ok( $app, 'CODE', 'Got PSGI app' );
+    test_psgi $app, sub {
+        my $cb = shift;
+        is_available( $cb, 2 );
+        isnt_available( $cb, 1, 3 );
+    };
+};
+
+note 'Specific apps by App names'; {
+    my $app = Dancer2->psgi_app( [ 'App1', 'App3' ] );
+    isa_ok( $app, 'CODE', 'Got PSGI app' );
+    test_psgi $app, sub {
+        my $cb = shift;
+        isnt_available( $cb, 2 );
+        is_available( $cb, 1, 3 );
+    };
+}
+
+note 'Specific apps by App names with regular expression, v1'; {
+    my $app = Dancer2->psgi_app( [ qr/^App1$/, qr/^App3$/ ] );
+    isa_ok( $app, 'CODE', 'Got PSGI app' );
+    test_psgi $app, sub {
+        my $cb = shift;
+        isnt_available( $cb, 2 );
+        is_available( $cb, 1, 3 );
+    };
+}
+
+note 'Specific apps by App names with regular expression, v2'; {
+    my $app = Dancer2->psgi_app( [ qr/^App(2|3)$/ ] );
+    isa_ok( $app, 'CODE', 'Got PSGI app' );
+    test_psgi $app, sub {
+        my $cb = shift;
+        isnt_available( $cb, 1 );
+        is_available( $cb, 2, 3 );
+    };
+}
+
@@ -0,0 +1,77 @@
+#!perl
+
+use strict;
+use warnings;
+use Test::More tests => 9;
+use Plack::Test;
+use HTTP::Request::Common;
+
+{
+    package App::SetContent;
+    use Dancer2;
+    get '/' => sub {
+        content 'OK';
+
+        'Not OK';
+    };
+}
+
+{
+    package App::PassSuccess;
+    use Dancer2;
+
+    get '/' => sub {
+        content 'Missing';
+        pass;
+    };
+
+    get '/' => sub {
+        'There';
+    };
+}
+
+{
+    package App::PassFail;
+    use Dancer2;
+
+    get '/' => sub {
+        content 'Missing';
+        pass;
+    };
+
+    get '/' => sub {};
+}
+
+{
+    my $app = App::SetContent->to_app;
+    isa_ok( $app, 'CODE' );
+
+    my $test = Plack::Test->create($app);
+    my $res  = $test->request( GET '/' );
+
+    is( $res->code,    200,  'Reached route'   );
+    is( $res->content, 'OK', 'Correct content' );
+}
+
+{
+    my $app = App::PassSuccess->to_app;
+    isa_ok( $app, 'CODE' );
+
+    my $test = Plack::Test->create($app);
+    my $res  = $test->request( GET '/' );
+
+    is( $res->code,    200,     'Reached route'   );
+    is( $res->content, 'There', 'Correct content' );
+}
+
+{
+    my $app = App::PassFail->to_app;
+    isa_ok( $app, 'CODE' );
+
+    my $test = Plack::Test->create($app);
+    my $res  = $test->request( GET '/' );
+
+    is( $res->code,    200, 'Reached route'   );
+    is( $res->content, '',  'Correct content' );
+}
+
@@ -0,0 +1,57 @@
+#!perl
+
+use strict;
+use warnings;
+use Test::More tests => 4;
+use Plack::Test;
+use HTTP::Request::Common;
+
+{
+    package App;
+    use Dancer2;
+    get '/' => sub {'OK'};
+}
+
+{
+    package App::Extended;
+    use Dancer2;
+    prefix '/test';
+    get '/'  => sub {'Also OK'};
+    post '/' => sub {
+        my $params = params;
+        ::isa_ok( $params, 'HASH' );
+        ::is( $params->{'foo'}, 'bar', 'Got params' );
+        return $params->{'foo'};
+    };
+}
+
+my $app = Dancer2->psgi_app;
+isa_ok( $app, 'CODE' );
+
+my $test = Plack::Test->create($app);
+
+subtest 'GET /' => sub {
+    plan tests => 2;
+    my $res = $test->request( GET '/' );
+    is( $res->code,    200,  'Correct code'    );
+    is( $res->content, 'OK', 'Correct content' );
+};
+
+subtest 'GET /test/' => sub {
+    plan tests => 2;
+    my $res = $test->request( GET '/test/' );
+    is( $res->code,     200,      'Correct code'    );
+    is( $res->content, 'Also OK', 'Correct content' );
+};
+
+subtest 'Missing POST params' => sub {
+    plan tests => 4;
+    my $res = $test->request(
+        POST '/test/',
+        { foo => 'bar' },
+    );
+
+    is( $res->code,    200,   'Correct code'    );
+    is( $res->content, 'bar', 'Correct content' );
+};
+
@@ -87,7 +87,7 @@ sub get_app_for_engine {
     hook 'engine.session.after_retrieve' => sub {
        my ($response) = @_;
        is ref($response), 'Dancer2::Core::Session',
-                            'Correct response type returned in before_retrieve';
+                            'Correct response type returned in after_retrieve';
     };
     #this returns dancer app. We'll register it with LWP::Protocol::PSGI
     dance;
@@ -120,6 +120,16 @@ foreach my $engine (@engines) {
         is $test_flags->{'engine.session.after_destroy'}, undef, "session.after_destroy not called";
     };
 
+    subtest 'verify Handler::File (static content) does not retrieve session' => sub {
+        my $r = $ua->get("http://localhost:3000/file.txt");
+
+        # These should not change from previous subtest
+        is $test_flags->{'engine.session.before_create'}, 1, "session.before_create not called";
+        is $test_flags->{'engine.session.after_create'}, 1, "session.after_create not called";
+        is $test_flags->{'engine.session.before_retrieve'}, undef, "session.before_retrieve not called";
+        is $test_flags->{'engine.session.after_retrieve'}, undef, "session.after_retrieve not called";
+    };
+
     $r = $ua->get("http://localhost:3000/get_session");
     is $r->content, "ok", "get_session ran ok";
 
@@ -0,0 +1,2 @@
+---
+name: damian
@@ -0,0 +1,2 @@
+---
+name: damian
@@ -0,0 +1,2 @@
+---
+name: damian
@@ -0,0 +1,2 @@
+---
+name: damian
@@ -0,0 +1,2 @@
+---
+name: damian
@@ -0,0 +1,2 @@
+---
+name: damian
@@ -0,0 +1,2 @@
+---
+name: damian
@@ -0,0 +1,2 @@
+---
+name: damian
@@ -0,0 +1,2 @@
+---
+name: damian
@@ -0,0 +1,2 @@
+---
+name: damian
@@ -0,0 +1,2 @@
+---
+name: damian
@@ -0,0 +1,2 @@
+---
+name: damian
@@ -0,0 +1,2 @@
+---
+name: damian
@@ -0,0 +1,2 @@
+---
+name: damian
@@ -0,0 +1,2 @@
+---
+name: damian