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
インスタンスの状態とメソッド検索メソッドの関係についてまとめました。

まずはどんなメソッド検索メソッドを調べます。
  1. # >> Object.methods.select{|m| m=~ /_methods/}    
  2. # => ["public_methods", "instance_methods", "singleton_methods", "public_instance_methods", "protected_methods", "protected_instance_methods", "private_methods", "private_instance_methods"]    


こんなクラスで試します。
  1. class MyClass    
  2.   def initialize; end    
  3.     
  4.   def instance_method; end    
  5.   def self.singleton_method; end    
  6.     
  7. protected    
  8.   def protected_instance_method; end    
  9.   def self.protected_singleton_method; end    
  10.     
  11. private    
  12.   def private_instance_method; end    
  13.   def self.private_singleton_method; end    
  14. end    



クラスを検索


まずはクラスそのものでメソッドの検索をしてみます。methodsという配列との論理積を出しているのは、継承しているメソッドを表示させないためです。=beginで始まるコメントには上の4行の出力結果をそれぞれ示しています。
  1. methods = ["instance_method""singleton_method""protected_instance_method""protected_singleton_method""private_instance_method""private_singleton_method"]    
  2.     
  3. p methods & MyClass.public_methods.collect{|m| m.to_s}     
  4. p methods & MyClass.protected_methods.collect{|m| m.to_s}     
  5. p methods & MyClass.private_methods.collect{|m| m.to_s}     
  6. p methods & MyClass.singleton_methods.collect{|m| m.to_s}     
  7. =begin    
  8. ["instance_method""singleton_method""protected_singleton_method""private_singleton_method"]    
  9. []    
  10. []    
  11. ["singleton_method""protected_singleton_method""private_singleton_method"]    
  12. =end  
  13.     
  14. p methods & MyClass.instance_methods.collect{|m| m.to_s}    
  15. p methods & MyClass.public_instance_methods.collect{|m| m.to_s}    
  16. p methods & MyClass.protected_instance_methods.collect{|m| m.to_s}    
  17. p methods & MyClass.private_instance_methods.collect{|m| m.to_s}    
  18. =begin    
  19. ["instance_method""protected_instance_method"]    
  20. ["instance_method"]    
  21. ["protected_instance_method"]    
  22. ["private_instance_method"]    
  23. =end    

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

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


インスタンスを検索
  1. mc = MyClass.new    
  2. p methods & mc.public_methods.collect{|m| m.to_s}    
  3. p methods & mc.protected_methods.collect{|m| m.to_s}    
  4. p methods & mc.private_methods.collect{|m| m.to_s}    
  5. p methods & mc.singleton_methods.collect{|m| m.to_s}    
  6. =begin    
  7. ["instance_method"]    
  8. ["protected_instance_method"]    
  9. ["private_instance_method"]    
  10. []    
  11. =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できるかはまた別の話なのでご注意あれ。