まつもと ゆきひろ@トヨタケーラムです.
ruby拡張モジュール作成講座の2回目です.
--
2.rubyの機能を使う
原理的にrubyで書けることはCでも書けます.rubyそのものがCで記
述されているんですから,当然といえば当然なんですけど.ここで
はrubyの拡張に使うことが多いだろうと予測される機能を中心に紹
介します.
2.1 rubyに機能を追加する
rubyで提供されている関数を使えばrubyインタプリタに新しい機能
を追加することができます.rubyでは以下の機能を追加する関数が
提供されています.
* クラス,モジュール
* メソッド,特異メソッドなど
* 定数
では順に紹介します.
2.1.1 クラス/モジュール定義
クラスやモジュールを定義するためには,以下の関数を使います.
VALUE rb_define_class(char *name, VALUE super)
VALUE rb_define_module(char *name)
これらの関数は新しく定義されたクラスやモジュールを返します.
メソッドや定数の定義にこれらの値が必要なので,ほとんどの場合
は戻り値を変数に格納しておく必要があるでしょう.
2.1.2 メソッド/特異メソッド定義
メソッドや特異メソッドを定義するには以下の関数を使います.
void rb_define_method(VALUE class, char *name,
VALUE (*func)(), int argc)
void rb_define_sigleton_method(VALUE object, char *name,
VALUE (*func)(), int argc)
念のため説明すると「特異メソッド」とは,その特定のオブジェク
トに対してだけ有効なメソッドです.rubyではよくSmalltalkにお
けるクラスメソッドとして,クラスに対する特異メソッドが使われ
ます.
これらの関数の argcという引数はCの関数へ渡される引数の数(と
形式)を決めます.argcが正の時は関数に引き渡す引数の数を意味
します.16個以上の引数は使えません(が,要りませんよね,そん
なに).
argcが負の時は引数の数ではなく,形式を指定したことになります.
argcが-1の時は引数を配列に入れて渡されます.argcが-2の時は引
数はrubyの配列として渡されます.
メソッドを定義する関数はもう二つあります.ひとつはprivateメ
ソッドを定義する関数で,引数はrb_define_method()と同じです.
void rb_define_private_method(VALUE class, char *name,
VALUE (*func)(), int argc)
privateメソッドとは関数形式でしか呼び出すことの出来ないメソッ
ドです.
もうひとつはモジュール関数を定義するものです.モジュール関数
とはモジュールの特異メソッドであり,同時にprivateメソッドで
もあるものです.例をあげるとMathモジュールのsqrt()などがあげ
られます.このメソッドは
Math.sqrt(4)
という形式でも
include Math
sqrt(4)
という形式でも使えます.モジュール関数を定義する関数は以下の
通りです.
void rb_define_private_method(VALUE module, char *name,
VALUE (*func)(), int argc)
2.1.3 定数定義
拡張モジュールが必要な定数はあらかじめ定義しておいた方が良い
でしょう.定数を定義する関数は二つあります.
void rb_define_const(VALUE class, char *name, VALUE val)
void rb_define_global_const(char *name, VALUE val)
前者は特定のクラス/モジュールに属する定数を定義するもの,後
者はグローバルな定数を定義するものです.
2.2 rubyの機能をCから呼び出す
既に『1.5 rubyのデータを操作する』で一部紹介したような関数を
使えば,rubyの機能を実現している関数を直接呼び出すことが出来
ます.
# このような関数の一覧表はいまのところありません.ソースを見
# るしかないですね.
それ以外にもrubyの機能を呼び出す方法はいくつかあります.
2.2.1 rubyのプログラムをevalする
Cからrubyの機能を呼び出すもっとも簡単な方法として,文字列で
与えられたrubyのプログラムを評価する関数があります.
VALUE rb_eval_string(char *str)
この評価は現在の環境で行われます.つまり,現在のローカル変数
やselfなどを受け継ぎます.
2.2.2 IDまたはシンボル
Cから文字列を経由せずにrubyのメソッドを呼び出すこともできま
す.その前に,rubyインタプリタ内でメソッドや変数名を指定する
時に使われているIDについて説明しておきましょう.
IDとは変数名,メソッド名を表す整数です.rubyの中では
:識別子
でアクセスできます.Cからこの整数を得るためには関数
rb_intern(char *name)
を使います.
2.2.3 Cからrubyのメソッドを呼び出す
Cから文字列を経由せずにrubyのメソッドを呼び出すためには以下
の関数を使います.
VALUE rb_funcall(VALUE recv, ID mid, int argc, ...)
この関数はオブジェクトrecvのmidで指定されるメソッドを呼び出
します.
2.2.4 変数/定数を参照/更新する
Cから関数を使って参照・更新できるのは,クラス定数,インスタ
ンス変数です.大域変数は一部のものはCの大域変数としてアクセ
スできます.ローカル変数を参照する方法は公開していません.
オブジェクトのインスタンス変数を参照・更新する関数は以下の通
りです.
rb_ivar_get(VALUE obj, ID id)
rb_ivar_get(VALUE obj, ID id, VALUE val)
idはrb_intern()で得られるものを使ってください.
クラス定数を参照するには以下の関数を使ってください.
rb_const_get(VALUE obj, ID id)
クラス定数を新しく定義するためには『2.1.3 定数定義』で紹介さ
れている関数を使ってください.