ぼくがかんがえる、さいてきにむかうRubocop

Railsプロジェクトのコードをきれいに保つために、Rubocopを使っています。ただし、既存のスタイルそのままではなく、プロジェクトに合わせて各種の変更を行いつつ運用しています。

# 大原則
まず、運用ルールとして、「Rubocopの評価は行うけど、**コミットを止めたりはしない**」という方針で運用しています。というのも、（もちろん構文エラーがあるなど、どうしようもないものについては別途考えないといけないかもしれませんが）コミットを止めてしまうぐらいに強制すると、急ぎのときに「なんとかその場しのぎで（ルールだけ通過させる/ルール自体を一時停止させてしまう）」、より対応困難なコードを生む危険性があると考えたからです[^1]。

機能拡張とコード整理を別に行うということで、このようにゆるふわでやっていくのがいいのかなと思っています。

## おことわり
説明の都合上、実際の`.rubocop.yml`ではひとまとめに書いている部分を分解していることがあります。

# 初期設定
まずは、`.rubocop.yml`でRubyのバージョン設定などをしておきます（バージョンが上がれば、文法やメソッドが変化していきます）。

```yaml:初期設定
AllCops:
  TargetRubyVersion: 2.2

# Rails用の設定を有効化
Rails:
  Enabled: true
```

とりあえずこれで動くようにはなりますが、とはいえこのままでは過剰にかかる部分も多いので、適宜調整して行かなければいけません。

## 真っ先に止めるもの
まず、Railsが自動生成する、Bundlerでインストールするなどで、人の手で変更しないことが前提のファイルは、問題点を指摘されても対応不能ですので、チェックの対象から外しておきます。

```yaml
AllCops:
  Exclude:
    - bin/*
    - db/schema.rb
    - vendor/**/*
```

そして、Gemとしてなど全世界に公開するプロジェクトならともかく、開発もユーザーも日本人、というようなRailsシステムでは、コメントに日本語を書けないのは邪魔にしかならないので、[Style/AsciiComments](http://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/AsciiComments)も問答無用で停止します。

```yaml
Style/AsciiComments:
  Enabled: false
```

# 特殊なファイルには特殊な設定
Railsでは、メインのプログラムを書く`app/`以下以外にもコードを書く場所があります。たとえば、`db/migrate/`以下に書くマイグレーションは、10カラムを越えるようなテーブルを作っただけで行数やABCサイズが限界値を超えてしまいます。そして、これを複数のメソッドに分けるというのも非効率なだけで意味がありません。さらに、（[内部でデータ移行を行う](http://qiita.com/jkr_2255/items/bf201773853cbff28dfe)など凝ったものを作るのでもない限り）マイグレーションの内容はクラス名や中身で明らかですし、マイグレーションクラスを他のコードに使うこともないので、ドキュメントコメントの必要性も薄くなります。ということで、これだけの設定を止めました。

```yaml
Documentation:
  Exclude:
    - 'db/migrate/*'

Metrics/MethodLength:
  Exclude:
    - 'db/migrate/*'

Metrics/AbcSize:
  Exclude:
    - 'db/migrate/*'
```

また、初期データ用に[seed-fu](https://github.com/mbleigh/seed-fu)を使っていますが、データリストはRubyコードとは言えあくまでデータの管理用なので、ケツカンマを認めてあとから追記をやりやすくしたほうが運用上便利ということで、ここだけ外しています。

```yaml
Style/TrailingCommaInArguments:
  Exclude:
    - 'db/fixtures/*'
```

# スタイル設定
## 分量設定
メソッド長とかABCサイズとかは、デフォルト設定だときついように思うかもしれませんが、慣れれば案外書けるようになります。ただ、80桁制限はきつすぎるので、100桁まで緩和してあります[^2]。

```yaml
Metrics/LineLength:
  Max: 100
```

## コーディングスタイル
字下げはともかく（`private`以降を下げるRailsスタイル）、空行は多少入っていてもいなくても読みやすさにそこまで大きく影響するものではないと、全部止めてしまいました。

```yaml
Style/IndentationConsistency:
  EnforcedStyle: rails

Style/EmptyLines:
  Enabled: false

Style/EmptyLinesAroundClassBody:
  Enabled: false

Style/EmptyLinesAroundModuleBody:
  Enabled: false

Style/EmptyLinesAroundMethodBody:
  Enabled: false

Style/EmptyLinesAroundBlockBody:
  Enabled: false
```

## 好みの問題
パーセントリテラルの区切り文字も特定のものを推奨してきますが（[Style/PercentLiteralDelimiters](http://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/PercentLiteralDelimiters)）、（正規表現以外では）好みで縦棒区切りを使っています。

```yaml
Style/PercentLiteralDelimiters:
  PreferredDelimiters:
    '%i': '||'
    '%w': '||'
    '%W': '||'
```

# 似て非なるもの
## モジュールメソッド的なもの
以前[記事にまとめました](http://qiita.com/jkr_2255/items/3a6049b39ac8272ba06c)が、`SomeModule.some_method`のように呼べるメソッドは、`extend self`と`module_function`のどちらでも作れます。Rubocopにもどちらかを推奨させるオプション（[Style/ModuleFunction](http://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/ModuleFunction)）があります…が、この2つは**挙動が異なります**。意識して使い分けたいので、これは停止させてあります。

```yaml
Style/ModuleFunction:
  Enabled: false
```

## 一部箇所だけ止める
[Style/NilComparison](http://www.rubydoc.info/github/bbatsov/rubocop/Rubocop/Cop/Style/NilComparison)は、`a == nil`ではなく`a.nil?`と書く、という設定です。ふつうは問題ないのですが、ActiveRecordのSQLをDSLで書ける[baby_squeel](https://github.com/rzane/baby_squeel)は`column_name == nil`でしか動かないので、それを使う箇所だけ、`# rubocop:disable Style/NilComparison`のようなコメントを入れて止めています。

あと、二重否定（`!!`）を使わない、という[Style/DoubleNegation](http://www.rubydoc.info/github/bbatsov/rubocop/Rubocop/Cop/Style/DoubleNegation)もあります。普段の条件判定に使う必要はほぼないのですが、`?`で終わるメソッドの返り値として`true`か`false`かだけを渡したい、というシチュエーションでは便利なので、そういう箇所だけ限定的に解除しています。

# 新しい設定を取り入れる
他のオブジェクトのメソッドを呼ぶ`.send`ですが、Ruby 1.9以降は`public_send`が登場しています。そこで、「パブリックでいいのなら`public_send`」「`private`が必要なら`__send__`」というように使い分けさせる、という[Style/Send](http://www.rubydoc.info/github/bbatsov/RuboCop/RuboCop/Cop/Style/Send)があります。この世界観に納得して、そして自動では入らないのであえてonにして運用しています[^3]。

# まとめに代えて
Rubyとして処理させる以上、（どれだけ納得できなくても）文法は守らないと動きませんが、そうでないコーディング規約には、設定するだけの理由があります。[以前にまとめました](http://qiita.com/jkr_2255/items/5e20100e4e8527baea03)が、このようなルールに対して「盲目的に従う」のも「守らなくても動くからと、ただ無視する」のも、同じように危険な行為だと思います。

前々からそんなことを考えつつRubocopの設定をテーマに書いてみようと思ったところに、[JavaScriptでの強烈かつ天下り的なルール設定](http://qiita.com/raccy/items/bf590d3c10c3f1a2846b)があったので、自分も記事にした次第です。


[^1]: 趣味で作っている別件のコードでは、Travis CIにRubocopも組み込んで、「1件でもあればテスト失敗」とするようにしてあることもあります。
[^2]: 別に入れたGemが長いコメントを生成してしまうので、どうしたものか少々悩んでいます。
[^3]: ソケット系など、まったく別な[send](https://docs.ruby-lang.org/ja/latest/class/BasicSocket.html#I_SEND)を使う場合は、素直にオフとしたほうが良さそうです。