8
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Module のメソッドオーバーライドに Module#prepend を使う

Posted at

Module のメソッドをオーバーライドする場合、クラス内に定義することもできますが、オーバーライドしていることを分かりやすくさせるため Module#prepend を使ったりします。加えて prepend であればメソッド呼び出しの優先順も高いため確実にオーバーライドしたメソッドが呼び出されることも保証されます。

Module#include

prepend に入る前に include について。
例えば以下のような Module があった場合

base_module.rb
module BaseModule
  def self.included(base)
    base.extend(ClassMethods)
  end

  def instance_method
    puts 'included_instance_method'
  end

  module ClassMethods
    def singleton_method
      puts 'included_singleton_method'
    end
  end
end

ここで、self.included で ClassMethod を extend しないと、この Module を include したクラスで singleton_method を呼び出した時に NoMethodError となります。base.extend することで Module のメソッドを特異メソッド(クラスメソッド)として使えるようにしてくれて、include したときにインスタンスメソッドとクラスメソッドも追加できます。
この Module を使いたいクラスで、

current_class.rb
class CurrentClass
  include BaseModule
end

と include すれば

# instance
current_class_obj = CurrentClass.new
current_class_obj.instance_method  #=> "included_instance_method"

# singleton
CurrentClass.singleton_method  #=> "included_singleton_method"

インスタンスメソッドもクラスメソッドも期待通りに呼び出すことができます。

Module#prepend

上記の Module クラスの特異メソッドである singleton_method をオーバーライドしたい場合、base_module.rb 内に singleton_method を定義しても良いのですが、Module#prepend 使ったほうが「Module のメソッドをオーバーライドしてるよ」というのがわかりやすくて良い気がしています。

base_module_extention.rb
module BaseModuleExtention
  def self.prepended(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def singleton_method
      puts 'prepended_singleton_method'
    end
  end
end

今回のようにオーバーライドしたいメソッドがクラスメソッドだった場合、self.prepended で extend を呼び出す必要があります。

current_class.rb
class CurrentClass
  include BaseModule
  prepend BaseModuleExtention
end

オーバーライドできているか確認します。

# instance
current_class_obj = CurrentClass.new
current_class_obj.instance_method  #=> "included_instance_method"

# singleton
CurrentClass.singleton_method  #=> "prepended_singleton_method"

ちゃんと prepend した BaseModuleExtention のメソッドが呼ばれてます。
ancestors を見ても、

BaseModuleExtention
CurrentClass
BaseModule
Object
Kernel
BasicObject

BaseModuleExtention から探索されることが分かるので期待通りの動きになることも保証されます。

8
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?