Gry の設計思想と実装について


Gry とは？
========



[pocke/gry: Gry generates .rubocop.yml automatically](https://github.com/pocke/gry)



そもそも Gry が何なのか知らない人が大半でしょう。
Gry はプロジェクト内のコードから自動的に `.rubocop.yml` を生成するツールです。

Ruby プロジェクトのルートディレクトリで`gry >> .rubocop.yml`の様に実行するだけで、そのプロジェクトに最適な RuboCop の設定を自動生成することが出来ます。

詳しい使い方などは、[隠れたコーディングスタイルを .rubocop.yml に抽出するツール、Gryをリリースしました！ - SideCI Blog](http://blog-ja.sideci.com/entry/2017/01/31/110000) をご覧ください




Gry の設計思想
=========

では、なぜ Gry は必要なのでしょうか？ この章では Gry の設計思想について述べます。

RuboCop には非常に多くの Cop(ルール) があります。そして、それぞれのルールはいくつかの設定項目を持っていることが多いです。
これには、様々なコーディングスタイルへの対応が可能な利点がある反面、最適な設定を作成することには多大な労力を必要とするという欠点もあります。


Gry は労力がかかる設定の作成を自動で行うことを目的として作成されました。


既存の解決方法
-------

ですが、設定の作成には既にいくつかの方法が存在します。
その中から代表的なものを3つ、メリットとデメリットを合わせて紹介します。



### デフォルト設定に従う


1つ目は、RuboCopのデフォルト設定に従う、というものです。

RuboCop は [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide) に沿った設定がデフォルトではなされています。
そのためこのスタイルに沿ったコードを書けば、理論上は RuboCop をデフォルトの設定でそのまま使うことが出来ると言えます。

ですが既存のプロジェクトでは独自のスタイルガイドを用いて運用している場合も多く、デフォルト設定を全て受け入れることは不可能でしょう。
そのため、デフォルト設定に寄せるとしても、多くの場合は追加での設定が必要になると考えられます。



### OnkCop や MeowCop を使用する


2つ目は、OnkCop や MeowCop などの既に用意された設定に従う、というものです。

- [onk/onkcop: OnkCop is a RuboCop configration gem.](https://github.com/onk/onkcop/)
- [sideci/meowcop](https://github.com/sideci/meowcop)

これらは RuboCop の設定が一つの Gem として提供されたものになっています。
これらの Gem であれば、標準の設定よりも自らのプロジェクトに合った設定がなされているかも知れません。
ですが、これらの Gem でもそのプロジェクトに合わなければ、1つ目の例と同じく設定の必要が生じます。

また、MeowCop は「全てのプロジェクトで有効に使える Cop」のみを有効にしたルールになっています。
そのためどのプロジェクトでも MeowCop を有効に導入出来ると思われますが、裏を返せばプロジェクト固有のルールとなりやすいコーディングスタイルに関しては一切チェックすることができなくなってしまいます。
ですので、コーディングスタイルをチェックしたい場合には MeowCop のみでは設定が不足すると言えるでしょう。




### `--auto-gen-config` を使用する

3つ目は、`--auto-gen-config`を使用する、というものです。

RuboCop には `--auto-gen-config` と言うオプションがあります。
このオプションを使用することで `.rubocop_todo.yml` を自動で生成することが可能です。


ですが名前に反して`--auto-gen-config`は実用的な設定ファイルを生成するオプションではありません。
この`.rubocop_todo.yml`は警告が出る Cop をファイル単位で無効にするだけであり、いわば「臭いものに蓋をする」だけのものです。
そのため、作成した設定に既存のコードを少しずつ合わせていく様な使い方には有効ですが、このオプションを使用してそもそもの設定を作成することは出来ません。





Gry の取る解決方法
------------

上記のように、既存の解決方法ではプロジェクト固有の設定を作ることは難しいと言えます。
対して Gry はプロジェクト固有の設定を作ることに特化しています。


プロジェクト内のコードは暗黙的にスタイルにある程度の統一がされていると Gry は仮定します。
明示的に RuboCop の設定がなされていない場合でも、人間によるレビューなどによってある程度コーディングスタイルが統一されていることは大いに考えられます。
その仮定に基づき、暗黙的なコーディングスタイルを`.rubocop.yml`として抽出することで、Gry はそのプロジェクトに特化した`.rubocop.yml`の作成を行います。



また、Gry は設定可能な Cop について最適な設定を提供することを目的としています。
そのため、Lint 系の Cop や Performance 系の Cop など、バグの発見やパフォーマンスの改善を目的とした Cop に関しては関知しません。


実装方法
===========


では、Gry はどのようにして暗黙的なコーディングスタイルを`.rubocop.yml`に落とし込むのでしょうか？

実は、実装はとても単純です。
はじめに、Gry は全ての設定で RuboCop を実行します。
そして、一番警告が少なかった設定を「このプロジェクトのスタイル」とみなし、`.rubocop.yml`に設定します。

また、単に一番警告が少なかった設定を採用するのみでは意図しない設定がされてしまうため、別途2点制約を設けています。

最大指摘数
------

1つ目は、最大指摘数の制約です。

例えば、ある Cop が設定Aだと100件、設定Bだと150件の警告が出る場合を考えます。
この様な場合に単純に設定Aを採用してしまった場合、コーディングスタイルに沿わないコードが100件も存在する状態でそのスタイルを認めてしまうことになります。
このようなケースは、プロジェクトのコーディングスタイルでは特に統一する必要のないスタイルであると考えられます。

そのため、一番警告が少ない設定でも一定数以上の警告が出ている場合、その Cop に関しては設定を行わないようになっています。
デフォルトではこのしきい値は10になっており、また`--max-count`オプションにて違う値を設定できるようになっています。
プロジェクトの大きさによっては10より大きい値にする必要があるでしょう。


最小相違数
-------

2つ目は、最小相違数の制約です。

今度は、ある Cop が設定Aだと3件、設定Bだと5件の警告が出る場合を考えます。
この様な場合に設定Aを採用することは正しいと言えるでしょうか？
私はこのケースにおいて自動的に設定を行うことには意味が薄いと考えています。
何故ならば2つの設定間での差異が2件の警告しかなく、どちらを採用しても大差がないからです。

そのため、Gry は一番警告が少ない設定と二番目に警告が少ない設定の警告数の差が一定数以下の場合、その Cop に関しては設定を行わないようになっています。
デフォルトではこのしきい値は10になっており、また`--min-difference`オプションにて違う値を設定できるようになっています。


まとめ
--------

このように Gry を使用することで、プロジェクトに合った `.rubocop.yml` を自動で作成することが可能です。
RuboCop の設定で消耗したくない方は是非お試しください。