Sevencop/RedundantExistenceCheck

気軽なカスタムCopの置き場としてsevencopというライブラリをつくり、第一弾として Sevencop/RedundantExistenceCheck というCopを用意した。カスタムCopを書くのは難しいことではないが、ライブラリとして提供しようとすると環境を用意するのが大変だったりするので、こういう実験的な場所があると手軽に試せて便利だ。

# bad
FileUtils.rm(a) if File.exist?(a)

# good
FileUtils.rm(a, force: true)

Sevencop/RedundantExistenceCheck は、ファイルの存在を確認してから消すという処理を、確認せずに黙って消すようにするCop。お察しの通り、偽陽性のあるUnsafeなCopである。実装テストを見れば、どう動くか分かると思うが、わざわざ見る人は居ないと思うので、ここで簡単に説明する。

上記のように、force オプションに対応しているものについては force: trueを付けた形に変更する。rm には rm_f という亜種があるが、一貫性を考慮してここではあえてオプションを付ける形を選択した。亜種を優先したい人は、別途オプション有り版をオプション無し版に書き換えるCopを使うべきだろう。

# bad
FileUtils.mkdir(a) unless File.exist?(a)

# good
FileUtils.mkdir_p(a)

無ければつくる版。FileUtils.mkdir には適当なオプションが無いので、mkdir_p に書き換える作戦を取った。

# bad
File.delete(a) if File.exist?(a)

# good
FileUtils.rm_f(a)

File.delete も適切なオプションが無いので、FileUtils.rm_f に書き換える作戦を取った。このケースでは rm(a, force: true) ではなく rm_f(a) を優先する。

# bad
FileUtils.rm(a, force: true) if File.exist?(a)

# good
FileUtils.rm(a, force: true)

最初から force: true が付いている場合はそこには手を付けない。

# bad
FileUtils.mkdir(a, verbose: true) unless File.exist?(a)

# good
FileUtils.mkdir_p(a, verbose: true)

verbose: true など他のオプションが付いている場合は引き継ぐ。

# bad
FileUtils.mkdir(a) unless FileTest.exist?(a)

# good
FileUtils.mkdir_p(a)

FileTest.exist? にも対応している。file?directory? などには、判断が難しいので今のところ対応していない。元々アグレッシブ気味な性格のCopであり、Unsafeだというフラグを立てているので、対応しても良いのかもしれないが。

簡単に対応できそうなのに対応できていないケースや、その他もっとこうした方が良いなどの意見があれば、気軽にPull Requestを送ってください。

まとめ

  • 気軽なカスタムCop置き場としてsevencopをつくった
  • 第一弾として Sevencop/RedundantExistenceCheck を用意した