Montag, 29. September 2008

Wie verwende ich Ironruby in einem C# Programm

Ich habe die Aufgabe gehabt einen Teil eines .Net Programm mit dynamischen Code auszustatten.

Aus meiner Sicht gab es nur die Möglichkeit, die für Silverlight entwickelten Sprachen zu verwenden (Python, Ruby bzw. Managed Javascript). Nach einigen Überlegungen und den Erfahrungen, die ich mit Rails gemacht habe, entschied ich mich für die Integration von Ironruby.

Nachdem ich zuerst ein paar Schwierigkeiten hatte einen String als Referenz an die Skript-Engine zu übergeben. Es schein ein Problem zu geben, wenn man mit ValueTypes arbeitet. Nachdem ich den String in eine Klasse eingepackt hatte, konnte ich die Daten ohne Problem mit der Script-Engine austauschen.

Ich habe den reduzierten Quellcode mal beigefügt:

using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using IronRuby;
using IronRuby.Hosting;
using Microsoft.Scripting.Hosting;
using System.Threading;
using System.Runtime.Remoting;
using System.Data.Odbc;
using System.Collections;
using System.Collections.Generic;

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

        private IDataReader GetData()
        {
            IDataReader result = null;
            OdbcConnection connection = new OdbcConnection("DSN=test_sqlite");
            try
            {
                connection.Open();
                IDbCommand command = new OdbcCommand("select * from projects"
                  , connection);

                IDataReader reader = command.ExecuteReader();

                while (reader.Read())
                {
                    for (int fieldIndex = 0; fieldIndex < reader.FieldCount;
                         fieldIndex++)
                    {
                        if (0 != fieldIndex)
                        {
                            mResult.AppendText(", ");
                        }

                        mResult.AppendText(reader.GetName(fieldIndex) 
                          + "=" + reader[fieldIndex].ToString());
                    }
                    mResult.AppendText(Environment.NewLine);
                }
                reader.Close();
                result = command.ExecuteReader();
                mResult.AppendText("-------------------------" + Environment.NewLine);
            }
            finally
            {
                //connection.Close();
            }
            return result;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ScriptRuntime scriptRuntime =   
               Ruby.CreateRuntime(Ruby.CreateRuntimeSetup());
            ScriptScope scope = scriptRuntime.CreateScope("ruby");

            IDataReader input = this.GetData();
            scope.SetVariable("input", input);

            IDictionary output = new Dictionary();
            scope.SetVariable("output", output);

            while (input.Read())
            {
                scope.Execute(mCode.Text);
                foreach (string key in output.Keys)
                {
                    mResult.AppendText(output[key] + " - ");
                }

                mResult.AppendText(Environment.NewLine);
                output.Clear();
            }
        }
    }
}

Der Quellcode, der im Beispiel verwendet wird, ist ziemlich trival. Für die Leute die der Sprache nicht mächtig sind, hier die paar Zeilen:

(0...input.FieldCount).each do |index|
     output.Add input.GetName(index), input.GetValue(index).ToString()
end

Im Beispiel werden die Daten aus dem input (IDataReader) in die Ausgabe output (IDictionary) kopiert. Der Range 0...input.FieldCount besagt, dass der Index bei 0 beginnt und bei input.FieldCount-1 endet.

Was ich interessant finde, ist, dass für die Einbindung einer Erweiterungssprache mehr nicht notwendig ist.

Viel Spass ;-)

2 Kommentare:

Manuel hat gesagt…

Hallo Martin,

ich bin nicht des Rubys mächtig.. kannst du auch einen kleinen Ruby-Beispielcode posten?

Wieso hat man das eigentlich FÜR Silverlight entwickelt? Als JavaScript Ersatz?

Gruß,
Manu

Martin hat gesagt…

ich denke das soll keinen ersatz darstellen, nur die verarbeitung von strings (wird in web ja stetig benötigt) ist mit ruby und python deutlich effizienter, ausserdem gibt es menge sehr gute bibiotheken ...