Search code examples
c#c#-4.0ironruby

Instantiating a ruby class that is in a Module from within C#


I'm attempting to re-use some ruby classes I wrote a while back within an ASP.NET MVC 2 project. The issue I'm having is if a class is within a Module I can't seem to instantiate it. If I move the class outside of the module it works fine. Here is a scaled down version of the class I want to instantiate:

module Generator
  class CmdLine
    attr_accessor :options

    def initialize(output)
    end

    def run(args=[])
    end
  end
end

If comment out the module portion I can create the object. Am I doing something wrong? Here is the C# code:

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

engine.ExecuteFile(@"c:\code\generator\lib\generator\generator_cmd_line.rb");
var rubyCmdLineObj = engine.Runtime.Globals.GetVariableNames();
// These lines works when I comment out the module
// var genCmdLineObj = engine.Runtime.Globals.GetVariable("CmdLine");
// var cmdLineObj = engine.Operations.CreateInstance(genCmdLineObj);
// var results = engine.Operations.InvokeMember(cmdLineObj, "run");
//  return Content(results);
var sb = new StringBuilder();
foreach (var name in rubyCmdLineObj)
{
  sb.AppendFormat("{0} ", name);
}

return Content(sb.ToString());

I have a work around - creating a separate class that I can call from within C# but if I don't have to do that I'd rather not do it. Any guidance would be greatly appreciated.


Solution

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

    Add the next code to the end of your ruby file:

    def hack(s)
      eval(s)
    end
    

    Now your C# code would look like that:

    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! :)