Use Object.factory without needing to cast to a specific type

Viewed 480

I'm trying to create a similar router to Rails ActionDispatch router, which allows you to define a route similar to

map.get "/foo", :controller => "Foo", :action => "index"

which will then route GET /foo to FooController#index. With this structure in place you can use methods like

map.resources :foos

which will call methods like

map.get "/foo", :controller => "Foo", :action => "index"
map.get "/foo/:id", :controller => "Foo", :action => "show"

and so on.

In D, I've been able to figure out a lot of the reflexive code required to make this work, but not all of it. In Ruby I can do:

class Foo
  def bar
    "FOOO BAR!"
  end
end

f = Object.const_get("Foo")
f.new.__send__(:bar) #=> "FOOO BAR!"

Which I've tried to translate to

module foo;
import std.stdio;

class Foo {
  void bar() {
    writeln("FOO BAR!");
  }
}

void main() {
  auto foo = Object.factory("foo.Foo");
  __traits(getMember, foo, "bar");
}

But that doesn't work because the compiler doesn't know what type foo is, so the call to #bar fails during compile. Everywhere I've seen Object.factory used they cast it to a specific type, so

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");
}

would work just fine. But if I know what I want to cast the object to what good is using Object.factory? That doesn't make any sense to me!

UPDATE 2 I've fixed compiler issues, but now it's crashing at runtime, saying it couldn't find the method

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");
}

Update For anyone coming to this question now, you can see my final solution here: https://github.com/jaredonline/action-pack

1 Answers
Related