Currently I'm using Vibe.d to make a website, which has a Response
class that's handed to every request. That looks something like this:
import vibe.d;
void index(HTTPServerRequest req, HTTPServerResponse res)
{
res.render!("index.dt", req);
}
shared static this()
{
auto router = new URLRouter;
router.get("/", &index);
auto settings = new HTTPServerSettings;
settings.port = 8080;
listenHTTP(settings, router);
}
In the example, I'm passing a const string
"index.dt
to the res.render!
method, but I want to pass a variable:
void render(string action, HTTPServerResponse res) {
res.render!(action);
}
But I get the following error:
Error: variable action cannot be read at compile time
In every spot I'm calling render
, I've hardcoded strings:
render("foo.dt");
But that doesn't satisfy the compiler. Any idea how I can make this work?
While using a run time variable is not possible as a matter of principle (that would basically require compiling D code at run time), you could use a compile time defined enum
constant or template parameters to avoid using the string constants directly:
void index(string templ)(HTTPServerRequest req, HTTPServerResponse res)
{
res.render!(templ, req);
}
shared static this()
{
// ...
router.get("/", &index!"index.dt");
// BTW, this special case is equal to
//router.get("/", staticTemplate!"index.dt");
// ...
}
or using an enum
:
enum indexTemplateFile = "index.dt";
void index(HTTPServerRequest req, HTTPServerResponse res)
{
res.render!(indexTemplateFile, req);
}
This alternative form of using a named enum
can also be used:
enum TemplateFile {
index = "index.dt",
login = "login.dt"
}
void index(HTTPServerRequest req, HTTPServerResponse res)
{
res.render!(TemplateFile.index, req);
}
Both of these approaches can also be combined and the constants can even be modified with the usual string operations, as long as the result can still be computed at compile time (e.g. it is possible to call something like std.string.toLower
on the string before passing it to render
).