RubyでGUI C#からRubyを呼び出す

IronRubyの1.0がリリースされたので、C#からRubyの呼び出しを試してみる。

まず、C#のプロジェクトを作成。
formにtextboxとbuttonを一つずつ配置する。
デザイナのbuttonをダブルクリックしてForm1の編集画面へ。
編集前に、参照設定にIronRuby/bin下の
IronRuby.dll
IronRuby.Libraries.dll
Microsoft.Dynamic.dll
Microsoft.Scripting.dll
を追加しておく。

以下、ソース

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using IronRuby.Hosting; // ここ以下が追加分
using IronRuby.Runtime;
using IronRuby.Builtins;
using Microsoft.Scripting.Hosting;

namespace CallRubySample
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var rt = IronRuby.Ruby.CreateRuntime();      // IronRubyのランタイム作成
            dynamic test = rt.UseFile(@"..\..\test.rb"); // スクリプト読み込み
            dynamic ret = test.foo(this.textBox1.Text);  // フクリプトのfooメソッド呼び出し
            this.textBox1.Text = ret;                    // 結果をtextboxに表示
        }
    }
}

呼ばれる側のtest.rbの内容。
ソースフォルダに配置するが、VSのエディタで編集するとBOM付きで保存されてしまって実行時にエラーになるので、外部のエディタで編集すること。

def foo(s)
  s + "Foo"
end

Buttonクリックで、textboxに入っていた文字列の後ろに"Foo"が追加される。
C#側の処理のポイントは"dynamic"で定義されている変数。コンパイル時にはRubyスクリプトに"foo"というメソッドが定義されているかは不明なのでdynamic型で定義しておいて、実行時に"foo"が定義されていなかったらエラーになる。

ここで、Rubyスクリプトのfooの定義を以下のように変更してみる。

def foo(s)
  "Foo" + s
end

こうすると

this.textBox1.Text = ret;

の行で"IronRuby.Builtin.MutableStringをstringに暗黙の変換ができません"という例外が発生する。

  s + "Foo"

では、C#のStringクラスのインスタンスがレシーバになっているので、C#のString型で返されるが、

  "Foo" + s

では、RubyのStringがレシーバになっているのでRubyのString型が返される。
この場合は

this.textBox1.Text = (string)ret;

のようにキャストする必要がある。

Rubyの方でも型変換する必要があるケース。

def foo(s)
  eval(s).to_s
end

これは、sがRubyのString型でないのでevalでエラーになる。

  eval(s.to_s).to_s

としてあげる必要がある。