この記事は OS X Advent Calendar 2014 の22日目の記事です。
はじめに
Ruby のインタプリタをアプリケーションに組み込もうとした場合、現在だと mruby があります。CocoaPods にも登録されているので実際に利用するのも簡単かも知れません。
それでも色々あって mruby ではなく CRuby を組み込んで使いたい事情があったため、難儀しながら x86_64 や ARM で動く libruby-static.a を作ったりしていました。
それで折角なのでそれをなんやかんやして CocoaPods の Pod として公開してみましたので紹介します。
使い方
使い方は簡単です。Pod をインストールしたらあとは ObjC のメソッドを一つ呼ぶだけでスクリプトが実行出来るようになります。
Pod のインストール
他の CocoaPods のライブラリの利用と同じく、組み込んで使いたいアプリの .xcodeproj と同じフォルダに以下のような Podfile を用意して pod install するだけす。これだけで Ruby のインタプリタを使う準備が完了します。
platform :osx, '10.7'
pod 'CRuby', git: 'https://github.com/xord/cruby'
ただこの時は、是非とも --verbose オプションを使うことをお勧めします。
$ pod install --verbose
なぜなら pod install 中に rake コマンドを使って ruby-x.x.x.tar.gz のダウンロードから、各 CPU アーキテクチャ用のバイナリを生成しユニバーサルバイナリを作るため、現時点で7回もの configure && make を実行する作りになっているためです。例えば私の非力な11インチの MacBook Air だと30分以上もかかってしまうので、--verbose オプション無しだと進み具合がわからず辛いのです。
アプリ内でスクリプトを実行する
pod install が済んだらもうインタプリタが使えるようになっていますので、以下のように Ruby のスクリプトをテキストとしてアプリ内で評価することが出来るようになります。
CRBValue *result = [CRuby eval:@"[1, 2, 3].map {|n| n ** 2}"];
NSString *string = result.inspect;
NSLog(@"result: %@", string);
このように、Pod として CRuby の導入からスクリプトの実行までを簡単に出来るようにするため、'CRuby' クラスと 'CRBValue' クラスという簡単な API を用意してありますが、#include "ruby.h" すれば rb_xxxx() 等の CRuby の C API も使えます。
Ruby 標準ライブラリについて
公式サイトから配布される ruby のアーカイブに含まれる lib/ 以下の *.rb は Pod の resource_bundle として組み込んでありますので、単純に require すれば利用することができます。
ext/ ディレクトリにある拡張ライブラリも --with-static-linked-ext を configure 時に指定しているためバイナリとしては含んでいます。ですが、今のところ標準拡張ライブラリの Init_XXX を呼ぶ仕組みを入れていないため、require に失敗します。
この辺は今後 require をラップするなどしてロード出来るようにする予定でいます。
利用サンプル
CRuby Pod の利用サンプルとして、OS X 用アプリの Xcode プロジェクトファイル一色を GitHub に上げてあります。
2個めのコミットが Podfile の追加と [CRuby eval:] を呼ぶ部分の差分が入っていますので使うときの実際の例として参考になると思います。
https://github.com/xord/CRubyDemo_OSX/commit/c35a1abd324bb8fd471d4ca811364a2e9a0ee1ab
(pod install によるプロジェクトのファイルの差分も混じってしまっているので見にくいですが、見る所は Podfile と AppDelegate.m だけです)
CRuby が使いたかった事情
mruby ではなく CRuby が使いたかった理由ですが、単純に自分が今開発している CRuby 用のライブラリがあってそれをアプリからインタプリタ経由で使いたかったためです。一時はそのライブラリの方を mruby 用の拡張ライブラリとしても使えるようにしようと頑張ってみた時もあったのですが、CRuby と mruby の両対応拡張にするのは色々問題があって挫折しました。
それで、Ruby の処理系として多少の制限もある mruby を使うより、フルスペック版の CRuby が使えればそれが一番だと思って作った次第です。
最後に
Ruby Advent Calendar の明日23日の記事も私が担当します。CRuby が使いたかった理由に書いた自前のライブラリの紹介をしますので、そちらも是非見てみてくださいね。
それではまた。