💭

[Ruby] マジックナンバーをメソッド内で定数として定義しない

に公開

Rubyでは、以下のようなコードを書くとRubocop先生に「その書き方アカンでぇ〜」と注意される。

module SomeModule
  def some_method
    SOME_CONSTANT = 8 # メソッド内で定数を定義している
    puts SOME_CONSTANT
  end
end

具体的には、以下のような指摘を受ける。

dynamic constant assignment
(Using Ruby 3.3 parser; configure using `TargetRubyVersion` parameter, under `AllCops`)rubocop(Lint/Syntax)

moduleじゃなく、classで定義しても結果は同じだ。

Rubyでは、定数を定義する場合はクラスやモジュールのトップレベルに定義しなければならない。
今回のようにメソッド内で定数を定義すると、Rubyでは動的な定数定義とみなされ、Rubocopの指摘を受ける。「定数は一度定義されたら変わらないものである」とRubyの世界では前提とされており(おそらく他の言語でも同じだろうが)、ランタイム中に定数が定義されてしまうと、その性質が失われてしまう。

定数を定義したいなら、こうすべき。

module SomeModule
  SOME_CONSTANT = 8 # トップレベルで定義する

  def some_method
    puts SOME_CONSTANT
  end
end

しかし、上記コードの場合、いろんな箇所でこの定数が使われそうな印象がある。しかし、実際にはsome_method内でマジックナンバーとしてしか使われていない。

では、ある特定のメソッド内のみでマジックナンバーの管理をしたい場合はどうしたらいいのか?
→ 普通にメソッド内に変数定義をすればいい。

module SomeModule
  def some_method
    some_constant = 8
    puts some_constant
  end
end

マジックナンバーだからといって、必ずしもSOME_CONSTANTのように大文字で定義される定数として使わなくてもいい。もちろん、複数の場所で繰り返し使用される値ならばトップレベルで定義すればいい。また、数値を使っているからといって、その意味が明確な場合はマジックナンバーにする必要があるか、検討すべきだ。チームメンバーに聞くのがもっとも手っ取り早いと思う。

Discussion