LoginSignup
5
4

More than 1 year has passed since last update.

Ruby|クラスメソッド内の super について

Last updated at Posted at 2020-01-14

はじめに

本稿は super について書いています。普段はインスタンスメソッドで super を利用するシーンがあると思いますが、クラスメソッドだと混乱することがあったのでまとめになります。

super is 何?

super をメソッドで呼び出すと、親クラスにある同名のメソッドを呼び出します。メソッドがなければ例外を起こします。

class Parent
  def do(something)
    p something
  end
end

class Child < Parent
  def do
    super('something')
  end
end

c = Child.new

インスタンスメソッドだと、ancestors を使えばどのように探索をするかヒントになります。先の例だと Child クラスの継承関係に Parent クラスがあるので、そこからメソッドを探すことが出来ています。

もし、期待するメソッドが Parent クラスになければ更に親のクラスを探索します。さらに親の Object クラスを探索してなければ、Kernel クラスを探索します。最後は BasicObject クラスですね。

p Child.ancestors
#=> [Child, Parent, Object, Kernel, BasicObject]

ハマったこと

仕事で pundit の中を調査することがあり、次のような記述を見つけました。included はモジュールがインクルードされたときのコールバックで base クラスに対して更に拡張をする場合(クラスメソッドの追加など)によく使われます。

module PolicyExampleGroup
  include Pundit::RSpec::Matchers

  def self.included(base)
    base.metadata[:type] = :policy
    base.extend Pundit::RSpec::DSL
    super # これ
  end
end

さて、この super はどのクラスで定義している included メソッドでしょうか。はじめは ancestors で調べればわかると思っていたのですがモジュールは親クラスを持たないのです。。。それでも例外にならない、なぜ? :thinking:

p Pundit::RSpec::PolicyExampleGroup.ancestors
#=> [Pundit::RSpec::PolicyExampleGroup]

Ruby はクラスメソッドは特異クラスに定義されているので、クラスメソッドで super を使うと探索は特異クラスの継承関係で行われます。

:warning: 見つける対象になるメソッドはインスタンスメソッドであることに注意

p Pundit::RSpec::PolicyExampleGroup.singleton_class.ancestors
#=> [#<Class:Pundit::RSpec::PolicyExampleGroup>, Module, ..., Kernel, BasicObject]

今回は Module クラスにあるインスタンスメソッドにマッチしたのでそれが実行されています。オーバーライドしなければ nil を返すだけのメソッドなので削除しても良さそうですね :thinking:

ひとまず、拙い英語で pull request を作成しましたがどうなることやら。。。 :eyes:

2022/10/22 更新

Varvet の方からコメントをもらいました。Module#included が何もしないという共通認識は得られたんですが、リリースしてから長く時間がたったのでこの super に依存してるものがあるかもしれないということで PR はクローズになりました。

ちょっと残念でしたが、まあしょうがないですよね :wink:

5
4
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
5
4