注 classは高性能なmoduleなので、classにおいてできることはmoduleにも適用できる場合が多い
##classとmoduleの比較
classはインスタンスをもつ
moduleはメソッド群
メソッドを定義するとself(カレントクラス)のインスタンスメソッドになる
クラスの定義の中ではカレントクラスとカレントobject(self)は同じである
クラスへの参照を持っていれば、クラスはclass_evalで参照できる
##クラスインスタンス変数
インスタンス変数の定義する場所によって、そのインスタンス変数をもつclassが異なることに気をつけなくてはいけない
メソッドの中ではメソッドのレシーバがselfになる、よって、インスタンスメソッドの中ではそのインスタンスがselfに、classの定義の中ではclass自身がselfになる。(あらゆるクラスはclassクラスのインスタンス クラスの定義内ではselfはclassクラスのインスタンスである、そのクラス自身を参照する)
classクラスのsuperclassはmoduleでmoduleのsuperclassはobjectとなる。だが、objectはclassクラスのインスタンスである。
よってあらゆるクラスはclassクラスのインスタンスである。また、新しく生成されたclassのsuperclassはobjectだが、これもクラスはclassである。また、class自身も例外ではなく、classクラスはclassクラスのインスタンスである。
ただ、ここで注意しなくてはならないのは継承しているということとそのクラスのインスタンスであるということは違うということ。継承はメソッドの引き継ぎ、インスタンスは継承されてきたものによって作られたクラスを用いた物体。
class Myclass
@my_var = 1
end
クラス定義の中ではselfはクラス自身になるので、@my_varはクラスに属していることになる。
よって、クラスのインスタンス変数とクラスのオブジェクトのインスタンス変数は別物になることを注意しなくてはならない
class Myclass
@my_var = 1
def self.read; @my_var; end
def write; @my_var = 2; end
def read; @my_var; end
end
obj = Myclass.new
obj.read #=> nil
obj.write
obj.read #=> 2
Myclass.read #=> 1
Myclassのインスタンスメソッドはwriteとreadで、objのメソッドでもある。
特異メソッド
rubyでは特定のobjectに対してメソッドを追加できる。
例えば、
a = User.find(3)
def a.black?
true if self.name == "ウエハラ"
end
的な
これはclassメソッドも実は特異メソッドで、classクラスの特定のobjectに対してメソッドを追加していることになるから。
特異メソッドが出た場合、メソッドの継承チェーンに特異クラスが挟まれる。つまり、そのobjectは特異クラスのインスタンスになる。特異クラスのインスタンスは通常のclassを継承しているので、それまで通りに使うことができる。つまり、moduleを挟み込むのと同じイメージ。
##ダックタイピング
静的型付け言語ではそのobjectがTの型を持つのはそのTクラスに属しているからだと考える。
動的型付け言語ではそのobjectがDuckクラスに属しているかどうかは重要ではない、そのメソッドが反応するかどうかである。
rubyではインスタンスのクラスがどのような継承関係をもっていても、ある特定のメソッドに応答できさえすればレシーバーとして振る舞うような処理がかける。
##メソッドラッパー
メソッドの書き換えに3つの方法がある。
### アラウンドエイリアス
class String
alias_method :real_length, :length
def length
real_length > 5 ? 'long' : 'short'
end
end
"War and Peace".length # => "long" ①
"War and Peace".real_length # => 13 ②
①の場合:まず、新しく定義されているlengthに入る。その中で、real_lengthが呼ばれ、aliasにしたがって、もともとのlengthが呼ばれ、13が返ってくる。13に対し評価を行い"long"という結果になる。
②の場合:real_lengthを呼ぶとaliasにしたがってlengthが返ってくる。
このようにlengthを再定義することが可能である。
他にもmodule内でsuperを使って再定義したメソッドを使うという手もある。
module ExplicitString
def length
super > 5 ? 'long' : 'short'
end
end
String.class_eval do
prepend ExplicitString
end
"War and Peace".length # => "long"