IronRuby Quick Start

IronRuby is Microsoft's, with collaboration by the public, implementation of Ruby on their imageDynamic Language Runtime. There's another version of Ruby for .NET called, ironically, Ruby.NET that runs directly on the CLR. This post won't be about that though, if you want to see a comparison, look here for a fairly good write up.

Downloading IronRuby from the SVN server and compiling in VS2005 was actually pretty painless. But after that I couldn't find any, working, examples of getting an Ruby script running in the DLR. A big part of this is due to IronRuby still being officially "pre-Alpha" with the Scripting Host API in flux. Regardless, I hope this will be enough to get some people trying to use the latest SVN (rev. 75) up and running.

Building The Source

Download the latest revision from RubyForge using SVN, if you need a client I HIGHLY recommend TortiseSVN. Once you're done downloading the source, you should be able to open the IronRuby.sln file in Visual Studio. We only need to make one change, and that's to the Microsoft Scripting Project. Bring up the project properties and go to the Build tab:

image

We have to remove the Conditional compilation symbol of "SIGNED", otherwise the Scripting host will be looking for Microsoft signed copies of the IronRuby library, which we don't have. After that go ahead and build the solution (cross your fingers if it makes you feel better).

When all is done you should end up with a bin\Debug folder in your SVN root that looks something like this:

image

You can go ahead and start rbx from right there and begin playing with Ruby if you'd like. But if that's all we wanted to do we would have just downloaded Ruby, right? This is IronRuby, let's do it the .NET Way!

Hosting IronRuby in C#

Create a new Console Application solution in Visual Studio, say RubyExample. Add References to the Microsoft.Scripting.dll, IronRuby.dll, and IronRuby.Libraries.dll files.

Let's begin with the most basic, a simple Hello World:

using System;
using Ruby;
using Ruby.Runtime;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;
namespace RubyExample
{
static class Program
{
/// <summary>
///
The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
IScriptEnvironment scriptenvironment = ScriptEnvironment.GetEnvironment();
IScriptEngine rubyengine = scriptenvironment.GetEngine("ruby");
scriptenvironment.ExecuteSourceUnit(rubyengine.CreateScriptSourceFromString("puts'Hello World!
\nPress Any Key To Continue..'"
) );
Console.ReadKey();
}
}
}


Let's take a quick look at what we're doing here. We're setting up a ScriptEnvironment, this is where our Dynamic languages are going to live and play. Then out of that environment we're asking for someone who understands Ruby. After that we're just saying, hey ScriptEnvironment, run what the Ruby guy says.

So that's pretty nifty, we could also tell the RubyEngine to CreateScriptSourceFromFile and move whatever code we want out of a string constant. Which is probably a good idea for anything beyond a line a two. But what if we actually want to talk back and forth? Let's move on to the next example.

Accessing Global Variables

The easiest way to pass data between IronRuby and C# is via Global Variables. See below for an example.



using System;
using System.Collections.Generic;
using Ruby;
using Ruby.Runtime;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;
namespace RubyExample
{
static class Program
{
/// <summary>
///
The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
IScriptEngine rubyengine = IronRuby.GetEngine(IronRuby.CreateRuntime());
Dictionary<SymbolId, object> globalvars = IronRuby.GetExecutionContext(rubyengine.Runtime).GlobalVariables;

globalvars[SymbolTable.StringToId("widget")] = ".NET";

IScriptScope scope = rubyengine.CreateScope();

rubyengine.Execute(scope, rubyengine.CreateScriptSourceFromString("puts 'Ruby and ' +
$widget.to_s + ' together at last'"
));

SymbolId rubynumber = SymbolTable.StringToId("mynumber");
int mynumber = 12;

globalvars[rubynumber] = mynumber;

rubyengine.Execute(scope, rubyengine.CreateScriptSourceFromString("$mynumber = $mynumber
+ 13"
));

mynumber = (int)globalvars[rubynumber];

Console.WriteLine("The variable mynumber = {0}", mynumber);
Console.ReadKey();
}
}
}


As you can see I switched it up a bit and inited the Environment and Engine a bit differently, one way is more general, the other specific to IronRuby. The power of the ScriptingHost API is you can on the fly decide what language you want to use. But if you know you're only going to be doing IronRuby, you can use the above method.



The real trick is in the second line, we get a reference to the GlobalVariables of the current IronRuby execution context. Once we have that we can start assigning global variables values and retrieving them back.

Summary

Hopefully this is enough to get you started. As I continue to delve into IronRuby, I will be sure to post what I find here, so keep an eye out!

IronRuby Homepage
IronRuby RubyForge Project
Ruby Language Homepage
DLR Hosting Spec
John Lam's homepage

1 comment:

Matt Blodgett said...

Great post, Michael. I look forward to more IronRuby stuff.