perldancer / dancer Goto Github PK
View Code? Open in Web Editor NEWThe easiest way to write web applications with Perl (Perl web micro-framework)
Home Page: http://perldancer.org/
The easiest way to write web applications with Perl (Perl web micro-framework)
Home Page: http://perldancer.org/
We have template, session and logger engines. Sometimes some engine-specific configuration is needed for them, like the templates start and stop tags, for instance.
What I have in mind would be the following:
Here is an example:
# config.yml
warnings: 1
template: template_toolkit
...
engines:
template_toolkit:
start_tag: '[%'
stop_tag: '%]'
In the template code:
sub some_engine_method {
my ($self, ...) = @_;
...
my $start_tag = $self->settings->{'start_tag'};
}
This reminds me of two things:
Route Caching should support reading and writing from a storable file.
This would help CGI applications make use of the caching to speed up route matching.
The README says nothing about Module::Refresh, and it's needed if you want to use auto_reload (the logs in development mode complain).
I think it would be very useful to have a "before template" filter, to allow template params to be massaged before passing to the template.
One use-case would be wanting to pass e.g. the username of the logged in user to the template, without every handler having to do it. A before-template filter could receive the template name and hashref of params, and make any changes it needs to the params, e.g. as simple as:
before_template sub {
my ($template, $params) = @_;
$params->{logged_in_user} = session->{user};
}
It could also be used to, for instance, automatically HTML-encode all params being passed to the template, to help prevent XSS vulnerabilities. (In fact, having that as a built-in ability enabled by a config setting could be useful to help people protect themselves, and as a "built-in XSS protection" feature to list on "marketing" pages :) )
This issue is just a test, to see if it gets reported to the IRC channel properly.
#!/opt/local/bin/perl -w
use warnings;
use strict;
use Dancer;
get '/hi' => sub {
"Hello World!"
};
dance;
$ ./dancer.pl --port=4123
>> Dancer server 32660 listening on http://0.0.0.0:3000
== Entering the development dance floor ...
$ ./dancer.pl --daemon
>> Dancer server 32677 listening on http://0.0.0.0:3000
== Entering the development dance floor ...
As asked on Twitter, it would be great to be able to declare a route handler with multiple HTTP method at one time, like the following:
any ['get', 'post'] => '/action' => sub {
};
Maybe we could also implement the following as well:
any '/action' => sub {
};
Which would define '/action' for all HTTP methods
If you are under the development environement, with the auto_reload flag set, and that a route script is loaded with the "load" (or require) keyword, you are vulnerable to the following bug:
As soon as the .pl file that contains routes is touched (while the server is running) Module::Refresh will reload it. But it will fail during compilation time because Dancer won't be loaded then, by the Module::Refresh process:
syntax error at foo.pl line 1, near "get '/foo'"
Compilation failed in require at /usr/local/share/perl/5.10.0/Module/Refresh.pm line 119.
I suppose the fix should be just to import Dancer whenever Module::Refresh has to come into play.
Dancer should provide a cookbook about deployment. This documentation should describe as many deployment facilities as possible:
Webserver configuration examples are welcome as well (Apache, Nginx, Lighttpd, ...)
Currently, if no port is specified, we default to trying 3000, and die if that port is already in use.
I think that if the user didn't specify a port, we should start at port 3000, and try successively higher ports until we find an unused one to listen on.
If the user hasn't said what port they want it on, I'd take that as a "I don't care, just start the app and show me the link I can use to get to it", in which case automatically selecting the first available port would be a benefit.
Looks like the request is badly interpreted when a send_file is done under an Apache2/mod_perl environment. The path from the initial query is kept instead of reading the one asked by send_file.
Maybe we could look at that issue when the CGI.pm removal is done.
The hash "params" contains values received from the client, but is also populated by named tokens in the route, in the way that these tokens overwrite query params.
This is convinient in some cases, also there is no "right way" to get all received parameters, because keys %{ params() } doesn't seem to be right.
Dancer::SharedData->cgi does the job, but it's not expected to be called from outside Dancer's core.
We need a way to do it in a clean way. I think that all we need to do is to add an helper in Dancer's syntax like the following:
sub client_params { Dancer::ShareData->cgi->params } or something alike.
Maybe we can also add route_params as well, which would make params to be just a merge between those two.
On the psgi-refactor branch I am able to connect to the development server using 127.0.0.1:3000, but when I connect from a different host using $hostname:3000, it times out. This worked fine on the latest release, but it appears to be brokem on psgi-refactor.
It would be nice to include a favicon.ico in a default Dancer app.
It mildly bugged me to see my debug log being filled with failed requests for /favicon.ico thanks to my browser - it'd be nice if there was already a basic favicon.ico in public/, which the user can replace if they want.
(It'd also make it clear to them how to do it, in case they struggled :) )
Dancer::Route::Cache should enforce the size_limit and path_limit, so the cache won't get too big.
Catching compilation-time warnings brings more evil than good, it should be removed from Dancer::Route.
This being done, a lot of warnings will appear in the test suite, they all should be fixed.
It's entirely likely that users will have e.g. database connection passwords in their app config files; the config dump on the error page produced with show_errors on would happily display that password.
When displaying the config dump, any field matching e.g. /pass(wd|word)?$/ should probably be "censored" to stop password details being leaked.
(Of course, sensitive info could still get out, so the documentation should make it clear that show_errors should never be enabled in a production environment, but this would be a simple tweak to help improve security a bit)
With regards to:
http://github.com/damog/Dancer/commit/ca82c792fe8af6e557fb690befc843cb1cc29b66
I tried adding a comment on the thread but GitHub wouldn't let me :\
Anyway, I'm not sure I follow. I had made the table to be code => status line to not repeat the code on the status line. When looping through the $HTTP_CODES list, the aliases are populated using the code on the key of the hash reference, line 30:
$HTTP_CODE->{$alias} = $code . ' ' . $HTTP_CODES->{$code};
Which becomes something like $HTTP_CODE->{internal_server_error} = '500 Internal Server Error';
I believe your changes break this. After pulling your latest push, the code number is printed duplicated:
$ curl -I http://localhost:3000/throw_error
HTTP/1.0 500 500 Internal Server Error
The session support is lacking in Dancer, and that is a blocker for 1.0, it should provide the following syntax sugar:
post '/login' => sub {
# ...
session user_id => params->{user_id};
};
get '/home' => sub {
if (session->{user_id}) {
# ....
}
};
I've used CGI::Session before and I think it could be a good module to use for that.
Oh, and of course, session support should be optional in Dancer, so we need a configuration variable too, named "session", that enable the session engine or not, and if so, try to loads dynamically the CGI::Session module, triggering an error if it's not installed.
Dancer::Cookies requires %ENV so it's not PSGI-compatible. Dancer apps run via app.psgi do not support cookies as a result. I don't see a clean way for Dancer::Cookies to get data from Dancer::Request right now so I'll write this as an issue. It's kinda serious too.
A serializer could be defined like the following:
set serializer => 'JSON';
or
set serializer => 'data_dumper';
When defined, the serializer is used for rendering route action whose return value is a data ref (ARRAY or HASH).
This would allow the following code:
get '/data' => sub {
return { foo => 'bar' };
};
The response would then be:
When using Dancer, it sets the app settings. This renders the app non-working when used by files in a deeper hierarchy or a different folder altogether.
One solution is for import not to set the settings unless asked explicitly
Another solution would be to check if they were already set, and not set them again.
Yet another solution would be to allow parameters to import() to check if to do the settings.
My solution was to create a new subroutine, "import_clean":
http://github.com/xsawyerx/Dancer/commit/b7cc27b02eb2a478819120a710771d90ce73e0af
I've also added documentation, but basically the deep hierarchy file just does this:
package App::People::Child;
BEGIN {
use Dancer ();
Dancer->import_clean;
}
The solution to change the import() subroutine and make it smarter is the most elegant in usage, but not necessarily in implementation.
The INCLUDE_PATH for TemplateToolkit is not being set, which means you can't have something like <% INCLUDE header.html %> inside of your template even if header.html is a file in appdir/views.
The following is not being executed in Dancer::Template::TemplateToolkit::init:
$tt_config->{INCLUDE_PATH} = path($self->{settings}{'appdir'}, 'views')
if $self->{settings} && $self->{settings}{'appdir'};
Because when that init is called, $self->{settings} does not exist. Sukria thought that this issue may occur because some settings get initialized before others. Another possibility is that an engine is not supposed to have a 'settings' attribute.
Both t/08_session/03_http_requests.t and t/09_cookies/03_persistence.t have warnings on Win32 because they use $ENV{HOME} which usually isn't defined.
File::MimeInfo::Simple is used by Dancer for mime-types resolution. It depends on Perl 5.10 and is required by Dancer as a mandatory dependency.
We already have a static mimeinfo database in Dancer::FileUtils, so why requiring this restrictive module ? I think we should make it optional.
The template module Dancer::Template::Simple
does not behave well if specified start_tag
and end_tag
are the same.
The dancer
script uses __
as start_tag
and end_tag
and the following files are broken/incomplete :
Also, using a start_tag
containing a [
character triggers the following error :
<Unmatched [ in regex; marked by <-- HERE in m/[ <-- HERE _(\S)/ at /usr/local/share/perl/5.10.0/Dancer/Template/Simple.pm line 34.>
Detected in version: 1.000, installed from CPAN.
I produced a patch correcting these issues agains the github sources : http://loin.ploup.net/~naz/pub/dancer_tags.diff
It might be a useful feature if the Dancer helper script checked whether the version of Dancer installed is the latest released version, and informed the user if not.
I'd say a quick HTTP request to an URL at which we publish the latest version number, with a timeout of say 2 seconds, so if network connectivity is unavailable or that URL is temporarily unavailable, they don't get left waiting.
If it's not the latest version, the script should go ahead anyway, but print a message, maybe something like:
Note: The latest Dancer release is $x, you are currently running $y. You might want to check $url for new features which may be useful to you in your new app :)
It would also be interesting to perhaps have it send the Perl version and Dancer version in the request, and log this, to get an idea of how often Dancer is being used, and what environments it's being run in :)
On the standard error page (with show_errors on), there's a dump of the config, but it only includes top-level stuff; if there's nested config, you see e.g.
engines : HASH(0x8e606a0)
It'd be nice if it could pretty-print the whole lot, maybe even getting clever with a little Javascript to create a "tree" with default stuff like engines, mime_types etc "folded" by default.
The current default behavior is to generate an app named "webapp" directly, this can possibly clobber the currently existing "webapp" directory of file. If not, it leads to a big confusion.
My first experience of running it is weird:
% dancer
- ./webapp
- webapp/views
...
Confused. Do it again
%dancer
./webapp
webapp/views
! webapp/views/index.tt exists, overwrite? [N/y/a]:
Realized that it generates "webapp" dir.
If the help message (-h) displayed by default, not only such confusion can be eliminated, but also it guides the user the "-a" arg that actually generates the app among other choices. Everything gets clearer because of that.
The problem raise with Windows XP and active state perl 5.10 by installation with cpan tool.
See my standard output below.
Sukria don't hesitate to ask me some logs.
cpan> install Dancer
Running install for module 'Dancer'
Running make for S/SU/SUKRIA/Dancer-0.9905.tar.gz
Has already been unwrapped into directory C:\Perl\cpan\build\Dancer-0.9905-wJd
KpR
Has already been made
Running make test
Microsoft (R) Program Maintenance Utility Version 1.50
Copyright (c) Microsoft Corp 1988-94. All rights reserved.
C:\Perl\bin\perl.exe -MExtUtils::Command -e cp script/dancer blib\script
\dancer
pl2bat.bat blib\script\dancer
C:\Perl\bin\perl.exe "-MExtUtils::Command::MM" "-e" "test_harness(0, 'bl
ib\lib', 'blib\arch')" t/00_base/001_load.t t/00_base/002_strict_and_warnings.t
t/00_base/003_syntax.t t/00_base/004_args.t t/01_config/01_settings.t t/01_confi
g/02_mime_type.t t/01_config/03_logger.t t/01_config/04_config_file.t t/02_http_
request/001_basic_request.t t/02_http_request/002_head_request.t t/03_route_hand
ler/00_http_methods.t t/03_route_handler/01_params.t t/03_route_handler/02_befor
e_filter.t t/03_route_handler/03_passing.t t/03_route_handler/04_wildcards.t t/0
3_route_handler/05_error_catching.t t/03_route_handler/06_regexp.t t/03_route_ha
ndler/07_compilation_warning.t t/03_route_handler/08_errors.t t/04_static_file/0
01_base.t t/04_static_file/002_mime_types.t t/05_views/001_settings.t t/05_views
/002_view_rendering.t t/05_views/03_layout.t t/06_helpers/01_send_file.t t/06_he
lpers/02_http_status.t t/06_helpers/03_content_type.t t/06_helpers/04_status.t t
/07_apphandlers/01_base.t t/07_apphandlers/02_apache2_plack.t
t/00_base/001_load...........................ok
t/00_base/002_strict_and_warnings............ok
t/00_base/003_syntax.........................ok
t/00_base/004_args...........................ok
t/01_config/01_settings......................ok
t/01_config/02_mime_type.....................ok
t/01_config/03_logger........................ok
t/01_config/04_config_file...................ok
t/02_http_request/001_basic_request..........dubious
Test returned status 2 (wstat 512, 0x200)
after all the subtests completed successfully
t/02_http_request/002_head_request...........Terminating on signal SIGINT(2)
NMAKE : U1058:
Stop.
Caught SIGINT, trying to continue
SUKRIA/Dancer-0.9905.tar.gz
nmake test -- NOT OK
//hint// to see the cpan-testers results for installing this module, try:
reports SUKRIA/Dancer-0.9905.tar.gz
Failed during this command:
SUKRIA/Dancer-0.9905.tar.gz : make_test NO
Could be great to have something like:
ajax '/some_action' => sub {
...
return { some => 'data };
};
This would actually be some syntactic sugar for:
post '/some_action', { XMLHttpRequest => 1 } => sub {
...
return { some => 'data };
};
Given that Dancer::Route is patched to allow the user to put any Dancer::Request attribute in the conditional hash of the route handler.
In Dancer::Request we have:
sub remote_address {
$_[0]->env->{'X_FORWARDED_FOR'} || $_[0]->env->{'REMOTE_ADDR'};
}
Which is either bad or incomplete. The complete solution would be to do as Catalyst does: http://search.cpan.org/src/FLORA/Catalyst-Runtime-5.80020/lib/Catalyst/Engine/CGI.pm
But in the meantime, I think it's best to let the user deal with it theirselves and provide both accessors ->remote_address and ->forwarded_for_address
I think it'd be nice to add a 'config' method to allow apps to access information from the config file, for instance:
get '/foo' => sub {
return "This is " . config->{appname};
};
Should be dead-simple to implement!
take a look on my nmake standard output
C:\Perl\bin\perl.exe -MExtUtils::Command -e cp script/dancer blib\script\dancer
pl2bat.bat blib\script\dancer
C:\Perl\bin\perl.exe "-MExtUtils::Command::MM" "-e" "test_harness(0, 'blib\lib', 'blib\arch')" t/00_base/001_load.t t/00_base/002_strict_and_warnings.t t/00_base/003_syntax.t t/00_base/004_args.t t/00_base/005_module_loader.t t/00_base/06_dancer_object.t t/01_config/01_settings.t t/01_config/02_mime_type.t t/01_config/03_logger.t t/01_config/04_config_file.t t/01_config/yaml_dependency.t t/02_http_request/001_basic_request.t t/02_http_request/002_head_request.t t/03_route_handler/00_http_methods.t t/03_route_handler/01_params.t t/03_route_handler/02_before_filter.t t/03_route_handler/03_passing.t t/03_route_handler/04_wildcards.t t/03_route_handler/05_error_catching.t t/03_route_handler/06_regexp.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/10_merge_registries.t t/03_route_handler/11_redirect.t t/03_route_handler/12_response.t t/04_static_file/001_base.t t/04_static_file/002_mime_types.t t/04_static_file/03_get_mime_type.t t/04_static_file/04_file_mimeinfo_simple.t t/05_views/001_settings.t t/05_views/002_view_rendering.t t/05_views/03_layout.t t/06_helpers/01_send_file.t t/06_helpers/02_http_status.t t/06_helpers/03_content_type.t t/06_helpers/04_status.t t/06_helpers/05_send_error.t t/06_helpers/06_load.t t/07_apphandlers/01_base.t t/07_apphandlers/02_apache2_plack.t t/07_apphandlers/03_psgi_app.t t/07_apphandlers/04_standalone_app.t t/08_session/01_load.t t/08_session/02_dependency_check.t t/08_session/03_http_requests.t t/08_session/04_api.t t/09_cookies/01_use.t t/09_cookies/02_cookie_object.t t/09_cookies/03_persistence.t t/09_cookies/04_has_changed.t t/09_cookies/05_api.t t/10_template/01_factory.t t/10_template/02_abstract_class.t t/10_template/03_simple.t t/10_template/05_template_toolkit.t t/11_logger/01_abstract.t t/11_logger/02_factory.t t/11_logger/03_file.t t/11_logger/04_syslog.t
t/00_base/001_load...........................ok
t/00_base/002_strict_and_warnings............ok
t/00_base/003_syntax.........................ok
t/00_base/004_args...........................ok
t/00_base/005_module_loader..................ok
t/00_base/06_dancer_object...................ok
t/01_config/01_settings......................ok
t/01_config/02_mime_type.....................ok
t/01_config/03_logger........................ok
t/01_config/04_config_file...................ok
t/01_config/yaml_dependency..................ok
t/02_http_request/001_basic_request..........ok
t/02_http_request/002_head_request...........ok
t/03_route_handler/00_http_methods...........ok
t/03_route_handler/01_params.................ok
t/03_route_handler/02_before_filter..........ok
t/03_route_handler/03_passing................ok
t/03_route_handler/04_wildcards..............ok
t/03_route_handler/05_error_catching.........ok
t/03_route_handler/06_regexp.................ok
t/03_route_handler/07_compilation_warning....ok
t/03_route_handler/08_errors.................ok
t/03_route_handler/09_status.................ok
t/03_route_handler/10_merge_registries.......ok
t/03_route_handler/11_redirect...............ok
t/03_route_handler/12_response...............ok
t/04_static_file/001_base....................ok
t/04_static_file/002_mime_types..............dubious
Test returned status 1 (wstat 256, 0x100)
DIED. FAILED test 4
Failed 1/9 tests, 88.89% okay
t/04_static_file/03_get_mime_type............ok
t/04_static_file/04_file_mimeinfo_simple.....dubious
Test returned status 1 (wstat 256, 0x100)
DIED. FAILED test 4
Failed 1/4 tests, 75.00% okay
t/05_views/001_settings......................ok
t/05_views/002_view_rendering................ok
t/05_views/03_layout.........................ok
t/06_helpers/01_send_file....................ok
t/06_helpers/02_http_status..................ok
t/06_helpers/03_content_type.................ok
t/06_helpers/04_status.......................ok
t/06_helpers/05_send_error...................ok
t/06_helpers/06_load.........................ok
t/07_apphandlers/01_base.....................ok
t/07_apphandlers/02_apache2_plack............ok
t/07_apphandlers/03_psgi_app.................skipped
all skipped: Test::Requires and Test::TCP are needed for this test
t/07_apphandlers/04_standalone_app...........skipped
all skipped: Test::Requires and Test::TCP are needed for this test
t/08_session/01_load.........................ok
t/08_session/02_dependency_check.............ok
t/08_session/03_http_requests................skipped
all skipped: Test::Requires needed for this test
t/08_session/04_api..........................ok
t/09_cookies/01_use..........................ok
t/09_cookies/02_cookie_object................ok
t/09_cookies/03_persistence..................skipped
all skipped: Test::Requires needed for this test
t/09_cookies/04_has_changed..................ok
t/09_cookies/05_api..........................ok
t/10_template/01_factory.....................ok
t/10_template/02_abstract_class..............ok
t/10_template/03_simple......................ok
t/10_template/05_template_toolkit............ok
t/11_logger/01_abstract......................ok
t/11_logger/02_factory.......................ok
t/11_logger/03_file..........................ok
t/11_logger/04_syslog........................skipped
all skipped: Sys::Syslog needed for this test
t/04_static_file/002_mime_types.t 1 256 9 1 4
t/04_static_file/04_file_mimeinfo_simple. 1 256 4 1 4
5 tests skipped.
Failed 2/60 test scripts. 2/368 subtests failed.
Files=60, Tests=368, 26 wallclock secs ( 0.00 cusr + 0.00 csys = 0.00 CPU)
How do you feel about adding exception support to Dancer?
This would be useful in helpers like redirect and other methods that we'd start porting. The exceptions could be thrown to halt the execution of routes, or transfer them to another handler or route, etc.
Exception::Class is a very neat module, but it may add dependencies overload to Dancer, which is maybe not desirable, how do you feel about that?
I'd go for Exception::Class instead of Error.pm since the former is more mature and the recent maintainer does not advocate its use anymore.
Depending on your comments I could work on it and propose a patch branch.
in my opinion, the development dance floor should allow the developer to reload the changes from disk on files without restarting the devel server.
When an application is scaffolded it contains an app.psgi file. that's OK, but it could be even better to provide a file named dispatch.cgi which would use Plack::Loader (IIRC).
This would allow a user to put configure very easily their application under a CGI/Fast-CGI environement (with Plack).
Dancer at present expects the YAML config file and environmental config to be in the same folder as the application and a folder named "environments", respectively. What I'd like to is to have this behavior as a default and allow for the locations of configuration files to be user-definable.
I'm not 100% sure on how to go about this, either something like calling it in the application as a setting:
set config_yaml => '/path/to/config.yml';
or as an argument (somehow similar to --environment is used).
Thanks.
If I use redirect to redirect to an URL with a query string, e.g.
redirect '/login?failed=1';
then the URL gets passed to uri_for() which ends up URL-encoding it, so I get redirected to, for instance,
http://supernova:8420/login%3Ffailed=1
uri_for accepts a hashref of params for the query string, perhaps redirect should accept that too, so you could do e.g.
redirect '/login', { failed => 1 };
That would be one solution, although it still leaves the potential confusion of "here's the URL, leave the bloody thing alone and just redirect to it" (turning it into an absolute URL for the Location header to be RFC-compliant is correct behaviour, but I'm not sure automatically URL-encoding it is...)
Thoughts?
Dancer::Request calls CGI::Vars.
CGI::Vars doesn't return an arrayref, which is not only NOT DWIM, but also it's incompatible with what happens with you run Dancer using Plack (on Apache, for instance).
Instead, CGI::Vars returns a string and you need to parse with split /\0/, ...[1].
It bit me good on a new project.
[1]http://search.cpan.org/~lds/CGI.pm-3.49/lib/CGI.pm#FETCHING_THE_PARAMETER_LIST_AS_A_HASH:
Take the following Dancer-App:
get '/redirect' => sub {
header 'X-Foo' => 'foo';
redirect '/';
};
get '/' => sub {
template 'index';
};
This happens:
$ curl -I http://localhost:3000/redirect
HTTP/1.0 302 Found
Location: /
X-Powered-By: Perl Dancer 1.130
My current workaround:
get '/redirect' => sub {
header 'X-Foo' => 'foo';
header 'Location' => '/';
status '302';
return "";
};
As illustrated in http://gist.github.com/332951, non-true params seem to get dropped.
When reading this blog post http://vti.showmetheco.de/articles/2010/02/using-jquery-and-ajax-in-mojolicious.html
I came across that code snipet, in Mojo::Lite:
# AJAX request
if ($header && $header eq 'XMLHttpRequest') {
$self->render_json({answer => "Hello from AJAX!"});
}
And I wondered how great it could be to have in Dancer's syntax somthing like:
if (request->is_ajax) {
...
}
This would be IMO simple to implement.
Also what about request->headers->{'X-Request-Header-Foo'} ...
I was thinking of another feature - a setting e.g. auto_pages or something, which would take requests which didn't match any specific route, and look for a template in the specified directory, and if found, use it to satisfy the request.
For instance, given:
auto_pages => 'views/pages',
If a request for /foo/bar is received, and no specific route matches /foo/bar, look for views/pages/foo/bar.tt; if found, output it as though there was a route which just did template 'views/pages/foo/bar';
My use-case: building websites where there are some dynamic sections, and quite a few plain pages.
I don't really want to have to create routes for all the plain pages, but in order to make use of the template engine for the layout, I'd need to.
I can do something like:
for my $page (qw(/foo/bar /foo/wibble)) {
route $page => sub { template $page => {} };
}
But, it would be nice not to have to :)
Thoughts, anyone?
This is because of Dancer::Logger::File
Dancer::Request lacks support for file uploads.
This is mandatory before we release Dancer 1.2
Now that Dancer is all-the-way PSGI-compatible, we should not have so much code for handlers. This should be refactored to allow less code, and less confusion for the end-user when they want to deploy under Plack or as a standalone server.
The app.psgi file is maybe also avoidable.
Ideally, Dancer should be able to detect automatically if it's running under Plack or not, and choose the appropriate handler by itslef, without needing a setting for that (apphandler).
This can be done easily with last versions of Plack which sets up PLACK_ENV. Remains to see what to do for old-fashioned plack envs (maybe SetEnv DANCER_HANDLER "PSGI"?).
Support for the 'delete' method would be great. This is necessary for people wanting to use Dancer to build restful webapps. Doesn't seem like this would be too hard. Could just adding the following line to Dancer.pm do it:
sub delete { Dancer::Route->add('delete', @_) }
CGI is a pain. It would be great to handle request 100% with Dancer::Request and to drop CGI out of the dependecy box.
This would provide, as a side-effect, a smaller app.psgi syntax (CGI::PSGI won't be needed anymore).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.