我正在尝试为Rails ActionDispatch路由器创建一个类似的路由器,它允许您定义类似于
的路由map.get "/foo", :controller => "Foo", :action => "index"
然后将GET /foo
路由到FooController#index
。使用此结构,您可以使用
map.resources :foos
将调用类似
的方法map.get "/foo", :controller => "Foo", :action => "index"
map.get "/foo/:id", :controller => "Foo", :action => "show"
等等。
在D中,我已经能够找出完成这项工作所需的许多反身代码,但不是全部。在Ruby中,我可以做到:
class Foo
def bar
"FOOO BAR!"
end
end
f = Object.const_get("Foo")
f.new.__send__(:bar) #=> "FOOO BAR!"
我试图将其翻译为
module foo;
import std.stdio;
class Foo {
void bar() {
writeln("FOO BAR!");
}
}
void main() {
auto foo = Object.factory("foo.Foo");
__traits(getMember, foo, "bar");
}
但这不起作用,因为编译器不知道foo
是什么类型,因此在编译期间对#bar
的调用失败。我看到Object.factory
使用的所有地方都将它们转换为特定类型,所以
module foo;
import std.stdio;
class Foo {
void bar() {
writeln("FOO BAR!");
}
}
void main() {
auto foo = cast(Foo) Object.factory("foo.Foo");
__traits(getMember, foo, "bar");
}
会工作得很好。但是,如果我知道我想要将对象转换为使用Object.factory
的好处吗?这对我来说没有任何意义!
更新2 我修复了编译器问题,但现在它在运行时崩溃,说无法找到方法
module foo;
import std.stdio;
class MyDynamic {
void call(C, T...)(C instance, string method, T args) {
foreach(member; __traits(allMembers, C)) {
writeln(member);
if (member == method) {
static if (__traits(compiles, __traits(getMember, instance, member)(args))) {
__traits(getMember, instance, member)(args);
}
return;
}
}
assert(0, "No method found");
}
}
class Foo : MyDynamic {
void bar() {
writeln("FOO BAR!");
}
}
void main() {
auto foo = cast(MyDynamic) Object.factory("foo.Foo");
assert(foo !is null);
foo.call(foo, "bar");
}
更新对于现在提出此问题的任何人,您可以在此处查看我的最终解决方案:https://github.com/jaredonline/action-pack
答案 0 :(得分:5)
我这样做的方法是建立自己的工厂功能和动态调度。使用__traits(allMembers),遍历所有支持的类并获取方法列表。编写一个包装器模板,它接受泛型参数并将它们转换为函数所需的参数。在关联数组中存储对包装函数的引用,或者在接口中使用调度方法来调用它。
当需要完成工作时,创建类(使用自己的包装器,或者也可以使用Object.factory将其转换为动态调度函数的通用接口),然后使用动态函数。如下所示:
// IMPORTANT: Object.factory needs a full name - includes the module and class name!
auto foo = cast(MyDynamic) Object.factory("mymodule.Foo");
assert(foo !is null); // Object.factory can return null if it didn't find the class
// and cast can also return null if it wasn't actually of that interface type, so gotta check
foo.call("my_method", ["arg", "arg2", ...]);
我使用完整示例更新了此链接,如果您在顶部没有看到module dynamicstuff;
则刷新:
http://arsdnet.net/dcode/test46.d
循环allMembers,根据运行时字符串调用。通过循环ModuleInfo,获取实现接口的所有类的列表也是可能的。请参阅示例文件的底部以获取执行此操作的功能。
我的web.d这样做是为了从网络上自动调用功能。冗长,凌乱的代码,但它做了很多。这是包装函数: https://github.com/adamdruppe/misc-stuff-including-D-programming-language-web-stuff/blob/master/web.d#L2538
请注意使用std.traits中的ParameterTypeTuple!func。
我在这里发表了很多评论http://arsdnet.net/dcode/test46.d,希望他们能回答你的问题。该示例简要说明:
你不一定要使用所有这些东西,但我想我会触及所有这些,因为这些对于这些url路由任务都非常有用。