Watson's Blog

RubyMotion で Ruby と Objective-C をミックスしてみました

| Comments

今日は、RubyMotion でベンチマークを計測してみたいなと思い、いろいろ試行錯誤していました。Ruby には benchmark というライブラリがあるのでそれを使えばすぐなのですが、RubyMotion ではライブラリがないので自作することにしました。そして、Objective-C を使って書いておけば何かの役に立ちそうかと簡単なライブラリをつくりました。

興味を持たれた方は Github に置いてありますので、

1
2
3
$ git clone git://github.com/Watson1978/RubyMotion-Benchmark.git
$ cd RubyMotion-Benchmark/
$ rake

と実行してください。

以下は試行錯誤の過程です。

RubyMotion Project Management Guide を読むと、サードパーティのライブラリは vendor ディレクトリを作成しそこに配置するのが慣わしらしいです。

配置するライブラリは Xcode で Cocoa Touch Static Library のテンプレートを選択して別途用意し、vendor ディレクトリに配置します。そして、Rakefile にライブラリを設定します。

1
2
3
4
5
6
7
8
9
10
11
Motion::Project::App.setup do |app|
  # Use `rake config' to see complete project settings.
  app.name = 'bench'

  # 3rd-Party Libraries
  app.vendor_project('vendor/Benchmark', :xcode,
    :headers_dir => 'Benchmark')

  # wrapper module
  app.files += Dir.glob(File.join(app.project_dir, 'vendor/Benchmark/lib/**/*.rb'))
end

app.vendor_project でライブラリのパス、ライブラリの種類(:xcode:static)、ヘッダファイルが存在するディレクトリを :headers_dir で設定します。:headers_dir は第一引数で指定したライブラリのパスからの相対パスで指定します。

:headers_dir は必ず指定した方がよさそうです。MacRuby や RubyMotion では、ヘッダファイルを解析して、どのような定数があるか、メソッドに Blocks が使われていないかチェックし、MacRuby や RubyMotion でそれらが使用できるようにするために Bridge Support というファイルを作ります。実際にプロジェクトをビルドしていただくと vendor/Benchmark/Benchmark.bridgesupport と Bridge Support ファイルが作成されています。

ライブラリは、

1
2
3
b = Bench.new
b.bm = lambda { 1 + 2 + 3 } # an expression for measuring 
b.exec

のように使用し、b.bm = lambda { 1 + 2 + 3 } で Blocks を property として受け付けるように Objective-C でライブラリを作成しています。

MacRuby や RubyMotion では、lambda などで生成した Proc オブジェクトを Blocks として実行することができます。

パフォーマンスを計測するたびに、毎回、上記のように記述するのが煩わしいので、vendor/Benchmark/lib/Benchmark.rb

1
2
3
4
5
6
7
8
9
module Benchmark
  module_function

  def bm(&block)
    b = Bench.new
    b.bm = block
    b.exec
  end
end

というラッパーを用意してあります。bm メソッドの引数でもらうブロックは Proc オブジェクトなので、そのまま Blocks として使っています。

1
2
3
4
Benchmark.bm do
  # an expression for measuring
  1 + 2 + 3
end

と記述できるようなります。

Github にアップロードしたプロジェクトを実行すると、以下のようになります。

1
2
3
4
5
6
7
$ rake
     Build ./build/iPhoneSimulator-5.1-Development
     Build vendor/Benchmark
  Simulate ./build/iPhoneSimulator-5.1-Development/bench.app
(main)>> 5702887
2012-05-09 21:50:43.158 bench[77935:f803] time = 0.278049
(main)>>

Comments