22 Jun 2010

インスタンスの状態とpublic_methods, private_methods, singleton_methods, public_instance_methods, protected_instance_methods, private_instance_methods

インスタンスの状態とpublic_methods, private_methods, singleton_methods, public_instance_methods, protected_instance_methods, private_instance_methods
インスタンスの状態とメソッド検索メソッドの関係についてまとめました。

まずはどんなメソッド検索メソッドを調べます。

# >> Object.methods.select{|m| m=~ /_methods/}
# => ["public_methods", "instance_methods", "singleton_methods", "public_instance_methods", "protected_methods", "protected_instance_methods", "private_methods", "private_instance_methods"]


こんなクラスで試します。

class MyClass
def initialize; end

def instance_method; end
def self.singleton_method; end

protected
def protected_instance_method; end
def self.protected_singleton_method; end

private
def private_instance_method; end
def self.private_singleton_method; end
end



クラスを検索


まずはクラスそのものでメソッドの検索をしてみます。methodsという配列との論理積を出しているのは、継承しているメソッドを表示させないためです。=beginで始まるコメントには上の4行の出力結果をそれぞれ示しています。

methods = ["instance_method", "singleton_method", "protected_instance_method", "protected_singleton_method", "private_instance_method", "private_singleton_method"]

p methods & MyClass.public_methods.collect{|m| m.to_s}
p methods & MyClass.protected_methods.collect{|m| m.to_s}
p methods & MyClass.private_methods.collect{|m| m.to_s}
p methods & MyClass.singleton_methods.collect{|m| m.to_s}
=begin
["instance_method", "singleton_method", "protected_singleton_method", "private_singleton_method"]
[]
[]
["singleton_method", "protected_singleton_method", "private_singleton_method"]
=end

p methods & MyClass.instance_methods.collect{|m| m.to_s}
p methods & MyClass.public_instance_methods.collect{|m| m.to_s}
p methods & MyClass.protected_instance_methods.collect{|m| m.to_s}
p methods & MyClass.private_instance_methods.collect{|m| m.to_s}
=begin
["instance_method", "protected_instance_method"]
["instance_method"]
["protected_instance_method"]
["private_instance_method"]
=end

注意すべきところはpublic_methodsにprotected_singleton_methodとprivate_singleton_methodが含まれるところです。理由はよく分かりません。それから、protected_methodsとprivate_methodsは何も表示しません。

instance_methodsはpirvate_instance_methodを表示させません。インスタンスメソッドを検索したい場合はスコープごとに分けて検索するか、すべてのスコープの結果を論理和したものから探すのが良いと思います。


インスタンスを検索

mc = MyClass.new
p methods & mc.public_methods.collect{|m| m.to_s}
p methods & mc.protected_methods.collect{|m| m.to_s}
p methods & mc.private_methods.collect{|m| m.to_s}
p methods & mc.singleton_methods.collect{|m| m.to_s}
=begin
["instance_method"]
["protected_instance_method"]
["private_instance_method"]
[]
=end


インスタンスから検索した場合、当然ながらクラスで定義したシングルトンメソッドは表示されません。代わりにインスタンスにシングルトンメソッドを定義すればsingleton_methods()で発見されます。

protected_instance_methodとprivate_instance_methodが発見されます。

インスタンスからinstance_xxxx_methodsと名のつくメソッドを実行すると全てundefined methodになります(ので表記してません)。


継承したクラスを検索


元のクラスと同じ結果

継承したインスタンスを検索


元のクラスのインスタンスと同じ結果

まとめ


- シングルトンメソッドは(当たり前だけど)定義したインスタンス(クラスはClassクラスのインスタンス)からしか参照できない。
- クラスのprotected_instance_methods(), private_instance_methods()は何も見つけないので何のためにあるか分からない。
- instance_methodsはpirvate_instance_methodを含まない

ちなみに、メソッド検索メソッドで参照できるのと、callできるかはまた別の話なのでご注意あれ。