RuboCop v1.60の変更点を見てみよう

こんにちは！withサーバーチームの@10keiと申します。

先日、RuboCopのバージョン最新化を行いました。

2024年2月時点で最新マイナーバージョンである
[RuboCop v1.60(2024-01-15 リリース)](https://rubygems.org/gems/rubocop/versions/1.60.0)における変更点を確認しましたので
以下に詳細を書いていこうと思います🙆

## Allow --autocorrect with --display-only-fail-level-offenses.
RuboCopを実行する際、`-a/--autocorrect`と`--display-only-fail-level-offenses`のオプションを同時に指定することが許可されました。

ちなみに、[`--display-only-fail-level-offenses`](https://docs.rubocop.org/rubocop/usage/basic_usage.html#:~:text=%2D%2Ddisplay%2Donly%2Dfail%2Dlevel%2Doffenses)は
`--fail-level`と合わせて指定することで
copの指摘を指定したレベル以上に限定できるオプションです。
```terminal
以下の様にRuboCopを実行すると、Error以上の指摘に限定できます。
$ rubocop --fail-level E --display-only-fail-level-offenses

違反レベルは以下の通り
[A] autocorrect
[I] info
[R] refactor
[C] convention
[W] warning
[E] error
[F] fatal
```
## [Follow a Ruby 3.3 warning for Security/Open when open with a literal string starting with a pipe.](https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Security/Open)
`Security/Open`は、Kernel#openおよびURI.openが使用されている箇所で変数が使用されていないか確認し
コード作成者の想定しない引数が渡された際に、意図しない挙動を起こしてしまう危険性がないか検知してくれるcopでした。

openメソッドは、以下のように`|`をプレフィックスにすることで
ファイルの呼び出しだけでなく、コマンドを実行してその出力を取得することも可能だったのですが
[ruby3.3にて、非推奨の仕様へと変更になりました。](https://rubyreferences.github.io/rubychanges/3.3.html#deprecate-subprocess-creation-with-method-dedicated-to-files)
```ruby
open("| foo")
#=> fooコマンドの実行

#after ruby3.3
open("| foo")
#=> warning: Calling Kernel#open with a leading '|' is deprecated and will be removed in Ruby 4.0; use IO.popen instead
#=> fooコマンドの実行
```
この変更を受けて`RuboCop v1.60`にて
上述したように、openメソッドでコマンドの実行を行おうとしている箇所を
copが指摘してくれるようになりました。
```ruby
# bad
open("| foo")
```

## [Make Style/RedundantEach aware of safe navigation operator.](https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/RedundantEach)
`Style/RedundantEach`は、冗長な"each"が使用されている箇所を指摘してくれるcopです。
```ruby
# bad
array.each.each { |v| do_something(v) }

# good
array.each { |v| do_something(v) }

# bad
array.each.each_with_index { |v, i| do_something(v, i) }

# good
array.each.with_index { |v, i| do_something(v, i) }
array.each_with_index { |v, i| do_something(v, i) }
```
このcopは、ぼっち演算子`&.`が使用されている箇所は検知してくれなかったのですが
`RuboCop v1.60`で、ぼっち演算子使用箇所も指摘してくれるようになりました。
```ruby
# bad
array&.each&.each_with_index { |v, i| do_something(v, i) }

# good
array.each.with_index { |v, i| do_something(v, i) }
array.each_with_index { |v, i| do_something(v, i) }
```

## [Make Style/SlicingWithRange aware of redundant and beginless range.](https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/SlicingWithRange)
`Style/SlicingWithRange`は、以下のような配列から要素を取り出す際に
冗長な範囲指定を検知してくれるcopです。
```ruby
items = ['hoge', 'fuga', 'piyo', 'hogehoge']

# bad
items[1..-1]
#=> ['fuga', 'piyo', 'hogehoge']

# good
items[1..]
#=> ['fuga', 'piyo', 'hogehoge']
```
上記例を見ると、bad例も、good例も同様に
配列の1番目の要素が始端で、末尾から1つ目の要素が終端に指定されています。
要は、0番目の要素である'hoge'以外を全て取得していますね。

ruby2.6にて、終端を持たないRangeオブジェクトが作成できるようになり
good例のように、終端を持たない範囲指定をすることで
わざわざ終端に-1を指定する必要がなくなったので
bad例のような範囲指定は冗長であると、copが指摘してくれてました。

`RuboCop v1.60`では、上記に加えて**始端がnilの範囲指定**も指摘するようになりました。
```ruby
# bad
items[nil..42]

# good
items[..42]
items[0..42]
```
ruby2.7にて、始端を持たないRangeオブジェクトも作成できるようになっています。
始端にnilをわざわざ与えなくても、good例のようにnilを省略して書くことができるので、bad例のような範囲指定を冗長であると指摘してくれます。
始端に0を明示的に指定する書き方も、許容してくれているみたいですね🙆

また以下のように、これ結局全要素を取得してるよね？という範囲指定も
指摘してくれるようになりました。
```ruby
# bad
items[0..-1]
items[0..nil]
items[0...nil]

# good
items
```
## Reject additional 'expanded' EnforcedStyle options when --no-auto-gen-enforced-style is given.
[`--no-auto-gen-enforced-style`](https://docs.rubocop.org/rubocop/configuration.html#automatically-generated-configuration:~:text=Some%20cops%20have,gen%2Dconfig.)は
rubocop_todo.ymlを生成する際に与えることができるオプションです。

copによっては、`EnforcedStyle`というオプションが用意されているのですが
rubocop_todo.yml生成時に全てのファイルにおいて
`EnforcedStyle`で設定できるスタイルにてコーディングされていた場合
デフォルトではRuboCopが自動的に`EnforcedStyle`を設定してくれるようになっています。

`--no-auto-gen-enforced-style`オプションは、この挙動を抑制してくれるオプションで
このオプションを与えてrubocop_todo.ymlを生成した場合
RuboCopが自動的に`EnforcedStyle`を設定しなくなります。

ところで、一部のcopには`EnforcedStyleForEmptyBraces`のような
`EnforcedStyle`を拡張したオプションも用意されており
今までは`--no-auto-gen-enforced-style`オプションを与えたとしても
`EnforcedStyle`を拡張したオプションはRuboCopが自動的に設定してしまっていました。

`RuboCop v1.60`ではこれらのオプションについても
`--no-auto-gen-enforced-style`を設定してrubocop_todo.ymlを生成した場合は
自動的に設定されることがなくなりました。

例えば、以下のようなcopに影響する変更となります。
[Class: RuboCop::Cop::Layout::SpaceInsideBlockBraces](https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Layout/SpaceInsideBlockBraces#:~:text=each%20%7B%7D-,EnforcedStyleForEmptyBraces%3A,-space)
[Class: RuboCop::Cop::Style::TrailingCommaInArguments](https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/TrailingCommaInArguments)
## Require Parser 3.3.0.2 or higher.
依存gemであるparserの依存バージョンが引き上げられました。
`RuboCop v1.59.0`までは`parser >= 3.2.2.4`でした。

`parser v3.3.0.2`の変更点については[こちら](https://github.com/whitequark/parser/blob/master/CHANGELOG.md#v3302-2024-01-07)

## まとめ
v1.60での変更点は以上になります！
なるべくRuboCopのバージョンは最新を保って
品質の高いコードを心がけたいですね✨