いろいろな場所へ
Windows Phone 7 での IronRuby
Shay Friedman
数年前、私は間違いなく .NET にはまっていました。他の開発分野についてはまったく知りませんでしたし、.NET に没頭できることをとても幸せに感じていました。その後、ちょっとした手違いで、Ruby について勉強することになったのですが、それは開いた口がふさがらないほどの経験でした。言語の組み込み機能を使用して処理が行われる方法は衝撃的でした。
それでもやはり、人を .NET の世界から連れ出すことはできても、人から .NET の世界を奪うことはできません。そのため、マイクロソフトが Microsoft .NET Framework を基盤にして実装される Ruby 言語 (IronRuby と呼びます) を開発したと聞いた瞬間、大興奮し、それにのめりこんでいきました。
IronRuby によって、.NET の世界と Ruby の世界がつながるようになります。このため、新たな可能性が無限に広がり、このような組み合わせから得られるメリットはまったく驚異的なものです。
今月のコラムでは、.NET Framework と Ruby の両方の開発者にとって重要なメリットの 1 つについて説明します。それは、Windows Phone 7 で IronRuby を使用できることです。
IronRuby とは
2006 年にマイクロソフトは IronRuby を開発することを発表しました。この開発には 3 年以上かかり、今年の 4 月に IronRuby チームは IronRuby の最初の安定したバージョンとしてバージョン 1.0 を発表しました。
IronRuby では、Ruby 言語のすべての機能セットと固有のアドイン (Ruby コードと .NET Framework コードの統合) がサポートされます。この統合は非常にシームレスで、.NET Framework アセンブリを Ruby コンテキストに読み込む必要があるだけです。たとえば、次の IronRuby コードでは、System.Windows.Forms アセンブリを読み込んで、そのクラスを使用します。
require 'System.Windows.Forms'
include System::Windows::Forms
form = Form.new
form.height = 200
form.width = 400
form.text = "IronRuby Window"
form.show_dialog
この統合は、動的言語ランタイム (DLR) という .NET Framework インフラストラクチャに追加されたレイヤーのおかげで実現したもので、フレームワークの上位に記述される動的言語に共通のサービスを提供します。DLR は CLR を基に記述されており、.NET の上位に動的言語を非常に簡単に実装できるようにしています。これが、IronRuby、IronPython、IronJS、Nua、ClojureCLR というように、最近目にする .NET Framework 動的言語が増えてきた主な理由の 1 つです。
IronRuby の主な機能
Ruby は動的言語であり、IronRuby もそうです。つまり、コンパイラの必要がありません。静的言語ではコンパイル中やビルド時に行われる処理の大半が、実行時に行われます。この動作により、現在のほとんどの静的言語では実現が困難または不可能なさまざまな機能が提供されます。
.NET Framework オブジェクトとの相互運用性: Ruby 言語には、MRI (オリジナル版)、JRuby、Rubinius、MacRub、IronRuby など、さまざまな実装があります。その中でも IronRuby が目立っているのは、.NET Framework オブジェクトと適宜相互運用できるためです。この相互運用性は双方向で、.NET Framework オブジェクトを IronRuby コードから利用でき、IronRuby オブジェクトを .NET Framework コードから利用できます。
動的な型指定: IronRuby 変数の型は実行時に決定されるため、コードで型を指定する必要がありません。ただし、IronRuby に型がないという意味ではありません。型はあります。すべての型には、静的言語の型と同様に独自の規則があります。次のコード サンプルでは、いくつかの簡単な手順で動的型指定のメカニズムを示しています。
# Declaring a numeric variable
a = 1
# The variable is of a numeric type
# and therefore numeric operations are available
a = a * 2 + 8 / 4
# The next line will raise an exception
# because it is not possible to add a string to a number
a = a + "hello"
# However, the next line is entirely legit and will result
# in changing the variable type to String
a = "Hello"
対話型コンソール: Windows コマンド プロンプトに似た対話型コンソールは、IronRuby コードを取得して即座に実行するアプリケーションです。実行フローは、REPL (Read-Evaluate-Print-Loop) とも呼ばれています。変数やメソッドだけでなくクラスまでも定義し、IronRuby ファイルまたは .NET Framework アセンブリを読み込んですぐに使用することができます。たとえば、図 1 はクラスを作成して即座に使用する単純なコンソール セッションを示しています。
図 1 IronRuby コンソールの使用
ダック タイピング: IronRuby はオブジェクト指向言語です。オブジェクト指向言語に想定されるように、クラス、継承、カプセル化、およびアクセス制御をサポートします。ただし、多くの静的言語でサポートされるような、インターフェイスや抽象クラスはサポートしません。
とはいっても、言語仕様の不備ではありません。動的型指定により、インターフェイスや抽象クラスなど、コードのコントラクトを宣言することが冗長になります。オブジェクトに関して唯一重要なことは、具体的なメソッドを定義するかどうかであって、メソッドを定義するときにそのメソッドの型を指定する必要はありません。これがダック タイピングとして知られていることです。「もしもそれがアヒルのように鳴き、アヒルのように泳ぐのなら、それはアヒルです。それをアヒルとみなすために印を付ける必要はありません」。
たとえば、図 2 のコード サンプルには、"say_hi" というメソッドと、introduce という別の一般的なメソッド (オブジェクトを取得して "say_hi" メソッドを実行する) を含む 2 つのクラスがあります (インターフェイスや他のマーキング メカニズムは含まれていないことがわかります)。
図 2 ダック タイピングの例
class Human
def say_hi
puts "Hi!"
end
end
class Duck
def say_hi
puts "Quack!"
end
end
def introduce(obj)
obj.say_hi
end
human = Human.new
duck = Duck.new
introduce(human) # prints "Hi!"
introduce(duck) # prints "Quack!"
メタプログラミング: IronRuby には強力なメタプログラミング機能が付属しています。メタプログラミングは、実行中にメソッドを追加、変更、および削除する方法です。たとえば、クラスにメソッドを追加したり、他のメソッドを定義するメソッドを記述したり、既存のクラスからメソッドの定義を削除したりすることが可能です。図 3 では、メソッドをクラスに追加します。このメソッドは、クラスの現在のインスタンスにも、将来新たに作成されるインスタンスにも反映されます。
図 3 クラスの宣言後にメソッドをクラスに追加
# Creating a class with no methods
class Demo
end
# Creating an instance of class Demo
d = Demo.new
# Opening the class and adding a new method - hello_world
class Demo
def hello_world
puts "hello world"
end
end
# Using the newly added method on the class instance
d.hello_world # prints "hello world"
さらに、未定義のメソッドや定数の呼び出しをキャッチするために使用できる特別なメソッドがあります。これらのメソッドを使用すると、find_by_[column name] のような動的メソッド名を簡単にサポートできます。ここで、[column name] は "find_by_name"、"find_by_city"、"find_by_zipcode" のような任意の値に置き換えることができます。
RubyGems: Ruby 言語は、そのままでも強力ですが、それと共にインストールして使用できる外部ライブラリがなければ、このような大きな成功は収められなかったでしょう。
Ruby のライブラリをインストールする場合、RubyGems システムを使用するのが主な方法です。RubyGems システムは、Ruby のライブラリを配布してインストールできるパッケージ マネージャーで、"gems" と呼ばれています。数千もの無償の gems があり、テスト用フレームワーク、税額計算ライブラリ、Web 開発フレームワークなど、プログラミングのほぼすべての側面や作業がカバーされています。
一部の RubyGems は C ライブラリに依存していることに注意してください。こうした gems は、C ライブラリを通常の Ruby または C# に移植しないと、現在のバージョンの IronRuby では実行できません。
コミュニティ: IronRuby の最もすばらしい点の 1 つは、Ruby コミュニティにアクセスできることです。コミュニティには、貴重なコンテンツが含まれる、多くのフォーラム、メーリング リスト、チャット ルーム、ブログがあり、質問に積極的に答える人々によって運営されています。是非、こうしたリソースをご活用ください。非常に役立ちます。
IronRuby と Silverlight
Silverlight 2 で、新しい重要な機能として DLR 言語のサポートが導入されました。このため、開発者は IronRuby を Silverlight アプリケーションで使用できます。つまり、IronRuby をアプリケーションに組み込むことから、IronRuby を使用して Silverlight アプリケーション全体を記述することまで可能です。
でもちょっと待ってください。Silverlight は Windows Phone 7 上で実行されますよね。確かにそうです。
Windows Phone 7
Microsoft の次期モバイル プラットフォームである Windows Phone 7 は、スマート フォン業界の形勢を変えるものになると期待されています。標準のマルチタッチ機能や最新の UI はさておき、Windows Phone 7 に関して開発者の観点からの最高のニュースは、Silverlight がその開発プラットフォームであるということです。
これは、定着したテクノロジを活用するという、マイクロソフトが打ち出した賢明な手段なので、多くの開発者がほとんど学習することなくモバイル アプリケーションを作成できます。
DLR 言語が Silverlight 環境内で実行できるため、IronRuby も利用できます。したがって、IronRuby を使用して Windows Phone 7 アプリケーションを記述できます。
ただし、注意すべき制限事項がいくつかあります。Windows Phone 7 は、.NET Compact Framework (.NET Framework のサブセット) に付属しています。Compact Framework はモバイル アプリケーションや埋め込みアプリケーション向けにデザインされており、完全版 .NET Framework の約 30 パーセントしか機能が含まれていません。したがって、多くのクラスが存在せず、これが IronRuby の動作に影響します。
不足している機能の中で IronRuby に影響する重要な機能が Reflection.Emit 名前空間です。IronRuby はこの機能を使用して、実行時にコードをコンパイルしてアプリケーションの実行を高速化します。ただし、これは単なるパフォーマンスの最適化であって、簡単なスクリプトやアプリケーションを実行する際に必要なコンポーネントではありません。
もう 1 つの制限事項は、新しい Windows Phone 7 アプリケーションの作成方法に関するものです。Windows Phone 7 アプリケーションは、Visual Studio の C# のみで作成できます。この要件により、開発者は IronRuby コードを起動するコードを C# で記述しなければなりません。
最後の重要な制限事項は、RubyGems が Windows Phone 7 上で機能しないことです。そのため、gems を使用するには、アプリケーション ファイルの中に gems のコード ファイルを含めて、それらを他の IronRuby コード ファイルとして使用する必要があります。
Windows Phone 7 でシンプルな IronRuby アプリケーションを構築する
IronRuby 主導の Windows Phone 7 アプリケーションに着手するには、まず、Windows Phone 7 Developer Tools をインストールする必要があります。この開発ツールは、developer.windowsphone.com (英語) からダウンロードできます。
ツールをインストールしたら、Visual Studio を起動し、[ファイル] メニューの [新規作成] をポイントして [プロジェクト] をクリックします。[新しいプロジェクト] ダイアログ ボックスで、[Silverlight for Windows Phone] カテゴリを選択し、[Windows Phone Application] プロジェクト テンプレートを選択します。プロジェクトに名前を付けて続行します。
新しいプロジェクトが開くとすぐに、簡単な XAML ファイルが作成されていることが通知されます。通常 Silverlight には XAML が必要であり、XAML は言語に依存しません。そのため、アプリケーション コードを IronRuby で記述する場合でも、XAML を使用して UI を作成する必要があります。このシンプルなアプリケーションでは、既定の XAML ファイルで十分なので、ここでは変更不要です。
このシンプルなアプリケーションで興味深い部分は、コードです。ただし、コードに着手する前に、IronRuby と DLR のアセンブリへの参照を追加する必要があります。追加するアセンブリは通常のものではありません。ironruby.codeplex.com/releases/view/43540#DownloadId=133276 (英語) から入手できる Windows Phone 7 対応のアセンブリが必要です。必要なアセンブリは、ダウンロードしたパッケージの silverlight/bin フォルダーにあります。
次に、IronRuby コードを記述する必要があります。新しいテキスト ファイルをアプリケーションに追加して、MainPage.rb という名前を付けます。また、携帯電話への配置を容易にするには、このファイルのプロパティを開いて、[ビルド アクション] プロパティを [埋め込まれたリソース] に変更します。
その後、図 4 のコードをファイルに貼り付けます。
図 4 Windows Phone 7 で実行する IronRuby コード ファイル
# Include namespaces for ease of use
include System::Windows::Media
include System::Windows::Controls
# Set the titles
Phone.find_name("ApplicationTitle").text = "MSDN Magazine"
Phone.find_name("PageTitle").text = "IronRuby& WP7"
# Create a new text block
textBlock = TextBlock.new
textBlock.text = "IronRuby is running on Windows Phone 7!"
textBlock.foreground = SolidColorBrush.new(Colors.Green)
textBlock.font_size = 48
textBlock.text_wrapping = System::Windows::TextWrapping.Wrap
# Add the text block to the page
Phone.find_name("ContentGrid").children.add(textBlock)
図 4 の IronRuby コードは非常にわかりやすいもので、タイトルを設定して、なんらかのテキストを含むテキスト ブロックを作成し、そのブロックをページに追加しています。Windows Phone 環境内で実行する場合前述の制限はあるものの、クラス、メタプログラミング、ライブラリなど、Ruby 言語のあらゆるものを使用できます (ここでは使用しませんが)。
後は、実際に IronRuby コードを実行するだけです。アプリケーションの読み込み時にコードを実行するには、図 5 のコードを MainPage クラス コンストラクターに追加します。このコンストラクターは MainPage.xaml.cs ファイルにあります。
図 5 クラス コンストラクターから IronRuby コードを実行するコードを追加する
// Allow both portrait and landscape orientations
SupportedOrientations = SupportedPageOrientation.PortraitOrLandscape;
// Create an IronRuby engine and prevent compilation
ScriptEngine engine = Ruby.CreateEngine();
// Load the System.Windows.Media assembly to the IronRuby context
engine.Runtime.LoadAssembly(typeof(Color).Assembly);
// Add a global constant named Phone, which will allow access to this class
engine.Runtime.Globals.SetVariable("Phone", this);
// Read the IronRuby code
Assembly execAssembly = Assembly.GetExecutingAssembly();
Stream codeFile =
execAssembly.GetManifestResourceStream("SampleWPApp.MainPage.rb");
string code = new StreamReader(codeFile).ReadToEnd();
// Execute the IronRuby code
engine.Execute(code);
図 5 のコードは非常に短く、どれほど簡単に C# コードから IronRuby コードを実行できるかを適切に示しています。
また、次の using ステートメントをクラスに追加してください。
using System.Reflection;
using System.IO;
using Microsoft.Scripting.Hosting;
using IronRuby;
図 5 のコードの 3 行目では、System.Windows.Media アセンブリを IronRuby コンテキストに読み込んでいます。このコードにより、このアセンブリのクラスや列挙子との相互運用が可能になります。
その次の行では、IronRuby コードにより、現在の Silverlight ページにアクセスできます。この行では、"Phone" という定数を使用して現在のインスタンス (this) を IronRuby コードに公開します。
残りのコードで、埋め込まれたファイルから IronRuby コードを読み取り (アプリケーション名前空間をファイル名に追加する必要があるため、MainPage.rb は SampleWPApp.MainPage.rb になることに注意してください)、エンジン インスタンスを使用してそれを実行します。
処理は以上です。ここでは、読み込まれた後に IronRuby が実行されて、タイトルが変更され、テキスト ブロックが Silverlight ページに追加されるアプリケーションを作成しました。後は、アプリケーションを実行するだけです。結果は 図 6 のようになります。
図 6 Windows Phone 7 で実行中の IronRuby 主導のアプリケーション
進化を続ける
Windows Phone 7 で IronRuby を使用しているときにワークフローが完璧ではなく、さまざまな制限事項を気にかける必要があるとしても、これはまだ始まったばかりです。IronRuby と Windows Phone 7 プラットフォームはどちらも新しく、これからも進化し続けます。
この組み合わせにより、.NET Framework 開発者と Ruby 開発者の両方に多くの可能性が広がります。現時点では、.NET 開発者は Windows Phone 7 アプリケーションを記述する際に、IronRuby コンソールをアプリケーションに組み込んだり、拡張機能を提供したりするなど、Ruby 言語の強力な機能を活用できます。一方、Ruby 開発者は、初めて Ruby 言語を使用してモバイル アプリケーションを記述できるようになります。
これはもちろん、たくさんの機会と可能性を持った素晴らしい新世界の始まりです。そして、すべてが読者の手に委ねられます。
Shay Friedman は、Microsoft Visual C#/IronRuby MVP であり、『IronRuby Unleashed』 (Sams 社、2010 年) の著者でもあります。Sela Group 社で動的言語のリーダーを務めており、世界中でコンサルタントや講師として活動しています。IronShay.com (英語) で彼のブログをご覧いただけます。
この記事のレビューに協力してくれた技術スタッフの Tomas Matousek に心より感謝いたします。