webエンジニアの日常

RubyやPython, JSなど、IT関連の記事を書いています

Rubyをもう一歩進んで勉強する7章(superの挙動)

親クラスの同名メソッドを呼ぶsuperについてです。

例えば以下のような場合

class User
  def login(acount, password)
    ~ログイン処理~
  end
end

class AdminUser < User
  def login(password)
    ~ログイン処理~
    ~固有の処理~
  end
end

AdminUserクラスではログインメソッドの中で、親クラスであるUserとログイン処理を共有しています。

同じ処理をなんども書きたくないので、親クラスのログインメソッドを呼びたい。そんなときに使うのがsuperです。

スポンサーリンク

class AdminUser < User
  def login(password)
    super('admin', password)
    ~固有の処理~
  end
end

便利なsuperですが、実はsuperはメソッドではなく、Rubyのキーワードになっており、引数のように見えているのはオプションなのです。

superはかっこがある場合、ない場合で挙動が変わるので、メソッドだと思って使っていると予期せぬ不具合が出てくるかもしれません。

superのふるまいを3つ書いておきたいと思います。

  • 引数あり

super(account, password)のように使うと、accountとpasswordをそのまま親クラスのメソッドに渡します。

もっとも基本的な使い方です。

また、メソッドと同じようにかっこを省略して書くことができます。

super account, password

  • かっこなし・引数なし

superとだけ書くとどうなるでしょう。

class AdminUser < User
  def login(account, password)
    super
    ~固有の処理~
  end
end

このときは、呼び出し元のメソッド(AdminUserのloginメソッド)の引数(accountとpassword)をそのまま親クラスのメソッドに渡します。

なので、もしAdminUserのloginメソッドの引数が1つや3つ以上だった場合には、「ArgumentError: wrong number of arguments (3 for 2)」のようなエラーになります。

  • かっこのみ

3つ目は、かっこのみの場合です。

class AdminUser < User
  def login(account, password)
    super()
    ~固有の処理~
  end
end

この場合は、引数を一つも渡さずにメソッドを実行します。

この書き方は、例えば親クラスが引数なしの場合に使います。

上述の通り、かっこ・引数なしの場合だと、呼び出し元の引数を渡してしまうので、ArgumentErrorになってしまいます。

superを使うときは、引数の渡し方を把握し、あいまいな書き方をしないようにしましょう。

次に、superで呼び出されるメソッドの探索についてです。

いやいや、親クラスのメソッドだろうと思うかもしれませんが(僕はそう思っていました)、実は継承階層全体、すなわちモジュールを含めた継承を順にたどって通常のメソッドと同様の探索を行っていきます。

module Account
  def login(account, password)
    ~何か処理~
  end
end

class User
  def login(account, password)
    ~何か処理~
  end
end

class AdminUser < User
  include(Account)
  def login(account, password)
    super
    ~何か処理~
  end
end

このような場合、うっかりUserのloginメソッドが呼ばれるかと思いきや、Accountモジュールのloginメソッドが呼ばれるのです。

メソッド探索の話は以下の記事を参照してください。

www.uosansatox.biz

Effective Ruby

Effective Ruby

Ruby on Rails 5アプリケーションプログラミング

Ruby on Rails 5アプリケーションプログラミング