mrubyを読む
はじめに †
最近、mrubyのAPIを使うサンプルを書こうとしているのですがよい題材が思いつきません。mrubyを使う際にまず知りたいのはmrubyと自分の対象領域のソフトウェアをつなげることだと思うので、今回はmruby本体中の生きたサンプルであるTimeクラスの実装をAPI利用の観点で読んでいきたいと思います。
クラスの定義 †
というわけで、src/time.cのmrb_init_time()を見ていきましょう。
1
2
3
4
5
|
| struct RClass *tc;
tc = mrb_define_class(mrb, "Time", mrb->object_class);
MRB_SET_INSTANCE_TT(tc, MRB_TT_DATA);
mrb_include_module(mrb, tc, mrb_class_get(mrb, "Comparable"));
|
クラスを定義するにはmrb_define_class()を利用します。第2引数にクラス名、第3引数にスーパークラスを指定します。次に、構造体をラップしたクラスであることを示すためにMRB_SET_INSTANCE_TTマクロを使ってMRB_TT_DATAを設定します。MRB_TT_DATAを設定しておかないと後々困ることになるので構造体をラップするクラスでは必ず指定してください。
クラスにモジュールをインクルードする場合はmrb_include_module()を利用します。第2引数で指定したクラスに第3引数のモジュールをインクルードします。モジュール(クラス)を取得したい場合はmrb_class_get()を使って取得を行います。
メソッドの定義 †
ではメソッドの定義に進みます。
1
2
3
4
5
6
|
| mrb_define_class_method(mrb, tc, "at", mrb_time_at, ARGS_ANY());
mrb_define_class_method(mrb, tc, "gm", mrb_time_gm, ARGS_REQ(1)|ARGS_OPT(6));
mrb_define_class_method(mrb, tc, "local", mrb_time_local, ARGS_REQ(1)|ARGS_OPT(6));
mrb_define_class_method(mrb, tc, "mktime", mrb_time_local, ARGS_REQ(1)|ARGS_OPT(6));
mrb_define_class_method(mrb, tc, "now", mrb_time_now, ARGS_NONE());
mrb_define_class_method(mrb, tc, "utc", mrb_time_gm, ARGS_REQ(1)|ARGS_OPT(6));
|
クラスメソッドの定義はmrb_define_class_method()で行います。第2引数で指定したクラスに第3引数のメソッドが定義されます。第4引数にはメソッドが呼ばれたときに呼び出される関数を指定します。
第5引数はメソッドの引数情報で、
- ARGS_ANY()
- 任意の引数を取る
- ARGS_REQ(1)|ARGS_OPT(6)
- 1つの引数は必須でオプション引数が6つある
- ARGS_NONE()
- 引数なし
という意味になります。*1
次にインスタンスメソッドの定義です。利用するAPIがmrb_define_method()になる以外はクラスメソッドの定義と同じです。
1
2
3
|
| mrb_define_method(mrb, tc, "==" , mrb_time_eq , ARGS_REQ(1));
mrb_define_method(mrb, tc, "<=>" , mrb_time_cmp , ARGS_REQ(1));
(以下省略)
|
インスタンスの生成 †
(以下執筆中)
メソッドの実装 †
APIまとめ †
最後にクラス定義・実装に利用するAPIをまとめておきます。一部、上で紹介していないAPIも知っていると便利なので載せておきます。
- struct RClass * mrb_class_get(mrb_state *mrb, const char *name);
- クラスを取得する。第2引数に取得したいクラス名を指定する
- struct RClass *mrb_define_module(mrb_state *mrb, const char *name);
- モジュールを定義する。第2引数にモジュール名を指定する
- struct RClass *mrb_define_class(mrb_state *mrb, const char *name, struct RClass *super);
- クラスを定義する。第2引数にクラス名、第3引数にスーパークラスを指定する
- struct RClass * mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, struct RClass *super);
- 指定モジュール以下にクラスを定義する。第2引数で指定したモジュール以下にクラスが定義される
- void mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m);
- モジュールをインクルードする。第2引数で指定したクラスに第3引数で指定したモジュールをインクルード
- void mrb_define_const(mrb_state *mrb, struct RClass *mod, const char *name, mrb_value v)
- クラス(モジュール)に定数を定義する。第2引数のクラスに第3引数の名前で第4引数の値を定義する
- void mrb_define_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, int aspec);
- インスタンスメソッドを定義する。第2引数のクラスに第3引数の名前のインスタンスメソッドが定義される。メソッドが呼び出されると第4引数で指定した関数が呼び出される。第5引数にはメソッドの引数情報を指定する
- void mrb_define_class_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, int aspec)
- クラスメソッドを定義する。引数の意味はmrb_define_method()と同じ
void
- mrb_define_module_function(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, int aspec);
- モジュール関数を定義する。引数の意味はmrb_define_method()と同じ