【Ruby】メタクラス。クラスメソッド定義の意味。
クラスメソッドの定義方法
この2つの方法はどちらも同じ意味となる。
class MailTruck def self.add( truck ) @@trucks << truck end end
と
class MailTruck class << self #<= 特異クラスをオープン def add( truck ) @@trucks << truck end end end
この例では、addはClassクラスオブジェクト(MailTruck)の特異メソッド。
Rubyでは必ず、メソッドはオブジェクトではなくクラスによって保持される。
→これはあくまで実装上そうだというだけで本質的な理解ではない。
メタクラスは「特異メソッドのロード(スーパークラスのメソッドをなぜ名前解決できるのか)」
の文脈だけでしか語らないようにする。
(10月15日追記)
つまり、クラスメソッドはそのクラスの特異クラス(メタクラス)によって保持される。
さっきの下の例が分かり易い。
特異クラスをオープンして、そこにメソッドを追加している。
メタクラスは継承チェインに割り込んで、
クラスのメソッドより先に呼び出されるようになる。
また、メタクラスも(クラスと同じように)スーパークラスをもつ。
子クラスにメソッドを追加する
Objectにメソッドを追加して、
class Object # 特異クラスはどこにでも隠れてる。 def metaclass; class << self; self; end; end def meta_eval &blk; metaclass.instance_eval &blk; end # メタクラスにメソッドを追加 def meta_def name, &blk meta_eval { define_method name, &blk } end # クラスの中でインスタンスメソッドを定義 def class_def name, &blk class_eval { define_method name, &blk } end end
こうやって書くと、子クラスにメソッドを定義できる。
親クラスのcompメソッド内のコンテキストが
HappyTruckクラスオブジェクトになるから、まあそうだよね。
class MailTruck def self.comp( name ) meta_def :company do name end end end class HappyTruck < MailTruck comp "Happy's -- We Bring the Mail, and That's It!" end p HappyTruck.company #<= "Happy's -- We Bring the Mail, and That's It!"
上のメソッドはきわめてシンプルだが、無限の可能性を秘めている。
そうなんだー。