Upload
masaya-konishi
View
2.005
Download
3
Embed Size (px)
DESCRIPTION
第16回 岡山ruby, ruby on rails勉強会でmrubyについて調べたこと、試したことを発表しました。
Citation preview
mrubyについて第16回 岡山Ruby, Ruby on Rails 勉強会
自己紹介
・小西 雅也
・Twitter: @ore_public・Github: https://github.com/ore-public・Ruby歴 12年くらい
・株式会社リゾーム 勤務
自己紹介
・言語処理系の技術が趣味
・プログラミング言語が趣味
・OSのクリーンインストールが趣味
るびま10周年https://twitter.com/gunjisatoshi/status/489194078139990016
アジェンダ
・mrubyとは
・ビルド
・mrbgemについて
・CRubyと比べる
・mrbgemを作ってみる
・mrbgemを元にmruby内部を少し解説
mruby・省メモリ版ruby・組み込み用途に使いやすい(らしい)・JRubyやRubiniusの様な「Ruby言語」の
別実装ではない
・mrubyという別の仕様をもった言語
ビルド$ git clone [email protected]:mruby/mruby.git$ cd mruby$ ruby ./minirake (もしくは rake )
以下の4つが出来上がる./bin/mruby mruby本体
./bin/mirb CRubyで言う irb
./bin/mrbc コンパイラ(rubyコード → バイトコード)
./bin/mruby-strip Todo
mrbgem・mrubyのビルド時にmrbgemのコードを取得
・mrubyにgemの内容も組み込まれる
・CRubyのgemのような依存関係の解決はない
・ビルドの設定ファイル (build_config.rb)で指定する
MRuby::Build.new do |conf| if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR'] toolchain :visualcpp else toolchain :gcc end enable_debug
conf.gem :git => 'https://github.com/ore-public/mruby-fizzbuzz' conf.gem ‘../fizzbuzz’ conf.gembox 'default'end
mrbgem#gitリポジトリ指定
conf.gem :git => 'https://github.com/ore-public/mruby-fizzbuzz'
#ファイルパス指定
conf.gem ‘../fizzbuzz’
#gembox指定
conf.gembox 'default' #依存関係の解決などにつかう
mrbgems・gemboxmrbgemsディレクトリに .gemboxファイルがありその中身に記述されているmrbgemがビルドされる
mrbgems
MRuby::GemBox.new do |conf| # Use standard Kernel#sprintf method conf.gem :core => "mruby-sprintf"
# Use standard print/puts/p conf.gem :core => "mruby-print"
# Use standard Math module conf.gem :core => "mruby-math"
default.gembox(一部抜粋)
mrbgems・以下のものもmrbgemsになっている
mrubyコマンド
mirbコマンド
・gembox defaultを外してビルドすると
mrbcしかビルドされない
CRubyと比べるCRuby (rbenvにてruby2.1.2) rubyコマンド 2,413,276バイト
mruby mrubyコマンド 705,956バイト
1/3くらい
※Mac OS X 10.9.4にてビルド時
CRubyと比べるmrbgemsを一切いれずにビルド時の出力
・構成ファイル結構少ない
・これなら読めそうな気がしてくる
CRubyと比べる・array.cを比べる (Arrayクラスの実装)
CRuby (ruby2.1.2) 約5700行 mruby 約1100行
・読めそうな気がしてくる
CRubyと比べる・Arrayに定義されているメソッド数を比べる
CRuby > Array.instance_methods(false).size => 90
mruby > Array.instance_methods(false).size => 42
CRubyと比べる
・mruby-array-ext gemを入れると
> Array.instance_methods(false).size => 67
mrbgemsを作ってみる
・Arrayクラスにfizzbuzzメソッドを追加する
gemを作ってみる
・mrubyによる実装と、Cによる実装
二つ試す
・https://github.com/ore-public/mruby-fizzbuzz
mrbgemsを作ってみる
mruby-mrbgem-template で作成
http://blog.matsumoto-r.jp/?p=3923
mrbgemsを作ってみる
・ディレクトリ構成mruby-fizzbuzz├── LICENSE├── README.md├── mrbgem.rake├── mrblib│ └── mrb_fizzbuzz.rb Rubyによる実装
├── mruby-fizzbuzz.gem├── src│ ├── mrb_fizzbuzz.c C言語による実装
│ └── mrb_fizzbuzz.h└── test └── mrb_fizzbuzz.rb テスト
mrbgemsを作ってみる
実装のデモ
mrbgemsを作ってみる
・mrubyでも、C言語でも実装出来る
・mrubyの機能で実装出来るものは
mrubyで作る
・それが無理なものはC言語で作る
mruby内部(mruby-fizzbuzzより)void mrb_mruby_fizzbuzz_gem_init(mrb_state *mrb){ struct RClass *a = mrb->array_class;
mrb_define_method(mrb, a, "fizzbuzz", mrb_fizzbuzz, MRB_ARGS_REQ(1));}
・mrb_state
mruby起動時に初期化され、mrubyの実行環境の状態を持っている。Objectクラスとか Classクラス Moduleクラスの 実体とか組み込みのクラスのArrayとかString、あとグローバル変数のテーブルとか色々持ってる。
常に引き回されて、mruby環境の情報をここから取得する。
mruby内部(mruby-fizzbuzzより)include/mruby.h (mrb_stateの一部)typedef struct mrb_state { struct mrb_jmpbuf *jmp;
mrb_allocf allocf; /* memory allocation function */ struct mrb_context *c; struct mrb_context *root_c;
struct RObject *exc; /* exception */ struct iv_tbl *globals; /* global variable table */
struct RObject *top_self; struct RClass *object_class; /* Object class */ struct RClass *class_class; struct RClass *module_class; struct RClass *proc_class; struct RClass *string_class; struct RClass *array_class; struct RClass *hash_class;
mruby内部(mruby-fizzbuzzより)void mrb_mruby_fizzbuzz_gem_init(mrb_state *mrb){ struct RClass *a = mrb->array_class;
mrb_define_method(mrb, a, "fizzbuzz", mrb_fizzbuzz, MRB_ARGS_REQ(1));}
・mrb_define_method
クラスにメソッドを定義するための関数。
上記では、mrb_stateからArrayクラスの実体を取得して、”fizzbuzz”というメソッドを定義。
mrb_fizzbuzzというCの関数へのポインタを渡している。
rubyの世界で言うと、 [ def ] の実装。
mruby内部(mruby-fizzbuzzより)static mrb_value mrb_fizzbuzz(mrb_state *mrb, mrb_value self){ mrb_int i; mrb_value v, value, fizzbuzz;
value = mrb_ary_new_capa(mrb, RARRAY_LEN(self)); for (i = 0; i < RARRAY_LEN(self); ++i) { v = RARRAY_PTR(self)[i]; if((mrb_fixnum(v) % 15) == 0){ fizzbuzz = mrb_str_new_cstr(mrb, "FizzBuzz"); } else if((v.value.i % 5) == 0) { (略)
} else { fizzbuzz = v; } mrb_ary_set(mrb, value, i, fizzbuzz); } return value;}
self メソッド呼び出し元のオブジェクトmrb_value mrubyの世界のオブジェクトを格納する型mrb_ary_new_capa Arrayのオブジェクト生成RARRAY_LEN Arrayオブジェクトの長さ取得RARRAY_PTR Arrayに格納されているオブジェクト配列への ポインタmrb_ary_set Arrayの指定インデックスへオブジェクトのセッ ト■概要・新規のArrayオブジェクト作成・自分自身の長さ分ループさせて、配列の中身を1つずつ取り 出す・取り出した値がfizzbuzzに該当する値なら、新規Arrayに文 字列オブジェクトをセット・そうじゃなければ、取り出した値をセット
■懸念点・selfがArrayかどうかチェックしてない・selfから取り出した v が整数と決めつけて処理している (別のオブジェクトだった場合、ポインタ値を整数として処 理してるので、落ちずに動いてはいる)
mruby内部(mruby-fizzbuzzより)typedef struct mrb_value { union { mrb_float f; void *p; mrb_int i; mrb_sym sym; } value; enum mrb_vtype tt;} mrb_value;
■mrb_value構造体
共用体になっていて、float, int, シンボルの値はそのまま valueの中に入っている。
それ以外のオブジェクトは、void *p でオブジェクトへのポインタを持っている。
mrb_vtypeは型の情報を保持。
void型のポインタなので、先のオブジェクトに合わせてキャストが必要だが RARRAY_PTRマクロとかがそれをやってくれている(多分)
fizzbuzzの例では配列の中身が整数(と決めつけて)なので、v.value.i として 整数の値を取得していた。
まとめ
・mrubyの概要
・mrubyのビルドとmrbgemsについて
・CRubyとの比較(主にArray)・mrbgemの作成(Array#fizzbuzzの実装)
・mrubyの実装を眺める
今後やってみたいこと
・mrbgemをもっと作る
・コードリーディング
・mrubyのAPIのまとめ
・アプリケーションへのmrubyの組み込み
参考・RHG (Rubyソースコード完全解説)
http://i.loveruby.net/ja/rhg/book/・mrubyアドベントカレンダー2013 http://qiita.com/advent-calendar/2013/mruby・Code Reading Wiki http://www.dzeta.jp/~junjis/code_reading/index.php?FrontPage