クラス内でのインスタンスメソッド、クラスメソッドの呼び出し

よくわからなかったのでメモ。環境は Ruby 2.1.5。

以下のようにmixinしたとする。このスクリプトを check_calling_methods.rbとする。

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

  module ClassMethods
    def myhello
      puts 'M, class method, public, hello'
    end

    private
    def myhi
      puts 'M, class method, private, hi'
    end
  end

  def mybye
    puts  'M, instance method, public, bye'
  end

  private
  def mychao
    puts  'M, instance method, private, chao'
  end
end

class C
  include M

  def myhoo
    puts  'C, instance method, public, hoo'
  end

  def self.myyo
    puts  'C, class method, public, yo'
  end

  private
  def myjumbo
    puts  'C, instance method, private, jambo'
  end

  class << self
    private
    def mymanbo
      myhello
      myhi
      puts  'C, class method, private, manbo'
    end
  end
end

puts "--- public instance method"
puts C.instance_methods.grep(/^my/)

puts "--- public class method"
puts C.singleton_methods.grep(/^my/)

puts "--- private instance method"
puts C.private_instance_methods.grep(/^my/)

puts "--- private class method"
puts C.singleton_class.private_instance_methods.grep(/^my/)

クラスメソッド(特異メソッド)とインスタンスメソッドの関係は以下のエントリーを参照のこと。

check_calling_methods.rb を実行すると以下の結果がでる。

% ruby check_calling_methods.rb 
--- public instance method
myhoo
mybye
--- public class method
myyo
myhello
--- private instance method
myjumbo
mychao
--- private class method
mymanbo
myhi

myhoo(クラスで定義、public、インスタンスメソッド)で呼び出せる他のメソッド

以下のように書き直すことで他のメソッド(mymanbo, myhi除く)を呼び出せる

def myhoo
    mybye
    myjumbo
    mychao
    self.class.myyo
    self.class.myhello
    puts  'C, instance method, public, hoo'
  end

=>
M, instance method, public, bye
C, instance method, private, jambo
M, instance method, private, chao
C, class method, public, yo
M, class method, public, hello

mymanbo, myhiを呼び出そうとすると以下のようなエラーがでる。

  def myhoo
    self.class.mymanbo
    puts  'C, instance method, public, hoo'
  end

=> check_calling_methods.rb:36:in `myhoo': private method `mymanbo' called for C:Class (NoMethodError)
	from check_method.rb:72:in `<main>

呼び出せるメソッドは以下のようになっている。

インスタンスメソッド クラスメソッド
public 呼び出せる 呼び出せる
private 呼び出せる 呼び出せない

myjumbo(クラスで定義、private、インスタンスメソッド)で呼び出せる他のメソッド

同上

myhoo(クラスで定義、public、クラスメソッド)で呼び出せる他のメソッド

 def self.myyo
    myhello
    mymanbo
    myhi
    puts  'C, class method, public, yo'
  end

=>
M, class method, public, hello
C, class method, private, manbo
M, class method, private, hi
C, class method, public, yo

インスタンスメソッドは呼び出せない。よって、呼び出せるメソッドは以下のようになっている。

インスタンスメソッド クラスメソッド
public 呼び出せない 呼び出せる
private 呼び出せない 呼び出せる

mymanbo(クラスで定義、private、クラスメソッド)で呼び出せる他のメソッド

同上

おわりに

確実にメタプログラミングの技術を使えば呼び出せるのだろうけどシンプルには上記の結果っぽい。