Iron Ruby

About Iron Ruby

Iron Ruby is a dynamic language runtime (DLR) based implementation of Ruby. Spark's Ruby integration is based on slightly modified trunk code. Other good resources are Ruby documentation and Programming Ruby.

The build of IronRuby used for Spark has had the assemblies Microsoft.Scripting.* assemblies renamed NonStandard.Microsoft.Scripting.*. Those libraries appear to be works in progess and some irreconcilable differences existed in these shared assemblies in the IronPython and IronRuby sources which were available at the time the integration with Spark was done. As those projects evolve the need for two sets of assemblies should disappear.

The support for the DLR is very Asp.Net MVC centric. If there's an interest in expanded Castle MonoRail support, please speak up in the discussion group.

Creating a new project

A standard Asp.Net MVC web application is always a great starting place. First, add references to the following assemblies:

  • Spark.dll
  • Spark.Ruby.dll
  • Spark.Web.Mvc.dll
  • Spark.Web.Mvc.Ruby.dll

And the following from the IronRuby release which are available in the Spark bin\dependencies folder. If you have problems with the these files from RubyForge try the ones in from the Spark distribution. You have the "works on my machine" guarantee.

  • NonStandard.Microsoft.Scripting.dll
  • NonStandard.Microsoft.Scripting.Core.dll
  • NonStandard.Microsoft.Scripting.ExtensionAttribute.dll
  • IronRuby.dll
  • IronRuby.Library.dll

Yeah, I know. It's a lot of assemblies. You're going to love the next part though, adding the Spark view engine to an Asp.Net MVC web application has been simplified.

Add the following to your Global Application_Start method:

using Spark.Web.Mvc.Ruby;
...
protected void Application_Start(object sender, EventArgs e)
{
    SparkRubyEngineStarter.RegisterViewEngine();
}

This will create a view engine and add it to the engines collection.

The Spark engine starter also has several utility methods for more advanced initialization. You can, for example, provide a settings object from code. You can also use the ISparkServicesContainer to provide specific implementations of different services used by the Spark engine. For example:

// this example avoids adding <spark> to web.config
var settings = new SparkSettings();
 
// change settings, like
settings
    .SetDebug(true)
    .SetPageBaseType(typeof(MyBasePage));
 
var container = SparkRubyEngineStarter.CreateContainer(settings);
 
// change services, like
container.SetServiceBuilder<IViewActivatorFactory>(
    c => new MyViewActivatorFactory());
 
SparkRubyEngineStarter.RegisterViewEngine(
    ViewEngines.Engines, container);

Adding views

Spark views for IronRuby look and act much like they would for csharp. They have a .spark extension and exist in the normal Views\<controllername>\<viewname>.spark path.

The syntax of Ruby on Spark is a bit rhtml-like. Spark supports <%= ... %> and <% ...%> in the same way, and the dictionary of ViewData values are added as @name attributes. Of course, just like other Spark variations can also execute code inline with #statement and output information with ${expression} and all of the <content>, <macro>, support for underscored partials, imports, etc. is unchanged.

<html>
  <head>
    <global title="'Python View Language Sample'"/>
    <title>${@title}</title>
  </head>
  <body>
    <use:view/>
  </body>
</html>

#@title = "Products - " + @title
<ul>
  <li each="p in @products">${html.ActionLink(p.name, "Show")}</li>
</ul>

Invoking methods and helpers

All methods and properties of the base view class are available. Ruby naming convention may be in effect, so if a symbol like ViewData isn't resolved try using view_data.

Some helper methods can be particularly tricky. It appears that native IronRuby can't be used for helper methods which take an anonymous type as a dictionary. The good news is you can typically call those helper methods with a CLR dictionary class you can create. The following is a bit of simplified code from the samples\AspNetMvc\IronRubyViews project available in the download.

<div>
  ## make a clr route dictionary for url.action
  #require 'System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
  #routeData = System::Web::Routing::RouteValueDictionary.new
 
  ## monkey patch an id setter equivalent to {routeData["id"] = value}
  #def routeData.id=(value); set_Item('id',value); end
 
  #routeData.id = page.CurrentPage - 1
  <a href="${url.action(action, controller, routeData)}">&laquo; Previous</a>
 
  <for each="pageIndex in 1..page.PageCount">
    #routeData.id = pageIndex
    <a href="${url.action(action, controller, routeData)}">${pageIndex}</a>
  </for>
 
  #routeData.id = page.CurrentPage + 1
  <a href="${url.action(action, controller, routeData)}">Next &raquo;</a>
</div>