SlideShare a Scribd company logo
Rubyのコードを読んでみよう:その2
さて今日のお題ですが
コレです
Rubyには他の代表的な言語にない黒魔術的な
メソッドがありますが
その殆どはrubyのクラスの内側に挟み込まれて
存在しています
具体的には
● モンキーパッチング
● eigenclass(self)
● Kernel#define_method
● Object#extend
● Kernel#include
● Object#method_missoing
Etc...
これらの機能はrubyのruby的な
rubyたる、オブジェクト指向と
深く結びついています
今回のお題
これらを手繰りながらrubyの
● クラスって何?
● オブジェクトって何?
● メソッドって何?
” ”という 定義 を辿って行きましょう
細かいこと
● 解析するversionはruby2.0.0-p0でやりますよ!
(1.9系と劇的に違ったりはしていないんですけどね)
Stage1: Classをnewしてみる
クラスの作成(class.c)
スタートはrb_class_new→rb_class_bootを呼
び出してここで初期化している
VALUE
rb_class_new(VALUE super)
{
Check_Type(super, T_CLASS);
rb_check_inheritable(super);
return rb_class_boot(super);
}
rb_class_bootは継承先、継承元の設定をしてい
るだけとっても素直な作り。
VALUE rb_class_boot(VALUE super){
VALUE klass = class_alloc(T_CLASS, rb_cClass);
RCLASS_SUPER(klass) = super;
RCLASS_M_TBL(klass) = st_init_numtable();
OBJ_INFECT(klass, super);
return (VALUE)klass;
}
マクロを展開していくと、RClassなるものが浮
いてくる
VALUE rb_class_boot(VALUE super){
VALUE klass = class_alloc(T_CLASS, rb_cClass);
R_CAST((RClass)(klass))->ptr->iv_tbl = super;
R_CAST((RClass)(klass))->m_tbl = st_init_numtable();
OBJ_INFECT(klass, super);
return (VALUE)klass;
}
Rclass!! クラスの正体はここにある
(rubyのオブジェクトを理解するにはここを起点にすると良い)
struct RClass {
struct RBasic basic;
rb_classext_t *ptr;
struct st_table *m_tbl; // メソッド関係一覧
struct st_table *iv_index_tbl; // インスタンス変数一覧
};
そして、メソッドは、実はforループで探索
して呼び出されている
int st_lookup(st_table *table, register st_data_t key, st_data_t *value){
...
st_index_t i;
for (i = 0; i < table->num_entries; i++) {
if ((st_data_t)table->bins[i*2] == key) {
if (value !=0) *value = (st_data_t)table->bins[i*2+1];
return 1;
}
}
...
まとめ:その1
● クラスはCの構造体
● 抑えておくべきデータ型はクラスの本体
RClassこれを作っている
Stage2: methodをdefineしてみる
Kernel#define_methodの解説
● define_methodの定義はproc.cにあるのでそこ
から順番に手繰る
● rb_define_private_method(rb_cModule, "define_method",
rb_mod_define_method, -1); // proc.c
● rb_mod_define_method(int argc, VALUE *argv, VALUE mod)
● rb_method_entry_set(mod, id, method->me, noex); // vm_method.c
● rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type,
rb_method_definition_t *def, rb_method_flag_t noex)
● st_insert(register st_table *table, register st_data_t key, st_data_t value)
st_insert(register st_table *table, register st_data_t key, st_data_t value)
このメソッドの、st_tableって構造体
…何処かで見たような気が
メソッドの挿入をしているst_insert
● st_insert(register st_table *table, register st_data_t key, st_data_t value)
このメソッドの、st_tableって構造体
…何処かで見たような気が
struct RClass {
struct RBasic basic;
rb_classext_t *ptr;
struct st_table *m_tbl; // メソッド関係一覧
struct st_table *iv_index_tbl; // インスタンス変数一覧
};
st_insert解読
st_insertの定義は呼び出し先の挙動を見たほうが早い
実はループで重複を探して、重複したものが無ければメ
ソッド挿入をしているだけ
int st_insert(register st_table *table, register st_data_t key, st_data_t value){
...
for (i = 0; i < table->num_entries; i++) {
if ((st_data_t)table->bins[i*2] == key) {
table->bins[i*2+1] = (struct st_table_entry*)value;
return 1;
}
..
}
まとめ2
メソッドは構造体st_tableの内側に、配列として
格納されている
Stage3: モジュールのinclude
Kernel#include,Object#extend
● まずObject#extendの呼び出しを手繰ってみる
以下は呼び出し順
rb_define_method(rb_mKernel, "extend", rb_obj_extend, -1); // eval.c
rb_mod_extend_object(VALUE mod, VALUE obj)
rb_extend_object(VALUE obj, VALUE module)
rb_include_module(VALUE klass, VALUE module)
Kernel#include
● 次にKernel#includeの呼び出しを手繰る
● rb_define_private_method(rb_cModule, "include", rb_mod_include, -1); // eval.c
● rb_funcall(argv[argc], rb_intern("append_features"), 1, module);
● rb_include_module(VALUE include, VALUE module); // ここでつながる
rb_include_module で繋がる
2つは根が同じもの
rb_include_module内約
● その内側は、実はスーパークラスの指定をしているだけ
include_modules_at(VALUE klass, VALUE c, VALUE module){
/* 色々と事前のチェック */
c = RCLASS_SUPER(c) = rb_include_class_new(module, RCLASS_SUPER(c));
}
Module#prepend
● Ruby2.0で追加されたModule#prependでも似
たようなもの
● ” ” ” ”継承順のリストに 追記 ではなく 挿入 をして
いるだけ
● 関数名は書いておくので興味があったら確認
してね
● rb_define_private_method(rb_cModule, "prepend", rb_mod_prepend, -1); // ./eval.c:
rb_mod_prepend(int argc, VALUE *argv, VALUE module)
rb_prepend_module(VALUE klass, VALUE module)
まとめ3
● includeはModuleを使った継承
● Kernel#includeとObject#extendは根っこは同じ
● Kernel#include、Object#extend、Module#prepe
ndって実は継承順序の内側に挟みこみをして
いるだけ
Stage4: method_missingの呼ばれ方
method_missing解説
メソッドの呼ばれ方(rb_call0)を探せば簡単
./vm_eval.c
● static inline VALUE rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv, call_type scope,
VALUE self){
rb_method_entry_t *me = rb_search_method_entry(recv, mid); // method_missingでないメソッド
rb_thread_t *th = GET_THREAD();
int call_status = rb_method_call_status(th, me, scope, self);
if (call_status != NOEX_OK) {
return method_missing(recv, mid, argc, argv, call_status); // ここでmethod_missingを読んでいる
}
stack_check();
return vm_call0(th, recv, mid, argc, argv, me);
}
普通のメソッドの場合
● メソッド探索のの順を手繰っていくと
● rb_search_method_entry
● rb_method_entry
● rb_method_entry_get_without_cache
● search_method
● st_lookup(st_table *table, register st_data_t key,
st_data_t *value)
st_lookupに突き当たる
● そして、st_lookupってdefine_methodの所で見
た!!
int st_lookup(st_table *table, register st_data_t key, st_data_t *value){
...
st_index_t i;
for (i = 0; i < table->num_entries; i++) {
if ((st_data_t)table->bins[i*2] == key) {
if (value !=0) *value = (st_data_t)table->bins[i*2+1];
return 1;
}
}
...
まとめ
● vm_call0 関数でクラスを指定
● Rclass を継承順に沿って探索
● st_lookup 関数で内部のメソッドを探索
● st_table 内部にあるメソッドを探す
これがrubyのメソッド探索順序
まとめ
● クラスの定義
● 継承順の定義
● メソッドの定義
● これらを合わせてメソッドの探索順を探した
…ことになりましたが
次回の予定
● もうコレ系のネタやめていいかなと思ってい
ますが
ネタがない場合、多分構文解析の部分やりま
す
大事なこと
● 今までのコード rb_define_method でメソッド
名でgrep して、そこから手繰る事で、すべて
やってこれました
● これだけでruby はほぼ解析可能です

More Related Content

PDF
TypeScript & 関数型講座 第2回 TypeScript という言語
PDF
JVMの中身を可視化してみた
PDF
Java開発の強力な相棒として今すぐ使えるGroovy
PDF
Hacking Ruby with Python
PPTX
JJUG CCC 2017 Fall オレオレJVM言語を作ってみる
PDF
JJUG CCC 2013 Fall「JVMコードリーディング入門-JVMのOS抽象化レイヤーについて-」
PPTX
資料
PDF
Rubyの拡張をCrystalで書いてみる
TypeScript & 関数型講座 第2回 TypeScript という言語
JVMの中身を可視化してみた
Java開発の強力な相棒として今すぐ使えるGroovy
Hacking Ruby with Python
JJUG CCC 2017 Fall オレオレJVM言語を作ってみる
JJUG CCC 2013 Fall「JVMコードリーディング入門-JVMのOS抽象化レイヤーについて-」
資料
Rubyの拡張をCrystalで書いてみる

What's hot (20)

PDF
Unityで覚えるC#
PPTX
メタプログラミングってなに?
PDF
js-ctypes - ネイティブコードを呼び出す新しいカタチ
PDF
Haml 学習コース 初級編
PDF
Java 7 invokedynamic の概要
PDF
JavaScript経験者のためのGo言語入門
PDF
ラムダと invokedynamic の蜜月
PPT
第4回勉強会 Groovyの文法からSpockまで
PDF
プログラムの処方箋~健康なコードと病んだコード
PDF
Boost.Flyweight
PDF
JavaScript基礎勉強会
PDF
C++でCプリプロセッサを作ったり速くしたりしたお話
KEY
JJUG CCC 2012 Real World Groovy/Grails
PDF
第2回勉強会スライド
PDF
覚醒!JavaScript
PDF
Nodejuku01 ohtsu
PDF
Swift 2.0 大域関数の行方から #swift2symposium
PDF
第三回ありえる社内勉強会 「いわががのLombok」
PDF
第1回勉強会スライド
PPTX
JEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_ccc
Unityで覚えるC#
メタプログラミングってなに?
js-ctypes - ネイティブコードを呼び出す新しいカタチ
Haml 学習コース 初級編
Java 7 invokedynamic の概要
JavaScript経験者のためのGo言語入門
ラムダと invokedynamic の蜜月
第4回勉強会 Groovyの文法からSpockまで
プログラムの処方箋~健康なコードと病んだコード
Boost.Flyweight
JavaScript基礎勉強会
C++でCプリプロセッサを作ったり速くしたりしたお話
JJUG CCC 2012 Real World Groovy/Grails
第2回勉強会スライド
覚醒!JavaScript
Nodejuku01 ohtsu
Swift 2.0 大域関数の行方から #swift2symposium
第三回ありえる社内勉強会 「いわががのLombok」
第1回勉強会スライド
JEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_ccc
Ad

Similar to Rubyのコードを読んでみよう(オブジェクト編) (20)

PDF
Ruby2.0 - refinements - 鳥取Ruby会 第11回
PDF
Ruby2.0について
PDF
Rails初心者レッスン lesson4 2edition
PDF
mruby for embedded systems
PDF
RubyとActive Support for expert 2
PPTX
DrupalでBDDテストを実施してみる①
PDF
「愛されたい!」と思ったときにJavaで書くRubyクラス
PDF
named_scope more detail
PDF
Android アプリ開発における Gradle ビルドシステム
PDF
Rubyのオブジェクト図をもう一度
PDF
mruby を C# に 組み込んでみる
PDF
Rubyにメソッドを追加して遊ぶ話
PDF
バカでもわかるRails #05
PDF
20110820 metaprogramming
PDF
Rcppを使って動的もしくは共有ライブラリ (dylib, soファイル)を用いた関数(パッ ケージ)を作る
PDF
Railsの開発環境作るぞ
PDF
名古屋Ruby会議02 LT:Ruby中級への道
PDF
Grails 2.0.0.M1の話
PDF
Haskell 6-module
Ruby2.0 - refinements - 鳥取Ruby会 第11回
Ruby2.0について
Rails初心者レッスン lesson4 2edition
mruby for embedded systems
RubyとActive Support for expert 2
DrupalでBDDテストを実施してみる①
「愛されたい!」と思ったときにJavaで書くRubyクラス
named_scope more detail
Android アプリ開発における Gradle ビルドシステム
Rubyのオブジェクト図をもう一度
mruby を C# に 組み込んでみる
Rubyにメソッドを追加して遊ぶ話
バカでもわかるRails #05
20110820 metaprogramming
Rcppを使って動的もしくは共有ライブラリ (dylib, soファイル)を用いた関数(パッ ケージ)を作る
Railsの開発環境作るぞ
名古屋Ruby会議02 LT:Ruby中級への道
Grails 2.0.0.M1の話
Haskell 6-module
Ad

More from baban ba-n (12)

ODP
Typusとadministrateを比較してみよう
ODP
Typusと付き合ってきた話
ODP
ハッカソン。来た、見た、負けた! Spajam2016仙台予選
ODP
ガラホ、なるものに対応してきた
ODP
Minitest調べてみた
ODP
人工言語ロジバン超入門編
ODP
普通のエンジニアが【ロジバン】やってみた
ODP
プログラミング言語Cyanの紹介
ODP
Rubyのソースコードを読んでみよう(入門編)
ODP
rails 管理画面作成gem Typus解説
PDF
名前重要 超重要
ODP
Rails-Plugin Flexturesの紹介
Typusとadministrateを比較してみよう
Typusと付き合ってきた話
ハッカソン。来た、見た、負けた! Spajam2016仙台予選
ガラホ、なるものに対応してきた
Minitest調べてみた
人工言語ロジバン超入門編
普通のエンジニアが【ロジバン】やってみた
プログラミング言語Cyanの紹介
Rubyのソースコードを読んでみよう(入門編)
rails 管理画面作成gem Typus解説
名前重要 超重要
Rails-Plugin Flexturesの紹介

Rubyのコードを読んでみよう(オブジェクト編)