I'm trying to make Router::Resource work where the parameters to the functions are not literal anonymous subs, but coderefs defined earlier. I am doing this to curtail code duplication.
Here's the code from the synopsis in a minimal but working fashion. This works.
# app.psgi
use 5.024;
use Router::Resource qw(resource router GET POST);
my $app = sub {
my ($env) = @_;
my $router = router {
resource '/' => sub {
GET { [200, [], ['get /']] };
};
resource '/blog/{year}/{month}' => sub {
GET { [200, [], ['get /blog']] };
POST { [200, [], ['post /blog']] };
};
};
$router->dispatch($env);
}
__END__
$ plackup &
$ http -b :5000
127.0.0.1 - - [17/Apr/2017:14:25:28 +0200] "GET / HTTP/1.1" 200 5 "-" "HTTPie/0.9.2"
get /
$ http -b :5000/blog/2017/4
127.0.0.1 - - [17/Apr/2017:14:26:15 +0200] "GET /blog/2017/4 HTTP/1.1" 200 9 "-" "HTTPie/0.9.2"
get /blog
$ http -b POST :5000/blog/2017/4
127.0.0.1 - - [17/Apr/2017:14:26:28 +0200] "POST /blog/2017/4 HTTP/1.1" 200 10 "-" "HTTPie/0.9.2"
post /blog
$ pkill -f plackup
After changing the inner PSGI code from a literal anonymous to a coderef, thus:
my $get_root = sub { [200, [], ['get /']] };
⋮
resource '/' => sub {
GET $get_root;
};
Then the program will not compile anymore:
$ perl -c app.psgi
Type of arg 1 to Router::Resource::GET must be block or sub {} (not private variable) at app.psgi line 8, near "$get_root;"
The function prototype is GET(&). When & is the first position, it allows the caller to use the abbreviated syntax, sort of like with sort { … } @list and map { … } instead of sort sub { … }, @list etc., see perlsub#Prototypes:
An
&requires an anonymous subroutine, which, if passed as the first argument, does not require thesubkeyword or a subsequent comma.
How can I use coderefs instead literal subs when there is a prototype?
Options:
Bypass the prototype.
&GET($get_root)
Provide a BLOCK as requested by the error message.
GET { $get_root->(@_) }
Provide a sub { } as requested by the error message.
GET(sub { $get_root->(@_) })
Use something that starts with \&. (Undocumented)
GET(\&$get_root)
GET \&$get_root seems to work.
For a more complicated expression like what you refer to in the comments, you can use
GET \&{$get_generic->('get /')}
The \&{...} operation coerces its contents to a code reference that is suitable to use with a & prototype. Likewise, you can use @{[...]} and %{{...}} in contexts where you want to workaround a \@ or \% prototype.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With