SlideShare uma empresa Scribd logo
1 de 35
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 はほぼ解析可能です

Mais conteúdo relacionado

Mais procurados

Java 7 invokedynamic の概要
Java 7 invokedynamic の概要Java 7 invokedynamic の概要
Java 7 invokedynamic の概要
Taku Miyakawa
 
ラムダと invokedynamic の蜜月
ラムダと invokedynamic の蜜月ラムダと invokedynamic の蜜月
ラムダと invokedynamic の蜜月
Taku Miyakawa
 
Boost.Flyweight
Boost.FlyweightBoost.Flyweight
Boost.Flyweight
gintenlabo
 
Nodejuku01 ohtsu
Nodejuku01 ohtsuNodejuku01 ohtsu
Nodejuku01 ohtsu
Nanha Park
 
第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」
yoshiaki iwanaga
 

Mais procurados (20)

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

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

Ruby2.0 - refinements - 鳥取Ruby会 第11回
Ruby2.0 - refinements - 鳥取Ruby会 第11回Ruby2.0 - refinements - 鳥取Ruby会 第11回
Ruby2.0 - refinements - 鳥取Ruby会 第11回
Rie HIRONO
 
Rails初心者レッスン lesson4 2edition
Rails初心者レッスン lesson4 2editionRails初心者レッスン lesson4 2edition
Rails初心者レッスン lesson4 2edition
Satomi Tsujita
 
RubyとActive Support for expert 2
RubyとActive Support for expert 2RubyとActive Support for expert 2
RubyとActive Support for expert 2
xibbar
 
20110820 metaprogramming
20110820 metaprogramming20110820 metaprogramming
20110820 metaprogramming
Masanori Kado
 
Rcppを使って動的もしくは共有ライブラリ (dylib, soファイル)を用いた関数(パッ ケージ)を作る
Rcppを使って動的もしくは共有ライブラリ (dylib, soファイル)を用いた関数(パッ ケージ)を作るRcppを使って動的もしくは共有ライブラリ (dylib, soファイル)を用いた関数(パッ ケージ)を作る
Rcppを使って動的もしくは共有ライブラリ (dylib, soファイル)を用いた関数(パッ ケージ)を作る
Satoshi Minakuchi
 

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

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

Mais de baban ba-n

プログラミング言語Cyanの紹介
プログラミング言語Cyanの紹介プログラミング言語Cyanの紹介
プログラミング言語Cyanの紹介
baban ba-n
 
Rubyのソースコードを読んでみよう(入門編)
Rubyのソースコードを読んでみよう(入門編)Rubyのソースコードを読んでみよう(入門編)
Rubyのソースコードを読んでみよう(入門編)
baban ba-n
 

Mais de baban ba-n (12)

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

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