rubyのインスタンスメソッドとクラスメソッド

gold対策。(基礎力確認問題11)

class Cls1
  def Cls1.foo
    puts 'Cls1'
  end
end

class Cls2 < Cls1
  def foo
    puts 'Cls2'
  end
end
Cls2.foo
# >> 'Cls1'
Cls2.new.foo
# >> Cls2

これ自体は、とてもシンプルですが
gold受験だけでなくruby書く上でも
以下のことを理解しておいた方が良いんじゃないかという気がしてきたので
自分の頭の整理のつもりで書いてみます。
 
 

includeでクラスメソッドを追加するには?

 

moduleにクラスメソッドを記述してclassでincludeしてみる

こんな風に書いてみて、うまくいかない経験は結構あるかと思います。

module M
  def self.foo
    puts "M"
  end
end

class Cls1
  include M
end
Cls1.foo
# ~> -:10:in `<main>': undefined method `foo' for Cls1:Class (NoMethodError)

 
 

そこで特異クラスを拡張します

module M
  def foo
    puts "M"
  end
end

class Cls1
  class << self
    include M
  end
end
Cls1.foo
# >> M

クラスメソッドってものが、クラスの特異メソッドであることと
特異メソッドの住む場所が、特異クラスであること
が理解できると分かるようになるかと思います。
このあたりは、メタプログラミングRubyが詳しいので割愛します。
 
 

extend

extendで同様の実装が可能です。

module M
  def foo
    puts "M"
  end
end

class Cls1
  extend M
end
Cls1.foo
# >> M

 
 

ついでにクラスマクロ

ちょっと話がはずれますが

Railsやプラグインのソースコードでよく見る書き方です。
クラスマクロと呼ばれているものです。
attr_accessor()みたいなもんですね。

module M
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def foo(*args)
      puts args
    end
  end
end

class Cls1
  include M
  foo :bar, :baz
end
# >> bar
# >> baz