はじめに
こんにちは、@wai-doi です。
本記事では RuboCop の設定ファイルの .rubocop.ymlで、特定の cop の無効化を明示している書き方から、逆に、有効になっている cop の有効化を明示する書き方に直す方法を考えました。
やりたかったこと
まず以下のような .rubocop.yml がありました。
AllCops: DisabledByDefault: true Layout: Enabled: true Layout/ArgumentAlignment: Enabled: false Layout/ArrayAlignment: Enabled: false # 省略 Layout/SpaceInsideHashLiteralBraces: Enabled: false
上から順に見ていくと、まず AllCops:
DisabledByDefault: true
で全ての cop を無効化しています。そして、Layout: Enabled: true
で Layout の cop を有効化にしています。最後に Layout の中で特定の cop を Layout/ArgumentAlignment:
Enabled: false
のように無効化にしています。
この状態から、逆に、どの cop が有効になっているかがわかりやすいよう、有効化している cop だけを明示した書き方に直したいということがありました。
期待する書き方は以下です。
AllCops: DisabledByDefault: true Layout/AccessModifierIndentation: Enabled: true # Layout/ArgumentAlignment Layout/ArrayAlignment は書かれていない Layout/BeginEndAlignment: Enabled: true # 省略 Layout/TrailingWhitespace: Enabled: true
つまり以下のように書き換えたかったです。
Layout:
Enabled: true
を削除する- Layout cops でデフォルトに有効になっている cop を明示的に
Enabled: true
で書く - ただし今
Enabled: false
を書いている cop については何も書かない
解決したスクリプト
明示的に Enabled: true
を書くために、RuboCop のドキュメントにあるたくさん Layout cops を書き写すのは面倒なので、以下の Ruby スクリプトを書いてみました。
rubocop v1.60.2 を用いました。
require 'rubocop' # Layout cops を取得します layout_cops = RuboCop::Cop::Registry.new(RuboCop::Cop::Registry.all).with_department(:Layout) # デフォルトで有効になる Layout cops だけを取得する default_enabled_layout_cops = layout_cops.enabled(RuboCop::ConfigLoader.default_configuration) # .rubocop.yml から Enabled: false を書いている cop名 を取り出す disabled_layout_cop_names = RuboCop::ConfigLoader .load_file('.rubocop.yml') .to_h .select {|cop_name, cop_config| cop_name.start_with?('Layout/') && cop_config['Enabled'] == false } .keys # デフォルトで有効になる cop から Enabled: false を書いている cop を除く enabled_layout_cop_names = default_enabled_layout_cops.map(&:cop_name) - disabled_layout_cop_names # .rubocop.yml に Enabled: true をコピペできる形式にして出力する puts enabled_layout_cop_names.map {|cop_name| <<~YAML #{cop_name}: Enabled: true YAML }.join("\n")
1行目と2行目の RuboCop::Cop::Registry
と RuboCop::ConfigLoader
の使ったコードは @koic さんに教えていただきました。
RuboCop::Cop::Registry
は RubCop が内部で持っている cop の一覧情報が取得できるクラスで、RuboCop::ConfigLoader
は RuboCop の設定ファイルを処理するクラスです。
工夫した点
工夫したところは3行目の disabled_layout_cop_names
を取得するところです。
以下のように RuboCop::Cop::Registry#disabled
を使って .rubocop.yml で無効になっている cop を取得しようとしましたが、これではうまくできませんでした。
disabled_layout_cop_names = layout_cops.disabled(RuboCop::ConfigLoader.load_file('.rubocop.yml'))
#disabled
の実装を見ると、.rubocop.yml に Enabled:true
と書かれている cop を除くという処理であることがわかりました。.rubocop.ymlには Enabled: true
は書いていないためなにも除かれなかったため、これはうまくできませんでした。
別の方法で取れないかいろいろ探すと、RuboCop::ConfigLoader.load_file('.rubocop.yml')
の結果を to_h
でハッシュに変換できるようだったため、正規表現などを使って Enabled: false
の cop を取得する方法で実現できました。
後からわかったことですが、ここで .rubocop.yml をハッシュへの変換しているのは単純にYAMLをパースしているだけなので、 YAML.load_file('.rubocop.yml')
でも同じでした。
RuboCop にあるメソッドで Enabled: false
と書いている cop をもっとスマートに取得できる方法もあるかもしれないですが、わかりませんでした。
おわりに
今回やってみて、RuboCop::Cop::Registry
や RuboCop::ConfigLoader
など RuboCop を普段使うだけでは知らなかったクラスなどを知ることができてよかったです。
永和システムマネジメントでは、Ruby とアジャイルソフトウェア開発を通じてコミュニティと成長したいエンジニアを絶賛募集しています。