Techioz Blog

Ruby でネストされたクラスをコンパクトなスタイルに自動的に変換する

概要

クラス定義にネストされたスタイルとコンパクトなスタイルを組み合わせて使用する非常に大規模なコードベースがあります。

RuboCop: クラスとモジュールの子

# Nested
class Foo
  class Bar
  end
end

# Compact
class Foo::Bar
end

正規表現を使用して多数のクラスの名前空間を再編成する自動ツールを構築しています。これは、クラス定義がコンパクト形式の場合は簡単に実行できますが、ネストされた形式の場合はさらに困難になります。

したがって、ネストされたスタイルのすべてのインスタンスをコンパクト スタイルに変換する方法が必要です。

RuboCop がこれを実行できることを期待していましたが、ドキュメントではオートコレクトをサポートしているようですが、機能させることができません。 RuboCop は違反行為を報告しますが、修正はしません。

bundle exec rubocop --auto-correct app/controllers/announcements_controller.rb
Inspecting 1 file
C

Offenses:

app/controllers/announcements_controller.rb:1:8: C: Style/ClassAndModuleChildren: Use compact module/class definition instead of nested style.
module Vapid
       ^^^^^
app/controllers/announcements_controller.rb:2:10: C: Style/ClassAndModuleChildren: Use compact module/class definition instead of nested style.
  module V2
         ^^

1 file inspected, 2 offenses detected

誰かがこれを機能させることができるか、コンパクトなスタイルを自動的に採用するより良い方法を知っていれば幸いです。

解決策

簡単な答えは、「やらない」です。あなた (そしてそのコップを書いた人) は、2 つの「スタイル」が実際には同じことを行うという間違った仮定を立てています。そうではありません。後者は本当に悪い習慣とみなされます。

したがって、次のものがあるとします。

module Foo
  TEST = "I'm nested in Foo"
end

module Foo
  class Bar
    puts TEST
  end
end

これにより、TEST は Foo::TEST に解決されるため、I は Foo にネストされます。スコープ解決演算子を使用するようにクラス定義を変更しましょう。

TEST = "I'm in the global scope"

module Foo
  TEST = "I'm nested in Foo"
end

class Foo::Bar
  puts TEST
end

これにより、I’m がグローバル スコープに入ります。モジュールのネストは依然としてグローバル スコープであり、TEST は ::TEST に解決されるためです。あなたの小さな「改善」は、実際には適切なモジュールのネストに依存するコードを破壊します。