Permalink
Browse files

merge release/1.3059_03

  • Loading branch information...
2 parents a37ca92 + b34cb40 commit b106f9172fc58ab67f9db81bcaed1d713be1e97f Alexis Sukrieh committed Jun 11, 2011
Showing with 2,527 additions and 2,675 deletions.
  1. +2 −1 AUTHORS
  2. +43 −0 CHANGES
  3. +20 −46 MANIFEST
  4. +0 −1 Makefile.PL
  5. +53 −18 lib/Dancer.pm
  6. +8 −1 lib/Dancer/App.pm
  7. +18 −1 lib/Dancer/Config.pm
  8. +6 −3 lib/Dancer/Cookbook.pod
  9. +2 −2 lib/Dancer/Deployment.pod
  10. +1 −1 lib/Dancer/Deprecation.pm
  11. +3 −1 lib/Dancer/Factory/Hook.pm
  12. +65 −21 lib/Dancer/FileUtils.pm
  13. +1 −1 lib/Dancer/Handler.pm
  14. +2 −2 lib/Dancer/Handler/Debug.pm
  15. +8 −0 lib/Dancer/Introduction.pod
  16. +2 −1 lib/Dancer/Logger/Abstract.pm
  17. +4 −2 lib/Dancer/Logger/File.pm
  18. +3 −3 lib/Dancer/MIME.pm
  19. +72 −59 lib/Dancer/Request.pm
  20. +9 −10 lib/Dancer/Route.pm
  21. +8 −6 lib/Dancer/Serializer/Mutable.pm
  22. +4 −1 lib/Dancer/Session/Abstract.pm
  23. +33 −7 lib/Dancer/Session/YAML.pm
  24. +1 −0 lib/Dancer/Template/Abstract.pm
  25. +10 −0 lib/Dancer/Test.pm
  26. +1 −0 t/00_base/003_syntax.t
  27. +8 −2 t/00_base/11_file_utils.t
  28. +11 −10 t/00_base/12_utf8_charset.t
  29. +33 −0 t/00_base/15_dependent_modules.t
  30. +5 −2 t/00_base/config.t
  31. +40 −0 t/00_base/optional-module-versions.t
  32. +6 −1 t/01_config/02_mime_type.t
  33. +2 −2 t/01_config/06_stack_trace.t
  34. +0 −38 t/02_request/02_get_params.t
  35. +0 −36 t/02_request/03_post_params.t
  36. +1 −1 t/02_request/04_custom.t
  37. +1 −1 t/02_request/04_forward.t
  38. +10 −3 t/02_request/06_init_env.t
  39. +6 −5 t/02_request/07_raw_data.t
  40. +110 −36 t/02_request/08_params.t
  41. +9 −8 t/02_request/10_mixed_params.t
  42. +1 −1 t/02_request/11_accessors.t
  43. +1 −1 t/02_request/12_base.t
  44. +5 −4 t/02_request/13_ajax.t
  45. +11 −10 t/02_request/14_uploads.t
  46. +9 −8 t/02_request/15_headers.t
  47. +1 −1 t/02_request/16_delete.t
  48. +2 −2 t/02_request/17_uri_base.t
  49. +15 −0 t/02_request/18_param_accessor.t
  50. +0 −18 t/03_route_handler/000_create_fake_env.t
  51. +0 −24 t/03_route_handler/00_http_methods.t
  52. +23 −0 t/03_route_handler/01_http_methods.t
  53. +0 −53 t/03_route_handler/01_params.t
  54. +75 −0 t/03_route_handler/02_params.t
  55. +0 −53 t/03_route_handler/03_passing.t
  56. +9 −16 t/03_route_handler/{00_route_object.t → 03_routes_api.t}
  57. +189 −0 t/03_route_handler/04_routes_matching.t
  58. +0 −42 t/03_route_handler/04_wildcards.t
  59. +92 −0 t/03_route_handler/05_filter.t
  60. +91 −0 t/03_route_handler/06_redirect.t
  61. +0 −35 t/03_route_handler/06_regexp.t
  62. +5 −6 t/03_route_handler/07_compilation_warning.t
  63. +22 −22 t/03_route_handler/08_errors.t
  64. +0 −21 t/03_route_handler/09_status.t
  65. +0 −54 t/03_route_handler/11_redirect.t
  66. +0 −22 t/03_route_handler/11_redirect_absolute.t
  67. +0 −35 t/03_route_handler/11_redirect_no_content.t
  68. +24 −22 t/03_route_handler/12_response.t
  69. +0 −67 t/03_route_handler/13_any_route_handler.t
  70. +15 −23 t/03_route_handler/14_options.t
  71. +43 −77 t/03_route_handler/15_prefix.t
  72. +18 −24 t/03_route_handler/16_caching.t
  73. +4 −8 t/03_route_handler/18_auto_page.t
  74. +0 −25 t/03_route_handler/19_filters_and_params.t
  75. +0 −21 t/03_route_handler/20_params_multiple_tokens.t
  76. +3 −3 t/03_route_handler/21_ajax.t
  77. +0 −31 t/03_route_handler/22_filter_halt.t
  78. +2 −2 t/03_route_handler/23_filter_error_catching.t
  79. +15 −32 t/03_route_handler/24_multiple_params.t
  80. +4 −9 t/03_route_handler/24_named_captures.t
  81. +0 −26 t/03_route_handler/27_issue_77_pass_breaks_routes.t
  82. +4 −6 t/03_route_handler/28_plack_mount.t
  83. +16 −20 t/03_route_handler/29_forward.t
  84. +4 −4 t/03_route_handler/29_redirect_immediately.t
  85. +0 −17 t/03_route_handler/30_bug_gh190.t
  86. +11 −13 t/03_route_handler/31_infinite_loop.t
  87. +0 −15 t/03_route_handler/32_gh_393.t
  88. +3 −3 t/03_route_handler/33_vars.t
  89. +46 −0 t/03_route_handler/34_forward_body_post.t
  90. +53 −0 t/03_route_handler/99_bugs.t
  91. +39 −30 t/04_static_file/001_base.t
  92. +0 −63 t/04_static_file/002_mime_types.t
  93. +23 −23 t/04_static_file/003_mime_types_reinit.t
  94. +64 −0 t/04_static_file/01_mime_types.t
  95. +0 −13 t/04_static_file/03_get_mime_type.t
  96. +0 −11 t/05_views/001_settings.t
  97. +29 −11 t/05_views/002_view_rendering.t
  98. +3 −5 t/05_views/03_layout.t
  99. +1 −0 t/05_views/views/vars.tt
  100. +9 −9 t/06_helpers/01_send_file.t
  101. +3 −3 t/06_helpers/02_http_status.t
  102. +2 −4 t/06_helpers/03_content_type.t
  103. +2 −7 t/06_helpers/04_status.t
  104. +0 −3 t/06_helpers/05_send_error.t
  105. +1 −1 t/06_helpers/06_load.t
  106. +2 −3 t/07_apphandlers/02_apache2_plack.t
  107. +4 −4 t/07_apphandlers/03_psgi_app.t
  108. +12 −5 t/07_apphandlers/04_standalone_app.t
  109. +7 −6 t/07_apphandlers/05_middlewares.t
  110. +2 −3 t/07_apphandlers/05_psgi_api.t
  111. +8 −6 t/07_apphandlers/06_debug.t
  112. +8 −6 t/07_apphandlers/07_middleware_map.t
  113. +8 −7 t/08_session/03_http_requests.t
  114. +12 −2 t/08_session/05_yaml.t
  115. +7 −6 t/08_session/07_session_expires.t
  116. +11 −23 t/08_session/10_filter.t
  117. +5 −4 t/08_session/13_session_httponly.t
  118. +8 −7 t/09_cookies/03_persistence.t
  119. +1 −1 t/09_cookies/05_api.t
  120. +2 −2 t/10_template/01_factory.t
  121. +1 −0 t/10_template/02_abstract_class.t
  122. +8 −8 t/10_template/03_simple.t
  123. +6 −6 t/10_template/05_template_toolkit.t
  124. +39 −19 t/11_logger/01_abstract.t
  125. +11 −5 t/11_logger/03_file.t
  126. +9 −2 t/11_logger/05_format.t
  127. +4 −5 t/11_logger/11_runtime_file.t
  128. +9 −6 t/12_response/04_charset_server.t
  129. +3 −3 t/12_response/08_drop_content.t
  130. +0 −18 t/14_serializer/000_create_fake_env.t
  131. +0 −46 t/14_serializer/01_basic.t
  132. +201 −0 t/14_serializer/01_helpers.t
  133. +0 −75 t/14_serializer/02_json.t
  134. +50 −0 t/14_serializer/02_request_json.t
  135. +50 −0 t/14_serializer/03_request_yaml.t
  136. +0 −26 t/14_serializer/03_yaml.t
  137. +0 −96 t/14_serializer/04_mutable.t
  138. +54 −0 t/14_serializer/04_request_xml.t
  139. +0 −202 t/14_serializer/05_live.t
  140. +44 −0 t/14_serializer/05_request_mutable.t
  141. +119 −0 t/14_serializer/06_api.t
  142. +0 −32 t/14_serializer/06_serialize_response.t
  143. +0 −59 t/14_serializer/07_bug_57805.t
  144. +0 −69 t/14_serializer/08_error.t
  145. +0 −34 t/14_serializer/09_abstract.t
  146. +0 −31 t/14_serializer/10_dumper.t
  147. +0 −38 t/14_serializer/11_bug_57829.t
  148. +0 −61 t/14_serializer/12_bug_gh106.t
  149. +0 −58 t/14_serializer/13_xml.t
  150. +0 −17 t/14_serializer/14_api.t
  151. +0 −55 t/14_serializer/14_show_errors.t
  152. +0 −23 t/14_serializer/16_bug_gh_299.t
  153. +6 −5 t/14_serializer/17_clear_serializer.t
  154. +114 −0 t/14_serializer/99_bugs.t
  155. +0 −40 t/14_serializer/handler-helper.t
  156. +2 −3 t/15_plugins/02_config.t
  157. +19 −1 t/16_timer/00_base.t
  158. +0 −21 t/16_timer/02_hires.t
  159. +10 −11 t/17_apps/01_settings.t
  160. +0 −18 t/18_main_dsl/000_create_fake_env.t
  161. +0 −9 t/18_main_dsl/01_config.t
  162. +0 −15 t/18_main_dsl/uri_for.t
  163. +1 −9 t/19_dancer/01_script.t
  164. +9 −8 t/19_dancer/02_script_version_from.t
  165. +1 −6 t/20_deprecation/01_api.t
  166. +7 −7 t/21_dependents/Dancer-Session-Cookie.t
  167. +19 −1 t/22_hooks/01_api.t
  168. +3 −3 t/22_hooks/02_before.t
  169. +9 −11 t/23_dancer_tests/01_basic.t
  170. +9 −4 t/23_dancer_tests/02_tests_functions.t
  171. +0 −32 t/lib/TestSerializer.pm
View
3 AUTHORS
@@ -4,7 +4,7 @@ The first version of Dancer was written by Alexis Sukrieh in summer 2009.
The project has evolved a lot since that time, and a huge and very active
community emerged to extend and improve Dancer..
-The Project is now handled by a organised team of core developers, and many
+The Project is now handled by an organised team of core developers, and many
valued contributions are sent by motivated developers around the globe.
This is what makes Dancer such a fun project to use - it's a living community
of motivated people.
@@ -65,6 +65,7 @@ A huge thank you to all of them!
Naveed <naveed@ironcamel.(none)>
Naveen <nmani@nashresearch.com>
Nicolas Oudard <noudard@weborama.com>
+ Niko <nikomomo@gmail.com>
Olivier Mengué <dolmen@cpan.org>
Paul Driver <frodwith@gmail.com>
Paul Tomlin <ptomli@gmail.com>
View
43 CHANGES
@@ -1,3 +1,46 @@
+1.3059_03 11.06.2011
+
+ [ BUG FIXES ]
+ * Fix for issue #539
+ https://github.com/sukria/Dancer/issues/539
+ Don't decode twice entries in the params hash table, file
+ uploads with UTF-8 characters in their name are now possible.
+ (Toby Corkindale, Alexis Sukrieh)
+ * Fix broken test with old version of HTTP::Parser::XS
+ (Franck Cuny)
+ * #492 - Don't run Test::TCP tests on win32
+ (Franck Cuny)
+ * Fix a bug that when forwarding a post with post data stalled the
+ code (read on no data handle). (Alberto Simões)
+ * Tweak tests regular expression to be more flexible (Pedro Melo)
+ * Require a recent Test::TCP (1.13) to run tests. (Alberto Simões)
+ * Fix hooks implementation that failed when user messes $_ (Pedro Melo)
+ * Fix broken params('query') and params('body') during forward and
+ dancer_request test function. (Alberto Simões and Squeek)
+
+ [ ENHANCEMENTS ]
+ * Fix for issue #516
+ https://github.com/sukria/Dancer/issues/516
+ No more legacy code in Dancer::Route to handle routes created
+ with the deprecated keyword "r". The related code is now more
+ concise and should be slightly more efficient.
+ (Alexis Sukrieh)
+ * Merge PR #541
+ https://github.com/sukria/Dancer/pull/541
+ New "param" accessor to retrieve a parameter easily.
+ (Alberto Simões)
+ * Implement session directory testing cache for Session::YAML
+ (Damien Krotkine)
+ * Tests rework (improve speed, remove useless tests, ...)
+ (Alberto Simões and Franck Cuny)
+ * Configuration for log_dir and log_file.
+ (Alberto Simões)
+ * Pass vars to templates automatically (David Precious)
+ * Support lexical prefix (Pedro Melo)
+
+ [ DOCUMENTATION ]
+ * Improve FileUtils documentation. (mokko)
+
1.3059_02 29.05.2011
[ BUG FIXES ]
View
66 MANIFEST
@@ -99,9 +99,11 @@ t/00_base/11_file_utils.t
t/00_base/12_utf8_charset.t
t/00_base/13_dancer_singleton.t
t/00_base/14_changelog.t
+t/00_base/15_dependent_modules.t
t/00_base/config.t
t/00_base/lib/AppWithError.pm
t/00_base/lib/WorkingApp.pm
+t/00_base/optional-module-versions.t
t/00_base/uri_for.t
t/00_base/utf8.tt
t/00_base/views/unicode.tt
@@ -116,8 +118,6 @@ t/01_config/environments/development.pl
t/01_config/yaml_dependency.t
t/02_request/000_create_fake_env.t
t/02_request/01_load.t
-t/02_request/02_get_params.t
-t/02_request/03_post_params.t
t/02_request/04_custom.t
t/02_request/04_forward.t
t/02_request/05_cgi_pm_compat.t
@@ -132,53 +132,42 @@ t/02_request/14_uploads.t
t/02_request/15_headers.t
t/02_request/16_delete.t
t/02_request/17_uri_base.t
-t/03_route_handler/000_create_fake_env.t
-t/03_route_handler/00_http_methods.t
-t/03_route_handler/00_route_object.t
-t/03_route_handler/01_params.t
-t/03_route_handler/03_passing.t
-t/03_route_handler/04_wildcards.t
+t/02_request/18_param_accessor.t
+t/03_route_handler/01_http_methods.t
+t/03_route_handler/02_params.t
+t/03_route_handler/03_routes_api.t
+t/03_route_handler/04_routes_matching.t
t/03_route_handler/04_wildcards_megasplat.t
+t/03_route_handler/05_filter.t
t/03_route_handler/05_unicode.t
-t/03_route_handler/06_regexp.t
+t/03_route_handler/06_redirect.t
t/03_route_handler/07_compilation_warning.t
t/03_route_handler/08_errors.t
-t/03_route_handler/09_status.t
-t/03_route_handler/11_redirect.t
-t/03_route_handler/11_redirect_absolute.t
-t/03_route_handler/11_redirect_no_content.t
t/03_route_handler/12_response.t
-t/03_route_handler/13_any_route_handler.t
t/03_route_handler/14_options.t
t/03_route_handler/15_prefix.t
t/03_route_handler/16_caching.t
t/03_route_handler/18_auto_page.t
-t/03_route_handler/19_filters_and_params.t
-t/03_route_handler/20_params_multiple_tokens.t
t/03_route_handler/21_ajax.t
-t/03_route_handler/22_filter_halt.t
t/03_route_handler/23_filter_error_catching.t
t/03_route_handler/24_multiple_params.t
t/03_route_handler/24_named_captures.t
-t/03_route_handler/27_issue_77_pass_breaks_routes.t
t/03_route_handler/28_plack_mount.t
t/03_route_handler/29_forward.t
t/03_route_handler/29_redirect_immediately.t
-t/03_route_handler/30_bug_gh190.t
t/03_route_handler/31_infinite_loop.t
-t/03_route_handler/32_gh_393.t
t/03_route_handler/33_vars.t
+t/03_route_handler/34_forward_body_post.t
+t/03_route_handler/99_bugs.t
t/03_route_handler/public/404.html
t/03_route_handler/public/utf8file.txt
t/03_route_handler/views/error.tt
t/03_route_handler/views/hello.tt
t/04_static_file/001_base.t
-t/04_static_file/002_mime_types.t
t/04_static_file/003_mime_types_reinit.t
-t/04_static_file/03_get_mime_type.t
+t/04_static_file/01_mime_types.t
t/04_static_file/static/hello.foo
t/04_static_file/static/hello.txt
-t/05_views/001_settings.t
t/05_views/002_view_rendering.t
t/05_views/03_layout.t
t/05_views/views/clock.tt
@@ -187,6 +176,7 @@ t/05_views/views/layouts/custom.tt
t/05_views/views/layouts/main.tt
t/05_views/views/request.tt
t/05_views/views/t03.tt
+t/05_views/views/vars.tt
t/06_helpers/000_create_fake_env.t
t/06_helpers/01_send_file.t
t/06_helpers/02_http_status.t
@@ -263,25 +253,14 @@ t/12_response/09_headers_to_array.t
t/12_response/10_error_dumper.t
t/13_engines/00_load.t
t/13_engines/02_template_init.t
-t/14_serializer/000_create_fake_env.t
-t/14_serializer/01_basic.t
-t/14_serializer/02_json.t
-t/14_serializer/03_yaml.t
-t/14_serializer/04_mutable.t
-t/14_serializer/05_live.t
-t/14_serializer/06_serialize_response.t
-t/14_serializer/07_bug_57805.t
-t/14_serializer/08_error.t
-t/14_serializer/09_abstract.t
-t/14_serializer/10_dumper.t
-t/14_serializer/11_bug_57829.t
-t/14_serializer/12_bug_gh106.t
-t/14_serializer/13_xml.t
-t/14_serializer/14_api.t
-t/14_serializer/14_show_errors.t
-t/14_serializer/16_bug_gh_299.t
+t/14_serializer/01_helpers.t
+t/14_serializer/02_request_json.t
+t/14_serializer/03_request_yaml.t
+t/14_serializer/04_request_xml.t
+t/14_serializer/05_request_mutable.t
+t/14_serializer/06_api.t
t/14_serializer/17_clear_serializer.t
-t/14_serializer/handler-helper.t
+t/14_serializer/99_bugs.t
t/15_plugins/000_create_fake_env.t
t/15_plugins/01_register.t
t/15_plugins/02_config.t
@@ -291,17 +270,13 @@ t/15_plugins/05_keywords.t
t/15_plugins/05_plugins_and_OO.t
t/15_plugins/06_hook.t
t/16_timer/00_base.t
-t/16_timer/02_hires.t
t/17_apps/000_create_fake_env.t
t/17_apps/00_base.t
t/17_apps/01_settings.t
t/17_apps/02_load_app.t
t/17_apps/03_prefix.t
t/17_apps/04_issue_91.t
t/17_apps/05_api.t
-t/18_main_dsl/000_create_fake_env.t
-t/18_main_dsl/01_config.t
-t/18_main_dsl/uri_for.t
t/19_dancer/01_script.t
t/19_dancer/02_script_version_from.t
t/20_deprecation/01_api.t
@@ -328,7 +303,6 @@ t/lib/TestApp.pm
t/lib/TestAppUnicode.pm
t/lib/TestPlugin.pm
t/lib/TestPlugin2.pm
-t/lib/TestSerializer.pm
t/lib/TestUtils.pm
t/manifest.t
t/pod.t
View
1 Makefile.PL
@@ -37,7 +37,6 @@ WriteMakefile1(
BUILD_REQUIRES => {
'Test::More' => '0.94',
- 'Tie::Hash::NamedCapture' => '0',
},
PREREQ_PM => {
View
71 lib/Dancer.pm
@@ -5,7 +5,7 @@ use warnings;
use Carp;
use Cwd 'realpath';
-our $VERSION = '1.3059_02';
+our $VERSION = '1.3059_03';
our $AUTHORITY = 'SUKRIA';
use Dancer::App;
@@ -63,6 +63,7 @@ our @EXPORT = qw(
logger
mime
options
+ param
params
pass
path
@@ -139,6 +140,7 @@ sub logger {
sub mime { Dancer::MIME->instance() }
sub options { Dancer::App->current->registry->universal_add('options', @_) }
sub params { Dancer::SharedData->request->params(@_) }
+sub param { params->{$_[0]} }
sub pass { Dancer::SharedData->response->pass(1) }
sub path { realpath(Dancer::FileUtils::path(@_)) }
sub post { Dancer::App->current->registry->universal_add('post', @_) }
@@ -286,6 +288,7 @@ sub _init_script_dir {
$res or croak "unable to set libdir : $error";
}
+
# Scheme grammar as defined in RFC 2396
# scheme = alpha *( alpha | digit | "+" | "-" | "." )
my $scheme_re = qr{ [a-z][a-z0-9\+\-\.]* }ix;
@@ -365,7 +368,7 @@ Dancer - lightweight yet powerful web application framework
use Dancer;
get '/hello/:name' => sub {
- return "Why, hello there " . params->{name};
+ return "Why, hello there " . param('name');
};
dance;
@@ -580,15 +583,15 @@ Sets the B<content-type> rendered, for the current route handler:
get '/cat/:txtfile' => sub {
content_type 'text/plain';
- # here we can dump the contents of params->{txtfile}
+ # here we can dump the contents of param('txtfile')
};
You can use abbreviations for content types. For instance:
get '/svg/:id' => sub {
content_type 'svg';
- # here we can dump the image with id params->{id}
+ # here we can dump the image with id param('id')
};
Note that if you want to change the default content-type for every route, you
@@ -779,15 +782,15 @@ Supported B<before> hooks (in order of execution):
This hook receives no arguments.
- hook before_deserializer {
+ hook before_deserializer => sub {
...
};
=item before_file_render
This hook receives as argument the path of the file to render.
- hook before_file_render {
+ hook before_file_render => sub {
my $path = shift;
...
};
@@ -812,7 +815,7 @@ This hook receives no arguments.
is equivalent to
- hook before sub {
+ hook before => sub {
...
};
@@ -822,14 +825,14 @@ This is an alias to 'before_template'.
This hook receives as argument a HashRef, containing the tokens.
- hook before_template_render sub {
+ hook before_template_render => sub {
my $tokens = shift;
delete $tokens->{user};
};
is equivalent to
- hook before_template sub {
+ hook before_template => sub {
my $tokens = shift;
delete $tokens->{user};
};
@@ -839,7 +842,7 @@ is equivalent to
This hook receives two arguments. The first one is a HashRef containing the
tokens. The second is a ScalarRef representing the content of the template.
- hook before_layout_render sub {
+ hook before_layout_render => sub {
my ($tokens, $html_ref) = @_;
...
};
@@ -848,7 +851,7 @@ tokens. The second is a ScalarRef representing the content of the template.
This hook receives as argument a L<Dancer::Response> object.
- hook before_serializer sub {
+ hook before_serializer => sub {
my $response = shift;
$response->content->{start_time} = time();
};
@@ -863,15 +866,15 @@ Supported B<after> hooks (in order of execution):
This hook receives no arguments.
- hook after_deserializer sub {
+ hook after_deserializer => sub {
...
};
=item after_file_render
This hook receives as argument a L<Dancer::Response> object.
- hook after_file_render sub {
+ hook after_file_render => sub {
my $response = shift;
};
@@ -880,7 +883,7 @@ This hook receives as argument a L<Dancer::Response> object.
This hook receives as argument a ScalarRef representing the content generated
by the template.
- hook after_template_render sub {
+ hook after_template_render => sub {
my $html_ref = shift;
};
@@ -889,7 +892,7 @@ by the template.
This hook receives as argument a ScalarRef representing the content generated
by the layout
- hook after_layout_render sub {
+ hook after_layout_render => sub {
my $html_ref = shift;
};
@@ -899,7 +902,7 @@ This is an alias for 'after'.
This hook receives as argument a L<Dancer::Response> object.
- hook after sub {
+ hook after => sub {
my $response = shift;
};
@@ -980,7 +983,20 @@ commonly-used methods are summarized below:
=head2 params
I<This method should be called from a route handler>.
-It's an alias for the L<Dancer::Request params accessor|Dancer::Request/"params">.
+It's an alias for the L<Dancer::Request params accessor|Dancer::Request/"params">. It returns
+an hash reference to all defined parameters. Check C<param> bellow to access quickly to a single
+parameter value.
+
+=head2 param
+
+I<This method should be called from a route handler>.
+This method is an accessor to the parameters hash table.
+
+ post '/login' => sub {
+ my $username = param "user";
+ my $password = param "pass";
+ # ...
+ }
=head2 pass
@@ -1027,6 +1043,16 @@ You can unset the prefix value:
prefix undef;
get '/page1' => sub {}; will match /page1
+For a safer alternative you can use lexical prefix like this:
+
+ prefix '/home' => sub {
+ ## Prefix is set to '/home' here
+
+ get ...;
+ get ...;
+ };
+ ## prefix reset to the previous version here
+
B<Notice:> once you have a prefix set, do not add a caret to the regex:
prefix '/foo';
@@ -1229,6 +1255,11 @@ You may also need to clear a session:
...
};
+If you need to fetch the session ID being used for any reason:
+
+ my $id = session->id;
+
+
=head2 splat
Returns the list of captures made from a route handler with a route pattern
@@ -1439,7 +1470,11 @@ see the AUTHORS file that comes with this distribution for details.
=head1 SOURCE CODE
The source code for this module is hosted on GitHub
-L<http://github.com/sukria/Dancer>
+L<http://github.com/sukria/Dancer>. Feel free to fork the repository and submit
+pull requests! (See L<Dancer::Development> for details on how to contribute).
+
+Also, why not L<watch the repo|https://github.com/sukria/Dancer/toggle_watch> to
+keep up to date with the latest upcoming changes?
=head1 GETTING HELP / CONTRIBUTING
View
9 lib/Dancer/App.pm
@@ -29,10 +29,17 @@ sub set_running_app {
}
sub set_prefix {
- my ($self, $prefix) = @_;
+ my ($self, $prefix, $cb) = @_;
croak "not a valid prefix: `$prefix', must start with a /"
if defined($prefix) && $prefix !~ /^\//;
+ my $previous = Dancer::App->current->prefix;
Dancer::App->current->prefix($prefix);
+ if (ref($cb) eq 'CODE') {
+ eval { $cb->() };
+ my $e = $@;
+ Dancer::App->current->prefix($previous);
+ die $e if $e;
+ }
return 1; # prefix may have been set to undef
}
View
19 lib/Dancer/Config.pm
@@ -27,6 +27,9 @@ my $setters = {
my ($setting, $value) = @_;
Dancer::Logger->init($value, settings());
},
+ log_file => sub {
+ Dancer::Logger->init(setting("logger"), setting());
+ },
session => sub {
my ($setting, $value) = @_;
Dancer::Session->init($value, settings());
@@ -71,6 +74,7 @@ my $setters = {
$Carp::Verbose = $traces ? 1 : 0;
},
};
+$setters->{log_path} = $setters->{log_file};
my $normalizers = {
charset => sub {
@@ -111,6 +115,7 @@ sub setting {
while (@_) {
my $setting = shift;
my $value = shift;
+
_set_setting ($setting, $value);
# At the moment, with any kind of hierarchical setter,
@@ -231,8 +236,11 @@ sub load_default_settings {
load_default_settings();
1;
+
__END__
+## TODO: C<environment> is not documented.
+
=pod
=head1 NAME
@@ -407,9 +415,18 @@ If set to true, tells Dancer to consider all warnings as blocking errors.
If set to true, Dancer will display full stack traces when a warning or a die
occurs. (Internally sets Carp::Verbose). Default to false.
+=head3 log_path (string)
+
+Folder where the ``file C<logger>'' saves logfiles.
+
+=head3 log_file (string)
+
+Name of the file to create when ``file C<logger>'' is active. It
+defaults to the C<environment> setting contents.
+
=head3 logger (enum)
-Select which logger to use. For example, to write to log files in C<logdir>:
+Select which logger to use. For example, to write to log files in C<log_path>:
logger: file
View
9 lib/Dancer/Cookbook.pod
@@ -481,9 +481,11 @@ All views must have a '.tt' extension. This may change in the future.
In order to render a view, just call the C<template> keyword at the end of the
action by giving the view name and the HASHREF of tokens to interpolate in the
-view (note that for convenience, the request, session and route params are
-automatically accessible in the view, named request, session and params) - for
-example:
+view (note that for convenience, the request, session, params and vars are
+automatically accessible in the view, named request, session, params and vars) -
+for example:
+
+ before => sub { var time => localtime() };
get '/hello/:name' => sub {
my $name = params->{name};
@@ -497,6 +499,7 @@ The template 'hello.tt' could contain, for example:
<% IF session.username %>
<p>You're logged in as <% session.username %>
<% END %>
+ It's currently <% vars.time %>
View
4 lib/Dancer/Deployment.pod
@@ -175,7 +175,7 @@ Start by creating a simple app.psgi file:
setting appname => 'app1';
load_app "app1";
Dancer::Config->load;
- my $request = Dancer::Request->new( $env );
+ my $request = Dancer::Request->new( env => $env );
Dancer->dance( $request );
};
my $app2 = sub {
@@ -184,7 +184,7 @@ Start by creating a simple app.psgi file:
setting appname => 'app2';
load_app "app2";
Dancer::Config->load;
- my $request = Dancer::Request->new( $env );
+ my $request = Dancer::Request->new( env => $env );
Dancer->dance( $request );
};
View
2 lib/Dancer/Deprecation.pm
@@ -61,7 +61,7 @@ List of possible parameters:
=item B<fatal> if set to true, croak instead of carp
-item B<reason> why is the feature deprecated
+=item B<reason> why is the feature deprecated
=back
View
4 lib/Dancer/Factory/Hook.pm
@@ -59,7 +59,9 @@ sub execute_hooks {
croak("The hook '$hook_name' doesn't exists");
}
- $_->(@args) foreach @{$self->get_hooks_for($hook_name)};
+ foreach my $h (@{$self->get_hooks_for($hook_name)}) {
+ $h->(@args);
+ }
}
sub get_hooks_for {
View
86 lib/Dancer/FileUtils.pm
@@ -11,7 +11,7 @@ use Cwd 'realpath';
use base 'Exporter';
use vars '@EXPORT_OK';
-@EXPORT_OK = qw(path real_path dirname read_file_content read_glob_content open_file set_file_mode);
+@EXPORT_OK = qw(dirname open_file path read_file_content read_glob_content real_path set_file_mode);
# Undo UNC special-casing catfile-voodoo on cygwin
sub _trim_UNC {
@@ -30,6 +30,7 @@ sub _trim_UNC {
}
return(@_);
}
+
sub d_catfile { File::Spec->catfile(_trim_UNC(@_)) }
sub d_catdir { File::Spec->catdir(_trim_UNC(@_)) }
sub d_canonpath { File::Spec->canonpath(_trim_UNC(@_)) }
@@ -38,7 +39,15 @@ sub d_splitpath { File::Spec->splitpath(_trim_UNC(@_)) }
sub path { d_catfile(@_) }
-sub real_path { realpath( d_catfile(@_) ) }
+sub real_path {
+ my $path = d_catfile(@_);
+ #If Cwd's realpath encounters a path which does not exist it returns
+ #empty on linux, but croaks on windows.
+ if (! -e $path) {
+ return;
+ }
+ realpath($path);
+}
sub path_no_verify {
my @nodes = File::Spec->splitpath(d_catdir(@_)); # 0=vol,1=dirs,2=file
@@ -112,11 +121,27 @@ Dancer::FileUtils - helper providing file utilities
=head1 SYNOPSIS
+ use Dancer::FileUtils qw/dirname real_path/;
+
+ # for 'path/to/file'
+ my $dir=dirname ($path); #returns 'path/to'
+ my $real_path=real_path ($path); #returns '/abs/path/to/file'
+
+
use Dancer::FileUtils qw/path read_file_content/;
my $content = read_file_content( path( 'folder', 'folder', 'file' ) );
my @content = read_file_content( path( 'folder', 'folder', 'file' ) );
+
+ use Dancer::FileUtils qw/read_glob_content set_file_mode/;
+
+ open my $fh, '<', $file or die "$!\n";
+ set_file_mode ($fh);
+ my @content = read_file_content($fh);
+ my $content = read_file_content($fh);
+
+
=head1 DESCRIPTION
Dancer::FileUtils includes a few file related utilities related that Dancer
@@ -125,13 +150,24 @@ file reading subroutines or using additional modules.
=head1 SUBROUTINES/METHODS
+=head2 dirname
+
+ use Dancer::FileUtils 'dirname';
+
+ my $dir = dirname($path);
+
+Exposes L<File::Basename>'s I<dirname>, to allow fetching a directory name from
+a path. On most OS, returns all but last level of file path. See
+L<File::Basename> for details.
+
=head2 open_file
use Dancer::FileUtils 'open_file';
my $fh = open_file('<', $file) or die $message;
-Calls open and returns a filehandle. Takes in account the 'charset' setting to
-open the file in the proper encoding.
+Calls open and returns a filehandle. Takes in account the 'charset' setting
+from Dancer's configuration to open the file in the proper encoding (or
+defaults to utf-8 if setting not present).
=head2 path
@@ -141,39 +177,48 @@ open the file in the proper encoding.
Provides comfortable path resolving, internally using L<File::Spec>.
-=head2 dirname
-
- use Dancer::FileUtils 'dirname';
-
- my $dir = dirname($path);
-
-Exposes L<File::Basename>'s I<dirname>, to allow fetching a directory name from
-a path.
-
=head2 read_file_content
use Dancer::FileUtils 'read_file_content';
- my $content = read_file_content($file);
my @content = read_file_content($file);
+ my $content = read_file_content($file);
Returns either the content of a file (whose filename is the input), I<undef>
if the file could not be opened.
-In array context it returns each line (as defined by $/) as a seperate element
-Scalar context returns the entire contents of the file.
+In array context it returns each line (as defined by $/) as a seperate element;
+in scalar context returns the entire contents of the file.
=head2 read_glob_content
use Dancer::FileUtils 'read_glob_content';
open my $fh, '<', $file or die "$!\n";
- my $content = read_glob_content($fh);
my @content = read_glob_content($fh);
+ my $content = read_glob_content($fh);
+
+Same as I<read_file_content>, only it accepts a file handle. Returns the
+content and B<closes the file handle>.
+
+=head2 real_path
+
+ use Dancer::FileUtils 'real_path';
+
+ my $real_path=real_path ($path);
-Same as I<read_file_content>, only it accepts a file handle.
+Returns a canonical and absolute path. Uses Cwd's realpath internally which
+resolves symbolic links and relative-path components ("." and ".."). If
+specified path does not exist, real_path returns nothing.
-Returns the content and B<closes the file handle>.
+=head2 set_file_mode
+
+ use Dancer::FileUtils 'set_file_mode';
+
+ set_file_mode($fh);
+
+Applies charset setting from Dancer's configuration. Defaults to utf-8 if no
+charset setting.
=head1 EXPORT
@@ -185,11 +230,10 @@ Alexis Sukrieh
=head1 LICENSE AND COPYRIGHT
-Copyright 2009-2010 Alexis Sukrieh.
+Copyright 2009-2011 Alexis Sukrieh.
This program is free software; you can redistribute it and/or modify it
under the terms of either: the GNU General Public License as published
by the Free Software Foundation; or the Artistic License.
See http://dev.perl.org/licenses/ for more information.
-
View
2 lib/Dancer/Handler.pm
@@ -98,7 +98,7 @@ sub psgi_app {
sub {
my $env = shift;
$self->init_request_headers($env);
- my $request = Dancer::Request->new($env);
+ my $request = Dancer::Request->new(env => $env);
$self->handle_request($request);
};
}
View
4 lib/Dancer/Handler/Debug.pm
@@ -33,7 +33,7 @@ sub run {
'SERVER_URL' => "http://$host:$port/",
};
- $req = Dancer::Request->new($env);
+ $req = Dancer::Request->new(env => $env);
my $headers = HTTP::Headers->new(
'User-Agent' => 'curl',
@@ -59,7 +59,7 @@ sub start {
my $dancer = Dancer::Handler::Debug->new();
my $psgi = sub {
my $env = shift;
- my $req = Dancer::Request->new($env);
+ my $req = Dancer::Request->new(env => $env);
$dancer->handle_request($req);
};
$dancer->{psgi_app} = $psgi;
View
8 lib/Dancer/Introduction.pod
@@ -166,6 +166,14 @@ You can unset the prefix value
prefix undef;
get '/page1' => sub {}; will match /page1
+Alternatively, to prevent you from ever forgetting to undef the prefix,
+you can use lexical prefix like this:
+
+ prefix '/home' => sub {
+ get '/page1' => sub {}; # will match '/home/page1'
+ }; ## prefix reset to previous value on exit
+
+ get '/page1' => sub {}; will match /page1
=head2 RUNNING THE WEBSERVER
View
3 lib/Dancer/Logger/Abstract.pm
@@ -90,7 +90,8 @@ sub format_message {
? $r->env->{'HTTP_X_REAL_IP'} || $r->env->{'REMOTE_ADDR'}
: '-';
},
- t => sub { Encode::decode(setting('charset'), POSIX::strftime( "%d/%b/%Y %H:%M:%S", localtime )) },
+ t => sub { Encode::decode(setting('charset'),
+ POSIX::strftime( "%d/%b/%Y %H:%M:%S", localtime )) },
T => sub { POSIX::strftime( "%Y-%m-%d %H:%M:%S", localtime ) },
P => sub { $$ },
L => sub { $level },
View
6 lib/Dancer/Logger/File.pm
@@ -47,10 +47,12 @@ sub init {
my $logdir = logdir();
return unless ($logdir);
- my $logfile = setting('environment');
+
+ my $logfile = setting('log_file') || setting('environment').".log";
mkdir($logdir) unless(-d $logdir);
- $logfile = File::Spec->catfile($logdir, "$logfile.log");
+ $logfile = File::Spec->catfile($logdir, $logfile);
+
my $fh;
unless($fh = open_file('>>', $logfile)) {
carp "unable to create or append to $logfile";
View
6 lib/Dancer/MIME.pm
@@ -41,9 +41,9 @@ sub add_type {
sub add_alias {
my($self, $alias, $orig) = @_;
- my $type = $self->for_name($orig) || croak "Can't find a mime type for $orig to alias $alias to";
+ my $type = $self->for_name($orig);
$self->add_type($alias, $type);
- return;
+ return $type;
}
sub for_file {
@@ -62,7 +62,7 @@ sub name_or_type {
sub for_name {
my ($self, $name) = @_;
- return $self->custom_types->{$name} || $self->mime_type->mimeTypeOf(lc $name) || $self->default;
+ return $self->custom_types->{lc $name} || $self->mime_type->mimeTypeOf(lc $name) || $self->default;
}
sub add_mime_type {
View
131 lib/Dancer/Request.pm
@@ -28,7 +28,7 @@ __PACKAGE__->attributes(
'content_type', 'content_length',
'body', 'id',
'uploads', 'headers', 'path_info',
- 'ajax',
+ 'ajax', 'body_is_parsed',
@http_env_keys,
);
@@ -55,9 +55,15 @@ sub script_name { $_[0]->env->{SCRIPT_NAME} }
sub scheme {
my $scheme;
if (setting('behind_proxy')) {
- $scheme = $_[0]->env->{'X_FORWARDED_PROTOCOL'} || $_[0]->env->{'HTTP_FORWARDED_PROTO'}
+ $scheme = $_[0]->env->{'X_FORWARDED_PROTOCOL'}
+ || $_[0]->env->{'HTTP_X_FORWARDED_PROTOCOL'}
+ || $_[0]->env->{'HTTP_FORWARDED_PROTO'}
+ || ""
}
- return $scheme || $_[0]->env->{'psgi.url_scheme'} || $_[0]->env->{'PSGI.URL_SCHEME'};
+ return $scheme
+ || $_[0]->env->{'psgi.url_scheme'}
+ || $_[0]->env->{'PSGI.URL_SCHEME'}
+ || "";
}
sub secure { $_[0]->scheme eq 'https' }
sub uri { $_[0]->request_uri }
@@ -74,29 +80,36 @@ sub request_method { method(@_) }
sub Vars { params(@_) }
sub input_handle { $_[0]->env->{'psgi.input'} || $_[0]->env->{'PSGI.INPUT'} }
-sub new {
- my ($class, $env) = @_;
-
- $env ||= {};
-
- my $self = {
- path => undef,
- method => undef,
- params => {},
- body => '',
- content_length => $env->{CONTENT_LENGTH} || 0,
- content_type => $env->{CONTENT_TYPE} || '',
- env => $env,
- id => ++$count,
- _chunk_size => 4096,
- _read_position => 0,
- _body_params => undef,
- _query_params => undef,
- _route_params => {},
- };
+sub init {
+ my ($self) = @_;
- bless $self, $class;
- $self->_init();
+ $self->{env} ||= {};
+ $self->{path} = undef;
+ $self->{method} = undef;
+ $self->{params} = {};
+ $self->{body} = '';
+ $self->{body_is_parsed} ||= 0;
+ $self->{content_length} = $self->env->{CONTENT_LENGTH} || 0;
+ $self->{content_type} = $self->env->{CONTENT_TYPE} || '';
+ $self->{id} = ++$count;
+ $self->{_chunk_size} = 4096;
+ $self->{_read_position} = 0;
+ $self->{_body_params} = undef;
+ $self->{_query_params} = undef;
+ $self->{_route_params} = {};
+
+ $self->_build_headers();
+ $self->_build_request_env();
+ $self->_build_path() unless $self->path;
+ $self->_build_path_info() unless $self->path_info;
+ $self->_build_method() unless $self->method;
+
+ $self->{_http_body} =
+ HTTP::Body->new($self->content_type, $self->content_length);
+ $self->{_http_body}->cleanup(1);
+ $self->_build_params();
+ $self->_build_uploads unless $self->uploads;
+ $self->{ajax} = $self->is_ajax;
return $self;
}
@@ -113,12 +126,13 @@ sub new_for_request {
$params ||= {};
$method = uc($method);
- my $req = $class->new( { %ENV,
- PATH_INFO => $path,
- REQUEST_METHOD => $method});
- $req->{params} = {%{$req->{params}}, %{$params}};
- $req->{body} = $body if defined $body;
- $req->{headers} = $headers if $headers;
+ my $req = $class->new(env => { %ENV,
+ PATH_INFO => $path,
+ REQUEST_METHOD => $method});
+ $req->{params} = {%{$req->{params}}, %{$params}};
+ $req->{_query_params} = $req->{params};
+ $req->{body} = $body if defined $body;
+ $req->{headers} = $headers if $headers;
return $req;
}
@@ -131,7 +145,7 @@ sub forward {
my $env = $request->env;
$env->{PATH_INFO} = $to_data->{to_url};
- my $new_request = $class->new($env);
+ my $new_request = $class->new(env => $env, body_is_parsed => 1);
my $new_params = _merge_params(scalar($request->params),
$to_data->{params} || {});
@@ -141,6 +155,10 @@ sub forward {
}
$new_request->{params} = $new_params;
+ $new_request->{_body_params} = $request->{_body_params};
+ $new_request->{_query_params} = $request->{_query_params};
+ $new_request->{_route_params} = $request->{_route_params};
+ $new_request->{_params_are_decoded} = 1;
$new_request->{body} = $request->body;
$new_request->{headers} = $request->headers;
@@ -219,8 +237,8 @@ sub params {
my @caller = caller;
if (not $self->{_params_are_decoded}) {
- $self->{params} = _decode($self->{params});
- $self->{_body_params} = _decode($self->{_body_params});
+ $self->{params} = _decode($self->{params});
+ $self->{_body_params} = _decode($self->{_body_params});
$self->{_query_params} = _decode($self->{_query_params});
$self->{_route_params} = _decode($self->{_route_params});
$self->{_params_are_decoded} = 1;
@@ -250,7 +268,7 @@ sub _decode {
my ($h) = @_;
return if not defined $h;
- if (not ref($h)) {
+ if (!ref($h) && !utf8::is_utf8($h)) {
return decode('UTF-8', $h);
}
@@ -287,25 +305,6 @@ sub upload {
return (ref($res) eq 'ARRAY') ? @$res : $res;
}
-# private
-
-sub _init {
- my ($self) = @_;
-
- $self->_build_headers();
- $self->_build_request_env();
- $self->_build_path() unless $self->path;
- $self->_build_path_info() unless $self->path_info;
- $self->_build_method() unless $self->method;
-
- $self->{_http_body} =
- HTTP::Body->new($self->content_type, $self->content_length);
- $self->{_http_body}->cleanup(1);
- $self->_build_params();
- $self->_build_uploads unless $self->uploads;
- $self->{ajax} = $self->is_ajax;
-}
-
# Some Dancer's core components sometimes need to alter
# the parsed request params, these protected accessors are provided
# for this purpose
@@ -353,15 +352,18 @@ sub _build_headers {
sub _build_params {
my ($self) = @_;
-
+
# params may have been populated by before filters
# _before_ we get there, so we have to save it first
my $previous = $self->{params};
# now parse environement params...
$self->_parse_get_params();
- $self->_parse_post_params();
-
+ if ($self->{body_is_parsed}) {
+ $self->{_body_params} ||= {};
+ } else {
+ $self->_parse_post_params();
+ }
# and merge everything
$self->{params} = {
@@ -567,10 +569,21 @@ use the current request object.
=head1 PUBLIC INTERFACE
-=head2 new($env)
+=head2 new()
The constructor of the class, used internally by Dancer's core to create request
-objects. It uses the environment hash table given to build the request object.
+objects.
+
+It uses the environment hash table given to build the request object:
+
+ Dancer::Request->new(env => \%ENV);
+
+It also accepts the C<body_is_parsed> boolean flag, if the new request object should
+not parse request body.
+
+=head2 init()
+
+Used internally to define some default values and parse parameters.
=head2 new_for_request($method, $path, $params, $body, $headers)
View
19 lib/Dancer/Route.pm
@@ -38,6 +38,10 @@ sub init {
croak "cannot create Dancer::Route without a pattern";
}
+ # If the route is a Regexp, store it directly
+ $self->regexp($self->pattern)
+ if ref($self->pattern) eq 'Regexp';
+
$self->check_options();
$self->app(Dancer::App->current);
$self->prefix(Dancer::App->current->prefix) if not $self->prefix;
@@ -252,9 +256,9 @@ sub _init_prefix {
my $prefix = $self->prefix;
if ($self->is_regexp) {
- my $regexp = $self->regexp || $self->pattern;
+ my $regexp = $self->regexp;
if ($regexp !~ /^$prefix/) {
- $self->{pattern} = qr{${prefix}${regexp}};
+ $self->regexp(qr{${prefix}${regexp}});
}
}
elsif ($self->pattern eq '/') {
@@ -278,24 +282,19 @@ sub _init_prefix {
sub equals {
my ($self, $route) = @_;
-
- # TODO remove this hack when r() is deprecated
- my $r1 = $self->regexp || $self->pattern;
- my $r2 = $route->regexp || $route->pattern;
- return $r1 eq $r2;
+ return $self->regexp eq $route->regexp;
}
sub is_regexp {
my ($self) = @_;
- return ($self->pattern && (ref($self->pattern) eq 'Regexp'))
- || $self->regexp;
+ return defined $self->regexp;
}
sub _build_regexp {
my ($self) = @_;
if ($self->is_regexp) {
- $self->{_compiled_regexp} = $self->regexp || $self->pattern;
+ $self->{_compiled_regexp} = $self->regexp;
$self->{_compiled_regexp} = qr/^$self->{_compiled_regexp}$/;
$self->{_should_capture} = 1;
}
View
14 lib/Dancer/Serializer/Mutable.pm
@@ -137,16 +137,18 @@ The default is B<application/json>
=head2 serialize
-Serialize a data structure to a structure. The type of structure depends of the
-request's content-type. For now, it can be one of YAML, XML, JSON.
+Serialize a data structure. The format it is serialized to is determined
+automatically as described above. It can be one of YAML, XML, JSON, defaulting
+to JSON if there's no clear preference from the request.
=head2 deserialize
-Deserialize a YAML structure to a data structure. The type of structure depends of the
-request's content-type. For now, it can be one of YAML, XML, JSON.
+Deserialize the provided serialized data to a data structure. The type of
+serialization format depends on the request's content-type. For now, it can
+be one of YAML, XML, JSON.
=head2 content_type
-Returns the content-type that were used during the last C<serialize> /
+Returns the content-type that was used during the last C<serialize> /
C<deserialize> call. B<WARNING> : you must call C<serialize> / C<deserialize>
-before calling C<content_type>. Otherwise he return value will be C<undef>.
+before calling C<content_type>. Otherwise the return value will be C<undef>.
View
5 lib/Dancer/Session/Abstract.pm
@@ -36,7 +36,10 @@ sub destroy {
confess "destroy not implemented";
}
-
+# does nothing in most cases (exception is YAML)
+sub reset {
+ return;
+}
# This is the default constructor for the session object, the only mandatory
# attribute is 'id'. The whole object should be serialized by the session
View
40 lib/Dancer/Session/YAML.pm
@@ -14,24 +14,31 @@ use File::Temp qw(tempfile);
# static
+my %session_dir_initialized;
+
sub init {
my $self = shift;
$self->SUPER::init(@_);
- croak "YAML is needed and is not installed"
- unless Dancer::ModuleLoader->load('YAML');
+ if (!keys %session_dir_initialized) {
+ croak "YAML is needed and is not installed"
+ unless Dancer::ModuleLoader->load('YAML');
+ }
# default value for session_dir
setting('session_dir' => path(setting('appdir'), 'sessions'))
if not defined setting('session_dir');
- # make sure session_dir exists
my $session_dir = setting('session_dir');
- if (!-d $session_dir) {
- mkdir $session_dir
- or croak "session_dir $session_dir cannot be created";
+ if (! exists $session_dir_initialized{$session_dir}) {
+ $session_dir_initialized{$session_dir} = 1;
+ # make sure session_dir exists
+ if (!-d $session_dir) {
+ mkdir $session_dir
+ or croak "session_dir $session_dir cannot be created";
+ }
+ Dancer::Logger::core("session_dir : $session_dir");
}
- Dancer::Logger::core("session_dir : $session_dir");
}
# create a new session and return the newborn object
@@ -44,6 +51,12 @@ sub create {
return $self;
}
+# deletes the dir cache
+sub reset {
+ my ($class) = @_;
+ %session_dir_initialized = ();
+}
+
# Return the session object corresponding to the given id
sub retrieve {
my ($class, $id) = @_;
@@ -117,6 +130,19 @@ files in /tmp/dancer-sessions
session: "YAML"
session_dir: "/tmp/dancer-sessions"
+=head1 METHODS
+
+=head2 reset
+
+to avoid checking if the sessions directory exists everytime a new session is
+created, this module maintains a cache of session directories it has already
+created. C<reset> wipes this cache out, forcing a test for existence
+of the sessions directory next time a session is created. It takes no argument.
+
+This is particulary useful if you want to remove the sessions directory on the
+system where your app is running, but you want this session engine to continue
+to work without having to restart your application.
+
=head1 DEPENDENCY
This module depends on L<YAML>.
View
1 lib/Dancer/Template/Abstract.pm
@@ -110,6 +110,7 @@ sub _prepare_tokens_options {
$tokens->{settings} = Dancer::Config->settings;
$tokens->{request} = Dancer::SharedData->request;
$tokens->{params} = Dancer::SharedData->request->params;
+ $tokens->{vars} = Dancer::SharedData->vars;
Dancer::App->current->setting('session')
and $tokens->{session} = Dancer::Session->get;
View
10 lib/Dancer/Test.pm
@@ -122,6 +122,11 @@ sub route_doesnt_exist {
# Response status
sub response_exists {
+ Dancer::Deprecation->deprecated(
+ fatal => 0,
+ feature => 'response_exists',
+ reason => 'Use response_status_isnt and check for status 404.'
+ );
my ($req, $test_name) = @_;
$test_name ||= "a response is found for " . _req_label($req);
@@ -135,6 +140,11 @@ sub response_exists {
}
sub response_doesnt_exist {
+ Dancer::Deprecation->deprecated(
+ fatal => 0,
+ feature => 'response_doesnt_exist',
+ reason => 'Use response_status_is and check for status 404.',
+ );
my ($req, $test_name) = @_;
$test_name ||= "no response found for " . _req_label($req);
View
1 t/00_base/003_syntax.t
@@ -31,6 +31,7 @@ my @keywords = qw(
logger
mime
options
+ param
params
pass
path
View
10 t/00_base/11_file_utils.t
@@ -3,15 +3,15 @@ use File::Spec;
use File::Temp;
use Dancer ':syntax';
-use Dancer::FileUtils qw/read_file_content/;
+use Dancer::FileUtils qw/read_file_content real_path/;
use lib File::Spec->catdir( 't', 'lib' );
use TestUtils;
use strict;
use warnings;
-plan tests => 2;
+plan tests => 3;
my $tmp = File::Temp->new();
@@ -22,3 +22,9 @@ ok $content = "one$/two";
my @content = read_file_content($tmp);
ok $content[0] eq "one$/" && $content[1] eq 'two';
+
+# returns UNDEF on non-existant path
+my $path='bla/blah';
+if (! -e $path) {
+ ok (!defined(real_path($path)), 'real_path on non-existant path');
+}
View
21 t/00_base/12_utf8_charset.t
@@ -7,16 +7,17 @@ use Test::More import => ['!pass'];
use Dancer::ModuleLoader;
use LWP::UserAgent;
+plan skip_all => "skip test with Test::TCP in win32" if $^O eq 'MSWin32';
plan skip_all => "Test::TCP is needed for this test"
- unless Dancer::ModuleLoader->load("Test::TCP");
+ unless Dancer::ModuleLoader->load("Test::TCP" => '1.13');
plan tests => 4;
Test::TCP::test_tcp(
client => sub {
my $port = shift;
my $res;
-
+
$res = _get_http_response(GET => '/string', $port);
is d($res->content), "\x{1A9}", "utf8 static response";
@@ -25,7 +26,7 @@ Test::TCP::test_tcp(
$res = _get_http_response(GET => "/param/".u("\x{1A9}"), $port);
is d($res->content), "\x{1A9}", "utf8 route param";
-
+
$res = _get_http_response(GET => "/view?string1=".u("\x{E9}"), $port);
is d($res->content), "sigma: 'Ʃ'\npure_token: 'Ʃ'\nparam_token: '\x{E9}'\n",
"params and tokens are valid unicode";
@@ -36,12 +37,12 @@ Test::TCP::test_tcp(
use Dancer;
use t::lib::TestAppUnicode;
- setting charset => 'utf8';
- setting port => $port;
- set show_errors => 1;
- setting startup_info => 0;
- set 'log' => 'debug';
- set logger => 'console';
+ set( charset => 'utf8',
+ port => $port,
+ show_errors => 1,
+ startup_info => 0,
+ log => 'debug',
+ logger => 'console');
Dancer->dance();
},
@@ -57,7 +58,7 @@ sub d {
sub _get_http_response {
my ($method, $path, $port) = @_;
-
+
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new($method => "http://127.0.0.1:$port${path}");
return $ua->request($req);
View
33 t/00_base/15_dependent_modules.t
@@ -0,0 +1,33 @@
+use strict;
+use warnings;
+
+use Test::More;
+
+unless ( $ENV{RELEASE_TESTING} ) {
+ plan( skip_all => "Author tests not required for installation" );
+}
+
+eval "use Test::DependentModules";
+plan skip_all => "Need Test::DependentModules for this test"
+ if $@;
+
+
+my @modules = qw(
+ Dancer::Plugin::Auth::Twitter
+ Dancer::Plugin::DBIC
+ Dancer::Plugin::Database
+ Dancer::Plugin::FlashMessage
+ Dancer::Plugin::MobileDevice
+ Dancer::Plugin::REST
+ Dancer::Session::Cookie
+ Dancer::Session::Storable
+);
+
+# install them in your perlbrew first
+if ($ENV{CPANM_RUN}) {
+ `cpanm -n --quiet $_` for @modules ;
+}
+
+plan tests => scalar(@modules);
+Test::DependentModules::test_module($_) for @modules;
+
View
7 t/00_base/config.t
@@ -2,15 +2,18 @@ use strict;
use warnings;
use Test::More import => ['!pass'];
-plan tests => 1;
+plan tests => 3;
use Dancer;
use Dancer::Test;
-setting foo => 42;
+set foo => 42;
get '/' => sub { config };
my $res = dancer_response(GET => '/');
is $res->{content}{foo}, 42, "setting is accessible via config";
+is config->{'foo'}, 42, "config works";
+
+is setting('foo'), 42, "setting works";
View
40 t/00_base/optional-module-versions.t
@@ -0,0 +1,40 @@
+use strict;
+use warnings;
+use Test::More import => ['!pass'];
+use Dancer ':syntax';
+
+plan tests => 1;
+
+# This isn't really a test, but simply to produce some diagnosis output showing
+# the versions of various modules in one place. Some modules, e.g. Test::TCP,
+# aren't a dependency, we simply skip tests if it's not available, so if it is
+# available, we don't get told the version in the test report.
+
+my @modules = qw(
+ Test::TCP
+ Test::More
+ JSON
+ Clone
+ Plack
+ XML::Simple
+ HTTP::Parser::XS
+);
+
+for my $module (@modules) {
+ # Just in case this fails for any modules for any reason, catch errors:
+ eval {
+ if (Dancer::ModuleLoader->load($module)) {
+ my $version = $module->VERSION;
+ diag("$module $version loaded successfully");
+ } else {
+ diag("$module is not available");
+ }
+ };
+ if ($@) {
+ diag("Error while checking $module version - $@");
+ }
+}
+
+
+ok(1, "Done checking versions of optional modules");
+
View
7 t/01_config/02_mime_type.t
@@ -1,7 +1,7 @@
use strict;
use warnings;
-use Test::More tests => 7, import => ['!pass'];
+use Test::More tests => 10, import => ['!pass'];
use Dancer ':syntax';
@@ -23,3 +23,8 @@ is($mime->for_name('bar'), 'text/foo', 'mime type bar is found');
is($mime->for_file('foo.bar'), 'text/foo', 'mime type for extension .bar is found');
+is($mime->add_alias(xpto => 'BAR'), 'text/foo', 'mime gets correctly lowercased for user types');
+
+is($mime->add_alias(xpto => 'SVG'), 'image/svg+xml', 'mime gets correctly lowercased for system types');
+
+is($mime->add_alias(zbr => 'baz'), $mime->default, 'alias of unkown mime type gets default mime type');
View
4 t/01_config/06_stack_trace.t
@@ -25,7 +25,7 @@ use Dancer::Template::TemplateToolkit;
is(scalar(@error_lines), 3, "test verbose croak");
like($error_lines[0], qr!^'/not/a/valid/file' doesn\'t exist or not a regular file at!, "test verbose croak");
like($error_lines[1], qr!^\s*Dancer::Template::TemplateToolkit::render\('Dancer::Template::TemplateToolkit', '/not/a/valid/file'\) called at!, "test verbose croak stack trace");
- like($error_lines[2], qr!^\s*eval {...} called at t/01_config/06_stack_trace.t!, "test verbose croak stack trace");
+ like($error_lines[2], qr!^\s*eval {...} called at (?:[.]/)?t/01_config/06_stack_trace.t!, "test verbose croak stack trace");
}
{
@@ -47,5 +47,5 @@ use Dancer::Template::TemplateToolkit;
is(scalar(@error_lines), 3, "test verbose croak");
like($error_lines[0], qr!^'/not/a/valid/file' doesn\'t exist or not a regular file at!, "test verbose croak");
like($error_lines[1], qr!^\s*Dancer::Template::TemplateToolkit::render\('Dancer::Template::TemplateToolkit', '/not/a/valid/file'\) called at!, "test verbose croak stack trace");
- like($error_lines[2], qr!^\s*eval {...} called at t/01_config/06_stack_trace.t!, "test verbose croak stack trace");
+ like($error_lines[2], qr!^\s*eval {...} called at (?:[.]/)?t/01_config/06_stack_trace.t!, "test verbose croak stack trace");
}
View
38 t/02_request/02_get_params.t
@@ -1,38 +0,0 @@
-use Test::More tests => 12;
-
-use strict;
-use warnings FATAL => 'all';
-use Dancer::Request;
-
-$ENV{REQUEST_METHOD} = 'GET';
-$ENV{PATH_INFO} = '/';
-
-for my $separator ('&', ';') {
- $ENV{QUERY_STRING} = join($separator,
- ('name=Alexis%20Sukrieh',
- 'IRC%20Nickname=sukria',
- 'Project=Perl+Dancer',
- 'hash=2',
- 'hash=4',
- 'int1=1',
- 'int2=0'));
-
- my $expected_params = {
- 'name' => 'Alexis Sukrieh',
- 'IRC Nickname' => 'sukria',
- 'Project' => 'Perl Dancer',
- 'hash' => [2, 4],
- int1 => 1,
- int2 => 0,
- };
-
- my $req = Dancer::Request->new(\%ENV);
- is $req->path, '/', 'path is set';
- is $req->method, 'GET', 'method is set';
- ok $req->is_get, "request method is GET";
- is_deeply scalar($req->params), $expected_params, 'params are OK';
- is $req->params->{'name'}, 'Alexis Sukrieh', 'params accessor works';
-
- my %params = $req->params;
- is_deeply scalar($req->params), \%params, 'params wantarray works';
-}
View
36 t/02_request/03_post_params.t
@@ -1,36 +0,0 @@
-use Test::More tests => 7;
-
-use strict;
-use warnings FATAL => 'all';
-use Dancer::Request;
-
-my $body = 'foo=bar&name=john&hash=2&hash=4&hash=6&';
-open my $in, '<', \$body;
-
-my $env = {
- CONTENT_LENGTH => length($body),
- CONTENT_TYPE => 'application/x-www-form-urlencoded',
- REQUEST_METHOD => 'POST',
- SCRIPT_NAME => '/',
- 'psgi.input' => $in,
-};
-
-my $expected_params = {
- name => 'john',
- foo => 'bar',
- hash => [2, 4, 6],
-};
-
-my $req = Dancer::Request->new($env);
-is $req->path, '/', 'path is set';
-is $req->method, 'POST', 'method is set';
-ok $req->is_post, 'method is post';
-my $request_to_string = $req->to_string;
-is $request_to_string, '[#1] POST /';
-
-is_deeply scalar($req->params), $expected_params, 'params are OK';
-is $req->params->{'name'}, 'john', 'params accessor works';
-
-my %params = $req->params;
-is_deeply scalar($req->params), \%params, 'params wantarray works';
-
View
2 t/02_request/04_custom.t
@@ -12,7 +12,7 @@ use Dancer::Request;
'QUERY_STRING' => 'foo=bar&number=42',
);
-my $req = Dancer::Request->new(\%ENV);
+my $req = Dancer::Request->new(env => \%ENV);
is $req->path, '/', 'path is /';
is $req->method, 'GET', 'method is get';
is_deeply scalar($req->params), {foo => 'bar', number => 42},
View
2 t/02_request/04_forward.t
@@ -12,7 +12,7 @@ use Dancer::Request;
'QUERY_STRING' => 'foo=bar&number=42',
);
-my $req = Dancer::Request->new(\%ENV);
+my $req = Dancer::Request->new(env => \%ENV);
is $req->path, '/', 'path is /';
is $req->method, 'GET', 'method is get';
is_deeply scalar($req->params), {foo => 'bar', number => 42},
View
13 t/02_request/06_init_env.t
@@ -5,7 +5,9 @@ use warnings FATAL => 'all';
use Dancer::Request;
-my $custom_env = {
+my $custom_env = {
+ 'SERVER_PORT' => 3000,
+ SERVER_PROTOCOL => 'http',
'QUERY_STRING' => 'foo=bar',
'PATH_INFO' => '/stuff',
'REQUEST_METHOD' => 'GET',
@@ -20,16 +22,21 @@ my $custom_env = {
'HTTP_CONNECTION' => 'keep-alive; keep-alive',
};
my @http_env = grep /^HTTP_/, keys (%$custom_env);
-plan tests => 3 + (2 * scalar(@http_env));
+plan tests => 6 + (2 * scalar(@http_env));
-my $req = Dancer::Request->new($custom_env);
+my $req = Dancer::Request->new(env => $custom_env);
is $req->path, '/stuff', 'path is set from custom env';
is $req->method, 'GET', 'method is set from custom env';
is_deeply scalar($req->params), {foo => 'bar'}, 'params are set from custom env';
+is $req->port, 3000, 'port is ok';
+is $req->protocol, 'http', 'protocol is ok';
+ok !$req->secure, 'not https';
+