【Ruby】メソッド定義と呼び出し側の引数の数が違うのに動くケース

実務で見たコードに対して「これで動くの?」と思ったんですが、実際には動いていたので混乱しました。

ようやく理由がわかったので備忘録としてまとめます。

バージョン
  • Ruby 3.0.3
  • Rails 6.1.6.1
記事の信頼性
  • ぼくは独学で未経験から従業員300名以上の自社開発企業へ転職しました。
  • 実務ではVue.jsとRailsを毎日書いています。
  • 初心者や駆け出しエンジニアがつまづくポイントも身をもってよく理解しています。
目次

問題

CreateEmployeeクラスからCreateEmployeeCommandクラスのメソッドを呼び出していたのですが、引数の数が異なるため、動かないように思えました。

class CreateEmployee
  def perform
    # キーワード引数で4つの引数を渡す
    CreateEmployeeCommand.execute(
      company_id: @company_id,
      name: @name,
      rank: @rank,
      status: @status
    )
  end
end

class CreateEmployeeCommand
  # 引数は1つだけ
  def self.execute(params)
    Employee.create!(params)
  end
end

しかし実際には動いていたので原因がわからずコードを読むのに時間がかかってしまいました。

解決策

結論として、Rubyではメソッドを呼び出す際に最後の引数がハッシュであれば、波括弧({})を省略できます。

つまり先ほどのコードは、実際には次のように記述したのと同じ挙動になります。

class CreateEmployee
  def perform
    # 実は引数は1つのハッシュとみなされる
    CreateEmployeeCommand.execute({
      company_id: @company_id,
      name: @name,
      rank: @rank,
      status: @status
    })
  end
end

class CreateEmployeeCommand
  # 引数は1つだけ
  def self.execute(params)
    Employee.create!(params)
  end
end

一見すると4つの引数を渡しているように見えても、実際には1つのハッシュを渡している扱いとなるため、正常に動作していたのです。

ただし、可読性の観点で考えると、以下のように引数の数を合わせるのがベターだとは思います。

class CreateEmployee
  def perform
    CreateEmployeeCommand.execute(
      company_id: @company_id,
      name: @name,
      rank: @rank,
      status: @status
    )
  end
end

class CreateEmployeeCommand
  def self.execute(company_id:, name:, rank:, status:)
    Employee.create!(
      company_id: company_id,
      name: name,
      rank: rank,
      status: status
    )
  end
end

おわりに

Rubyはやたらと省略できたりするので、個人的にはあまり好きではないですね。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

未経験でSESから従業員300名以上の自社開発企業に転職しました。業務や個人開発で直面した問題や、転職・学習の経験を発信していきます。

コメント

コメントする

目次