ソースを見てみる
Rubyソースコード完全解説を見ながらソースをチェック。object.c の以下の部分の理解が微妙であり、第4章 クラスとモジュールを熟読中。
void Init_Object() { VALUE metaclass; rb_cObject = boot_defclass("Object", 0); rb_cModule = boot_defclass("Module", rb_cObject); rb_cClass = boot_defclass("Class", rb_cModule); metaclass = rb_make_metaclass(rb_cObject, rb_cClass); metaclass = rb_make_metaclass(rb_cModule, metaclass); metaclass = rb_make_metaclass(rb_cClass, metaclass); rb_mKernel = rb_define_module("Kernel"); rb_include_module(rb_cObject, rb_mKernel); rb_define_alloc_func(rb_cObject, rb_class_allocate_instance); rb_define_private_method(rb_cObject, "initialize", rb_obj_dummy, 0); rb_define_private_method(rb_cClass, "inherited", rb_obj_dummy, 1); rb_define_private_method(rb_cModule, "included", rb_obj_dummy, 1); rb_define_private_method(rb_cModule, "extended", rb_obj_dummy, 1); rb_define_private_method(rb_cModule, "method_added", rb_obj_dummy, 1); rb_define_private_method(rb_cModule, "method_removed", rb_obj_dummy, 1); rb_define_private_method(rb_cModule, "method_undefined", rb_obj_dummy, 1); rb_define_method(rb_mKernel, "nil?", rb_false, 0); (以下略)
再読三読四読 ...
# class.c も見つつ
追記
うーん。分かったような分からないような。
とりあえず、object.c において Class と Object と Module 関連の手続きを抜き出してみる。まず、Object について。
rb_cObject = boot_defclass("Object", 0); metaclass = rb_make_metaclass(rb_cObject, rb_cClass); rb_include_module(rb_cObject, rb_mKernel); rb_define_alloc_func(rb_cObject, rb_class_allocate_instance); rb_define_private_method(rb_cObject, "initialize", rb_obj_dummy, 0); ruby_top_self = rb_obj_alloc(rb_cObject);
記述がつながっているように見えますが grep の出力です。上から順に
- クラスの定義 (スーパークラスは無し)
- メタクラスの生成 (クラスメソドの定義、と決めうち)
- Kernel モジュールの include
- allocate メソドの定義
- initialize (プライベートメソド) の定義
- rb_obj_alloc で実体の生成??
rb_obj_alloc 関数については、第5章 ガーベージコレクション に記述あり。allocate はしてますが initialize は Qnil 返却する関数になってるし initialize してない風に見える。ちなみに現行のリファレンスマニュアルにも何もしない、と書いてあるんで上記の理解でセイフかなぁ。
ちなみに
metaclass = rb_make_metaclass(rb_cObject, rb_cClass);
ですが、Object のメタクラス (特異クラス) を生成していて、それは Class を継承している、という読み方でセイフかなぁ。という事は Class で定義されているメソドはクラスメソドとして Object に実装される、と考えて良いのだろうか。
という事は、Class において定義されている
rb_define_method(rb_cClass, "allocate", rb_obj_alloc, 0); rb_define_method(rb_cClass, "new", rb_class_new_instance, -1); rb_define_method(rb_cClass, "initialize", rb_class_initialize, -1); rb_define_method(rb_cClass, "initialize_copy", rb_class_init_copy, 1); /* in class.c */ rb_define_method(rb_cClass, "superclass", rb_class_superclass, 0);
等は Object のクラスメソドとして継承されるの??
それぞれ 1.8.5 な irb で確認を。
irb(main):001:0> Object.allocate => #<Object:0x40235060> irb(main):002:0> Object.new => #<Object:0x40231960> irb(main):003:0> Object.initialize NoMethodError: private method `initialize' called for Object:Class from (irb):3 from :0 irb(main):004:0> Object.initialize_copy NoMethodError: private method `initialize_copy' called for Object:Class from (irb):4 from :0 irb(main):005:0> Object.superclass => nil irb(main):006:0>
うーん。initialize は object.c の Init_Object() で private 化しているんですが、initialize_copy はどこで操作しているのだろうか。って現行マニュアルの Object クラスの説明において以下のような記述を発見。
initialize_copy という名前のメソッドは自動的に private に設定されます。
なにー。根拠は何だ、と言いつつ initialize_copy で grep かけたら
./doc/ChangeLog-1.8.0: * eval.c (rb_add_method): initialize_copy should always be
みたいな出力が。doc/ChangeLog-1.8.0 を覗いてみると
Mon May 19 13:58:03 2003 Yukihiro Matsumoto <matz@ruby-lang.org> * object.c (init_copy): rename copy_object as initialize_copy, since it works as copy constructor. * eval.c (rb_add_method): initialize_copy should always be private, like initialize.
とある。eval.c の rb_add_method ですか。このあたりの処理??
if (!FL_TEST(klass, FL_SINGLETON) && node && nd_type(node) != NODE_ZSUPER && (mid == rb_intern("initialize" )|| mid == rb_intern("initialize_copy"))) { noex = NOEX_PRIVATE | noex; }
キッツいなぁ。Rubyソースコード完全解説をきっちり読まないと駄目そげ。
ってーか、何してるんだかワケワカ状態だ。何しようとしてたのか、というとマニュアル原本とソースの整合性を確認しようとしてたんだった。とりあえず、マニュアルのソースからメソド部分を抜き出してみた。
$ grep '^---' refm/api/src/_builtin/Object|sort -k 2 --- ==(other) --- ===(other) --- =~(other) --- __id__ --- __send__(name, *args) --- __send__(name, *args) { .... } --- _dump(limit) --- class --- clone --- display(out = $stdout) --- dup --- enum_for(method = :each, *args) --- eql?(other) --- equal?(other) --- extend(*modules) --- freeze --- frozen? --- hash --- id --- initialize --- initialize_copy(obj) --- inspect --- instance_eval {|obj| ... } --- instance_eval(expr, filename = '(eval)', lineno = 1) --- instance_of?(klass) --- instance_variable_defined?(symbol) --- instance_variable_get(var) --- instance_variable_set(var, val) --- instance_variables --- is_a?(mod) --- kind_of?(mod) --- marshal_dump --- marshal_load(obj) --- method(name) --- method_missing(name, *args, &block) --- methods --- methods([inherited_too]) --- new --- nil? --- object_id --- private_methods --- private_methods([inherited_too]) --- protected_methods --- protected_methods([inherited_too]) --- public_methods --- public_methods([inherited_too]) --- remove_instance_variable(name) --- respond_to?(name, include_private = false) --- send(name, *args) --- send(name, *args) { .... } --- singleton_method_added(name) --- singleton_method_removed(name) --- singleton_method_undefined(name) --- singleton_methods --- singleton_methods(inherited_too = false) --- singleton_methods(inherited_too = true) --- taint --- tainted? --- to_a --- to_ary --- to_enum(method = :each, *args) --- to_hash --- to_int --- to_s --- to_str --- type --- untaint $
マニュアルのソースにおいて、クラスメソドとして記述されているのは new だけ。それ以外は instance methods として記述されているんですが、現時点で全部ヒモが付いていない感じ。
とりあえず Object は Kernel モジュール を include してるんで Kernel 関連も抜き出してみる。でもまだ足りてない感じ。
rb_mKernel = rb_define_module("Kernel"); rb_define_method(rb_mKernel, "nil?", rb_false, 0); rb_define_method(rb_mKernel, "==", rb_obj_equal, 1); rb_define_method(rb_mKernel, "equal?", rb_obj_equal, 1); rb_define_method(rb_mKernel, "===", rb_equal, 1); rb_define_method(rb_mKernel, "=~", rb_obj_pattern_match, 1); rb_define_method(rb_mKernel, "eql?", rb_obj_equal, 1); rb_define_method(rb_mKernel, "id", rb_obj_id_obsolete, 0); rb_define_method(rb_mKernel, "type", rb_obj_type, 0); rb_define_method(rb_mKernel, "class", rb_obj_class, 0); rb_define_method(rb_mKernel, "clone", rb_obj_clone, 0); rb_define_method(rb_mKernel, "dup", rb_obj_dup, 0); rb_define_method(rb_mKernel, "initialize_copy", rb_obj_init_copy, 1); rb_define_method(rb_mKernel, "taint", rb_obj_taint, 0); rb_define_method(rb_mKernel, "tainted?", rb_obj_tainted, 0); rb_define_method(rb_mKernel, "untaint", rb_obj_untaint, 0); rb_define_method(rb_mKernel, "freeze", rb_obj_freeze, 0); rb_define_method(rb_mKernel, "frozen?", rb_obj_frozen_p, 0); rb_define_method(rb_mKernel, "to_a", rb_any_to_a, 0); /* to be removed */ rb_define_method(rb_mKernel, "to_s", rb_any_to_s, 0); rb_define_method(rb_mKernel, "inspect", rb_obj_inspect, 0); rb_define_method(rb_mKernel, "methods", rb_obj_methods, -1); rb_define_method(rb_mKernel, "singleton_methods", rb_obj_singleton_methods, -1); /* in class.c */ rb_define_method(rb_mKernel, "protected_methods", rb_obj_protected_methods, -1); rb_define_method(rb_mKernel, "private_methods", rb_obj_private_methods, -1); rb_define_method(rb_mKernel, "public_methods", rb_obj_public_methods, -1); rb_define_method(rb_mKernel, "instance_variables", rb_obj_instance_variables, 0); /* in variable.c */ rb_define_method(rb_mKernel, "instance_variable_get", rb_obj_ivar_get, 1); rb_define_method(rb_mKernel, "instance_variable_set", rb_obj_ivar_set, 2); rb_define_private_method(rb_mKernel, "remove_instance_variable", rb_obj_remove_instance_variable, 1); /* in variable.c */ rb_define_method(rb_mKernel, "instance_of?", rb_obj_is_instance_of, 1); rb_define_method(rb_mKernel, "kind_of?", rb_obj_is_kind_of, 1); rb_define_method(rb_mKernel, "is_a?", rb_obj_is_kind_of, 1); rb_define_private_method(rb_mKernel, "singleton_method_added", rb_obj_dummy, 1); rb_define_private_method(rb_mKernel, "singleton_method_removed", rb_obj_dummy, 1); rb_define_private_method(rb_mKernel, "singleton_method_undefined", rb_obj_dummy, 1);
うーむ。長い。
てーか、ぐだぐだ感満載だなぁ。