2013/10/23

C#からRubyを実行★IronRuby★

Kです。本日2回目の投稿です。というのも、テーマごとに1つの記事にすべきなので1日に何回投稿しても構いません。メールがうざったい人は管理できる人に言ってリストから削除して貰って下さい。尚、私は削除しました。笑

さて、本題のIronRubyに関して、まずは動機を説明しましょう。先日の操縦テストプログラムの要望によって、スクリプトファイルで処理した結果をデバイスに送信する必要が出てきました。従って、C#から数値の配列を渡し、Rubyが処理し、その結果を数値の配列で受け取る必要が出てきました。

次に、必要な環境について説明しましょう。IronRubyはC#上でRubyのソースコードを解釈し、実行するプログラムです。これを組み込めば、上記の目的は達成できるでしょう。さて、これを使うには次の4つのdllファイルを参照に追加する必要があります。
  • IronRuby.dll
  • IronRuby.Libraries.dll
  • Microsoft.Dynamic.dll
  • Microsoft.Scripting.dll
これらは、公式サイトからダウンロードできます。尚、Microsoft.Dynamic.dllについてはdynamicを使用しない場合は要らないようです。(適当)

とりあえずネット上から探してコードを実行してみました。

using System;
class Program {
 public static void Main() {
  var engine = IronRuby.Ruby.CreateEngine();
  var scope = engine.CreateScope();

  engine.ExecuteFile("./test.rb", scope);
  var ss = engine.CreateScriptSourceFromString("foo()");
  ss.Execute(scope);

  int res = engine.Execute<int>("fooo", scope);
  Console.WriteLine(res);
 }
}
test.rbの中身は以下の通りです。ちなみにRubyの流派ではreturnを書きません。
def foo
 $x = 10
end

def fooo
 return $x
end
これを実行すると、10と表示されます。

中身を追っていきます。 IronRuby.Ruby.CreateEngine();でRubyのインタプリタエンジンを作成します。

次に、engine.CreateScope();で変数などを記録するフィールド(適当)を作成します。このscopeが異なると別々の領域で実行されることになってしまいますので注意。

次に、engine.ExecuteFile("./test.rb", scope);でファイル都市コープを指定して実行します。実行された結果、値が返ってきますが、今回はメソッドの定義しかしていないのでその必要はありません。

 次に、var ss = engine.CreateScriptSourceFromString("foo()");でfooというメソッドを呼び出すプログラムを作成し、そのプログラムを変数ssに代入しています。これは次の行のとおりss.Execute(scope);と実行できます。ループして実行する場合は一度プログラムを解釈した後にまとめてExecuteしたほうが速かったです。

 最後にint res = engine.Execute<int>("fooo()", scope);でfoooメソッドを実行しました。結果をintで受け取り、ごにょごにょしています。文字列の場合はstringを、配列の場合はRubyArrayを指定します。

 その後いろいろ調べていたら、 次のコードでも実行できることが分かりました。但し参照にMicrosoft.CSharpを追加する必要があります。
using System;

class Program {
 public static void Main() {
  var rt = IronRuby.Ruby.CreateRuntime();
  dynamic t1 = rt.UseFile("./test.rb");
  dynamic t2 = rt.UseFile("./test2.rb");

  t1.foo();
  t2.bar();

  Console.WriteLine(t1.fooo());
 }
}
 Rubyは次の2ファイルです。1つめがtest.rbです。
def foo
 $x = 10
end

def fooo
 return $x
end
2つめがtest2.rbです。
def bar
 $x = 20
end

さてこの実行結果は20を表示します。

まず、var rt = IronRuby.Ruby.CreateRuntime();でRubyのランタイムを作成します。(適当)次にdynamic t1 = rt.UseFile("./test.rb");でソースコードを読み込み、解析結果をt1に代入します。このとき、dynamicを指定します。これは動的に動作が変わるためです。そしてt1.foo();で実行します。

この方法ではRuby内のメソッドをC#のメソッドで呼び出せます。更に、1つめのサンプルに比べてかなり高速です。これを使うしかありませんね!!

ファイルを分割しても、同じスコープを共有されるためグローバル変数が上書きされました。

0 件のコメント:

コメントを投稿