Posted at

Rubyのmixinの振る舞いを#~methodsを使って確認する

More than 1 year has passed since last update.


環境

Ruby 2.4.3


準備

下のようなmoduleとclassを用意します。


main.rb

module Included

def self.included_class_method; end

def included_public_instance_method; end

protected

def included_protected_instance_method; end

private

def included_private_instance_method; end

module_function

def included_module_function; end
end

module Extended
def self.extended_class_method; end

def extended_public_instance_method; end

protected

def extended_protected_instance_method; end

private

def extended_private_instance_method; end

module_function

def extended_module_function; end
end

class A
include Included
extend Extended
end



テスト


インスタンスメソッド

# public

A.public_instance_methods
# => [:included_public_instance_method, :remove_instance_variable, ...]

# protected
A.protected_instance_methods
# => [:included_protected_instance_method]

# private
A.private_instance_methods
# => [:included_private_instance_method, :included_module_function, :DelegateClass, ...]

モジュール関数はprivateのインスタンスメソッドとしてincludeされるようです。

あとはまあ予想通りです。


特異メソッド

# 特異メソッド

A.singleton_methods
# => [:extended_public_instance_method, :extended_protected_instance_method]


クラスメソッド

最後にクラスメソッドです。

# public

A.public_methods
# => [:extended_public_instance_method, :new, :allocate, :superclass, :<=>, ...]
A.public_methods(false)
# => [:extended_public_instance_method, :new, :allocate, :superclass]

# protected
A.protected_methods
# => [:extended_protected_instance_method]
A.protected_methods(false)
# => [:extended_protected_instance_method]

# private
A.private_methods
# => [:extended_private_instance_method, :extended_module_function, :initialize, :inherited, :using, ...]
A.private_methods(false)
# => [:extended_private_instance_method, :extended_module_function, :initialize, :inherited]

やはりモジュール関数はextendではprivateなクラスメソッドになるようです。

また、あまり予想していなかったことですが、#new#initialize等がfalseを渡したときにも含まれます。よくよく考えてみると自明ですが、これらはClassクラスのインスタンスメソッドです。

Class.instance_methods(false)

# => [:new, :allocate, :superclass]
Class.private_instance_methods(false)
# => [:initialize, :inherited]


まとめ


  • インスタンスメソッドはアクセス修飾子はそのままにinclude or extendされる

  • クラスメソッドはinclude or extendされない

  • モジュール関数はprivateのインスタンスメソッドとしてincludeされる

  • モジュール関数はprivateのクラスメソッドとしてextendされる


補足

今回使いませんでしたが、

#methods#public_methods + #protected_methods,

#instance_methods#public_instance_methods + #protected_instance_methods