オブジェクトモデル
オープンクラス
既存のクラスをオープンしてメソッドを追加すること
class String def to_alphanumeric gsub /[^\w\s]/, '' end end
既に同名のメソッドが存在するのに、オープンクラスで追加してしまうとエラーになる。何も考えずにクラスにコードを追加してしまうことを「モンキーパッチ」と呼ぶそうだ。
オブジェクト、クラス
Java等の静的言語と違いオブジェクトのインスタンス変数はクラスと何のつながりもなく値を代入した時に始めて出現する。
class MyClass def my_method @v = 1 end end
obj = MyClass.new #この時点ではインスタンス変数は存在しない obj.my_method #ここで始めてインスタンス変数が出現する
メソッドはオブジェクトには存在しない。オブジェクトにはクラスへの参照だけがある。メソッドはクラスに存在している。クラスに定義されているメソッドをインスタンスメソッドと呼ぶ。
String.instance_methods == "abc".methods # true String.methods == "abc".methods # false
Rubyではクラスもオブジェクトである。クラスにもクラスがある。クラスはClassクラスのインスタンスということ。
"hello".class # String String.class # Class
クラスにもオブジェクトと同じようにメソッドがある。オブジェクトのメソッドはクラスのインスタンスメソッドなのでクラスのメソッドはClassクラスのインスタンスメソッドでもある
inherited = false Class.instance_methods(inherited) #[:superclass, :allocate, :new]
すべてのクラスはObjectクラスを継承している。ObjectクラスはBasicObjectクラスを継承している。ClassクラスはModuleを継承している。ModuleはObjectクラスを継承している。
クラスはModuleにnew(),allocate(),superclass()を追加しただけのもの。クラスとモジュールはほとんど同じもの。
大文字で始まる参照はクラス、モジュール含めてすべて定数になる。そのためnamespaceの役割でModuleを使用することができる。
module MyModule OuterConstant = 'hoge' class MyClass InnerConstant = 'fuga' end end
MyModule::MyClass::InnerConstantでアクセスできる。
メソッド探索
メソッドを呼び出す時、Rubyはオブジェクトのクラスを探索してメソッドを見つける。レシーバとは呼び出すメソッドが属するオブジェクトのこと。メソッドを探すため、Rubyがレシーバのクラスに背理、メソッドを見つけるまで継承チェーンを上る。
モジュールをincludeする時Rubyは無名クラスを作ってモジュールをラップし継承チェーンに挿入する(インクルードするクラスの真上に入る)。
module M def my_method 'M#hoge' end end class C include M end class D < C; end
実効結果
D.new.my_method # M#hoge
print等のどこからでも呼び出せるメソッドはKernelモジュールのプライベートインスタンスメソッド。ObjectクラスがKernelモジュールをインクルードしているのでKernelモジュールのメソッドはどこからでも呼び出せる。
Rubyのコードはカレントオブジェクトの内部で実行される。カレントオブジェクトはselfキーワードでアクセスでき、selfとも呼ぶ。selfの役割を担うオブジェクトは同時に複数存在しない。メソッドを呼び出すときはレシーバがselfになる。レシーバを指定しない場合はselfに対するメソッド呼び出しになる。
クラス、モジュールの定義の中(メソッドの外側)では、selfはクラスやモジュールになる。
class MyClass self # MyClass end
モジュールを二つincludeした場合、後のモジュールをincludeすると先のモジュールを継承チェーンの上に押し上げる。そのため先にincludeしたモジュールが後のモジュールのスーパークラスになる。
class MyClass include Hoge include Fuga ancestors #[MyClass, Fuga,Hoge, Object, Kernel, BasicObject] end