Accessing a Module's Classes from C# with dynamic

Hey guys.

I am currently experimenting with IronRuby as an extensibility solution
for my application. However, I have hit a roadblock. What I would like
to do is call Runtime.UseFile(“script.rb”), then access a global module
in the script, and instantiate a specific class in that module.

Here is the script file for reference:
module RbScriptApp
class Foo
def Bar()
return (rand(100) + 1).to_s();
end
end
end

Initially, I thought it would be as easy as typing
dynamic globals = myRuntime.Globals;
dynamic myClass = globals.RbScriptApp.Foo.@new();
myClass.Bar();

but I soon found out this was not the case, as the builtin RubyModule
class does not support this dynamic syntax. Is there a way around this
or is it just plain impossible? I was unable to find any information
about how to do this (not even about RubyModule itself!) through Google.

The exception in question is a RuntimeBinderException:
‘IronRuby.Builtins.RubyModule’ does not contain a definition for ‘Foo’

Right now my workaround is a call to RubyModule.EnumerateConstants and
manual lookup of the class name I want, but it doesn’t have the
syntactic elegance of the dynamic keyword… Any thoughts?

EDIT: Just thought I’d add, I’d like to stay away from Engine.Execute()
if at all possible, unless someone can give me a reasonable case for not
doing so.

Thanks.

It turns out that the problem is not accessing a module’s class, but
accessing the contents of a module in a require’d file.

global.rb
require ‘app’

app.rb
module RbScriptApp
class Foo
def Bar()
return (rand(100) + 1).to_s()
end
end
end

No matter what I do I can only access RbScriptApp and not Foo if I call
Runtime.UseFile(“global.rb”). So far I have two other work arounds: 1.)
create wrapper methods for everything I want to access in app.rb (ugh),
or 2.) use Engine.Execute(“RbScriptApp::Foo.new”). The latter is more
preferrable, I suppose, but it seems strange that I can’t access Foo by
dynamic.

Any more information about this issue would be very helpful and
appreciated.

On Jan 15, 2011, at 2:55 AM, Joshua M. wrote:

No matter what I do I can only access RbScriptApp and not Foo if I call
Runtime.UseFile(“global.rb”). So far I have two other work arounds: 1.)
create wrapper methods for everything I want to access in app.rb (ugh),
or 2.) use Engine.Execute(“RbScriptApp::Foo.new”). The latter is more
preferrable, I suppose, but it seems strange that I can’t access Foo by
dynamic.

That’s how Modules work in Ruby. Just like namespaces in C#.

Try adding

include RbScriptApp

to your global.rb file. You need to include the Module if you want to
access the class without qualifying it.

Any more information about this issue would be very helpful and
appreciated.


Posted via http://www.ruby-forum.com/.


Ironruby-core mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/ironruby-core


Will G.
[email protected]

You need to include the Module if you want to
access the class without qualifying it.

I have tried this but it doesn’t work (RuntimeBinderException:
‘Microsoft.Scripting.Hosting.ScriptScope’ does not contain a definition
for ‘Foo’).

In my original post I had specified the fully qualified name.

RbScriptApp.const_get(“Foo”)

InvalidOperationException: Empty scope has no global scope.

I haven’t tried that, but I think it should work. Neither solution is
indeed ideal. CLR interop with Modules isn’t quite polished yet.

Ah, that would explain it. I guess I’ll hold off on integrating IronRuby
just yet.

Thank you both for your time.

Another option would be

RbScriptApp.const_get(“Foo”)

I haven’t tried that, but I think it should work. Neither solution is
indeed ideal. CLR interop with Modules isn’t quite polished yet.

Tomas

to add directories to your search path from within C# you can do
something like this:

var engine = Ruby.CreateEngine();
var searchPaths = engine.GetSearchPaths().ToList();
searchPaths.Add(@“c:\code\generator\lib”);
searchPaths.Add(@“C:\Ruby-ri-192\lib\ruby\1.9.1”);
engine.SetSearchPaths(searchPaths);

Let me know if you find out how to access classes that are within
modules from C#. I’m having no luck.

I got it working using a kind of a hack/workaround.

I know this is kind of a hack/workaround, but I managed to do it this
way:

I added the next code to the end of the ruby file:

def hack(s)
  eval(s)
end

And then used it from the C# code to get the class object:

var engine = Ruby.CreateEngine();

var scope =

engine.ExecuteFile(@“c:\code\generator\lib\generator\generator_cmd_line.rb”);

var genCmdLineObj = engine.Execute(String.Format("hack('{0}::{1}')",

“Generator”, “CmdLine”), scope);

var cmdLineObj = engine.Operations.CreateInstance(genCmdLineObj);
var results = engine.Operations.InvokeMember(cmdLineObj, "run");
return Content(results);

Kind of a hack, but hey, it works! :slight_smile:

Shay.

Shay F. | Co-Founder @ CodeValue http://codevalue.net/ |
C#/IronRuby MVP | Author of IronRuby Unleashed
Blog: http://IronShay.com http://ironshay.com/ | Twitter:
http://twitter.com/ironshay

Wouldn’t this work?

dynamic globalConstants = engine.Runtime.Globals

globalConstants.MyModule.const_get(‘MyClass’)

assuming

module MyModule
class MyClass
end
end

Haven’t tried. Let me know if it works.

Tomas

From: [email protected]
[mailto:[email protected]] On Behalf Of Shay F.
Sent: Thursday, February 24, 2011 10:38 PM
To: [email protected]
Subject: Re: [Ironruby-core] Accessing a Module’s Classes from C# with
dynamic

I got it working using a kind of a hack/workaround.

I know this is kind of a hack/workaround, but I managed to do it this
way:

I added the next code to the end of the ruby file:

def hack(s)
  eval(s)
end

And then used it from the C# code to get the class object:

var engine = Ruby.CreateEngine();

var scope = 

engine.ExecuteFile(@“c:\code\generator\lib\generator\generator_cmd_line.rb”);

var genCmdLineObj = engine.Execute(String.Format("hack('{0}::{1}')", 

“Generator”, “CmdLine”), scope);

var cmdLineObj = engine.Operations.CreateInstance(genCmdLineObj);
var results = engine.Operations.InvokeMember(cmdLineObj, "run");
return Content(results);

Kind of a hack, but hey, it works! :slight_smile:

Shay.

Shay F. | Co-Founder @ CodeValuehttp://codevalue.net/ |
C#/IronRuby MVP | Author of IronRuby Unleashed
Blog: http://IronShay.comhttp://ironshay.com/ | Twitter:
http://twitter.com/ironshay

On Thu, Feb 24, 2011 at 4:41 PM, Rob R.
<[email protected]mailto:[email protected]> wrote:
to add directories to your search path from within C# you can do
something like this:

var engine = Ruby.CreateEngine();
var searchPaths = engine.GetSearchPaths().ToList();
searchPaths.Add(@“c:\code\generator\lib”);
searchPaths.Add(@“C:\Ruby-ri-192\lib\ruby\1.9.1”);
engine.SetSearchPaths(searchPaths);

Let me know if you find out how to access classes that are within
modules from C#. I’m having no luck.


Posted via http://www.ruby-forum.com/.

const_get doesn’t work, but you can do
globalConstants.MyModule.constants()[0] but then you get back an object
which you can’t initialize…

Shay.

On Fri, Feb 25, 2011 at 10:25 AM, Tomas M. <