On Tuesday, 18 March 2014 at 21:56:32 UTC, Chris Williams wrote:
import fs = std.file;
import std.stdio;
template gotoPath(alias path) {
enum gotoPath = q{
string currPath = fs.getcwd();
scope (exit) fs.chdir(currPath);
fs.chdir(path);
};
This is just a string. The occurence of "path" in it has no
relation to the template parameter path. "path" is mixed in
literally. The template parameter is unused.
}
void doStuff(string targetDirectory) {
mixin(gotoPath!(targetDirectory));
writefln("b %s", fs.getcwd());
}
void main() {
writefln("a %s", fs.getcwd());
doStuff("/etc");
writefln("c %s", fs.getcwd());
}
When I try to compile (DMD 2.064), I get the following error:
test.d(16): Error: undefined identifier path
You can pass the variable name as a string:
import std.string: format;
template gotoPath(string pathVar) {
enum gotoPath = format(q{
...
fs.chdir(%s);
}, pathVar);
}
...
mixin(gotoPath!"targetDirectory");
Or you can get the variable name from the alias parameter:
import std.string: format;
template gotoPath(alias path) {
enum gotoPath = format(q{
...
fs.chdir(%s);
}, path.stringof);
}
I think I've read that .stringof shouldn't be used for code
generation, but I can't think of anything better.
Then there's the struct destructor version:
struct GotoPath
{
private string currPath;
this(string path)
{
currPath = fs.getcwd();
fs.chdir(path);
}
~this()
{
fs.chdir(currPath);
}
}
Ideally, it would be used like this:
with(GotoPath(targetDirectory)) writefln("b %s",
fs.getcwd());
which would be beautiful, if you ask me. But a compiler bug [1]
ruins that. You can still use it with a dummy variable:
auto dummy = GotoPath(targetDirectory);
writefln("b %s", fs.getcwd());
[1] https://d.puremagic.com/issues/show_bug.cgi?id=8269