RuboCop | 警告の出力フォーマット指定

# RuboCop | 警告の出力フォーマット指定

## 概要
警告の出力フォーマットの指定方法について
## 指定方法
`--format` オプションで指定します。

~~~bash
$ rubocop --format <some_format>
~~~
## フォーマット一覧

|フォーマット名|設定値|
|:--|:--|
|Progress Formatter|progress ※デフォルト|
|Clang Style Formatter|clang|
|Fuubar Style Formatter|fuubar|
|Emacs Style Formatter|emacs|
|Simple Formatter|simple|
|File List Formatter|files|
|JSON Formatter|json|
|Offense Count Formatter|offenses|

## フォーマット実行例集
* 検証用コード

~~~ruby:lib/hoge.rb
class Hoge
 def h(a)
  b
   [].inject(&:+)
  end
end
~~~

~~~ruby:lib/hige.rb
class Hige
 def h(a)
  b
   [].collect(&:+)
   [].map do|e| e;end
  end
end
~~~

### Progress Formatter

デフォルトのフォーマッター。
各警告に対する表示フォーマットは clang フォーマット。

clang フォーマットに加えて、進捗状況を警告種別を表す文字で表示する

|char|memo|
|:--|:--|
|.|警告なし|
|R|refactor|
|C|convention|
|W|warning|
|E|error|
|F|fatal|

が表示される。

~~~bash
$ rubocop lib | head
Inspecting 2 files
WW

Offenses:

lib/hige.rb:1:1: C: Missing top-level class documentation comment.
class Hige
^^^^^
lib/hige.rb:1:1: C: Carriage return character detected.
class Hige
~~~

### Clang Style Formatter

clang に似たマナーの違反表示を行う。

~~~text:フォーマット
違反ファイル1 相対パス:行番号:列番号: 違反種別: 違反メッセージ
以降、違反詳細
違反ファイル2 相対パス:行番号:列番号: 違反種別: 違反メッセージ
以降、違反詳細
:
~~~

~~~bash
$ rubocop lib --format clang | head
lib/hige.rb:1:1: C: Missing top-level class documentation comment.
class Hige
^^^^^
lib/hige.rb:1:1: C: Carriage return character detected.
class Hige
^^^^^^^^^^
lib/hige.rb:2:1: C: Use 2 (not 1) spaces for indentation.
 def h(a)
^
lib/hige.rb:2:8: W: Unused method argument - a. If it's necessary, use _ or _a as an argument name to indicate that it won't be used. You can also write as h(*) if you want the method to accept any arguments but don't care about them.
~~~

### Fuubar Style Formatter

末尾に進捗バーと実行時間を表示する。
このフォーマットは、 RSpec の  Fuubar フォーマッターに触発されている。

~~~bash
$ rubocop lib --format fuubar
# :
# : 中略
# :
lib/hoge.rb:4:7: C: Prefer reduce over inject.
   [].inject(&:+)
      ^^^^^^
lib/hoge.rb:5:3: W: end at 5, 2 is not aligned with def at 2, 1
  end
  ^^^
lib/hoge.rb:6:4: C: Final newline missing.
end

 2/2 files |====================== 100 =======================>| Time: 00:00:00

2 files inspected, 21 offenses detected
~~~

### Emacs Style Formatter

~~~text:フォーマット
違反ファイル1 フルパス:行番号:列番号: 違反種別: 違反メッセージ
違反ファイル2 フルパス:行番号:列番号: 違反種別: 違反メッセージ
:
~~~

~~~bash
$ rubocop lib --format emacs | head -3
/path/to/project/lib/hige.rb:1:1: C: Missing top-level class documentation comment.
/path/to/project/lib/hige.rb:1:1: C: Carriage return character detected.
/path/to/project/lib/hige.rb:2:1: C: Use 2 (not 1) spaces for indentation.
~~~

### Simple Formatter

~~~text:フォーマット
== 違反ファイル1 相対パス ==
違反種別: 行番号:列番号: 違反メッセージ
違反種別: 行番号:列番号: 違反メッセージ
違反種別: 行番号:列番号: 違反メッセージ
# : 
# : 違反ファイル1の違反を件数分表示
# : 
== 違反ファイル2 相対パス ==
違反種別: 行番号:列番号: 違反メッセージ
~~~

~~~bash
$ rubocop lib --format simple
== lib/hige.rb ==
C:  1:  1: Missing top-level class documentation comment.
# : 
# : 略
# : 
W:  6:  3: end at 6, 2 is not aligned with def at 2, 1
C:  7:  4: Final newline missing.
== lib/hoge.rb ==
C:  1:  1: Missing top-level class documentation comment.
# : 
# : 略
# : 
W:  5:  3: end at 5, 2 is not aligned with def at 2, 1
C:  6:  4: Final newline missing.

2 files inspected, 21 offenses detected
~~~

### File List Formatter

違反ファイルを絶対パスのリストで返却する。
パイプを利用して、エディタで編集する場合などの利用を想定。

~~~bash
$ rubocop lib --format file
/path/to/project/lib/hige.rb
/path/to/project/lib/hoge.rb
~~~

### JSON Formatter

JSONを返却する。ツール連携や二次加工などに。

~~~bash
$ rubocop lib --format json
{"metadata":{"rubocop_version":"0.24.1","ruby_engine":"ruby","ruby_version":"2.1.0","ruby_patchlevel":"-1","ruby_platform":"x86_64-cygwin"},"files":[{"path":"lib/hige.rb","offenses":[{"severity":"convention","message":"Missing top-level class documentation comment.","cop_name":"Style/Documentation","corrected":null,"location":{"line":1,"column":1,"length":5}},{"severity":"convention","message":"Carriage return character detected.","cop_name":"Style/EndOfLine","corrected":null,"location":{"line":1,"column":1,"length":12}},{"severity":"convention","message":"Use 2 (not 1) spaces for indentation.","cop_name":"Style/IndentationWidth","corrected":null,"location":{"line":2,"column":1,"length":1}},{"severity":"warning","message":"Unused method argument - `a`. If it's necessary, use `_` or `_a` as an argument name to indicate that it won't be used. You can also write as `h(*)` if you want the method to accept any arguments but don't care about them.","cop_name":"Lint/UnusedMethodArgument","corrected":null,"location":{"line":2,"column":8,"length":1}},{"severity":"convention","message":"Use 2 (not 1) spaces for indentation.","cop_name":"Style/IndentationWidth","corrected":null,"location":{"line":3,"column":2,"length":1}},{"severity":"convention","message":"Inconsistent indentation detected.","cop_name":"Style/IndentationConsistency","corrected":null,"location":{"line":4,"column":4,"length":15}},{"severity":"convention","message":"Prefer `map` over `collect`.","cop_name":"Style/CollectionMethods","corrected":null,"location":{"line":4,"column":7,"length":7}},{"severity":"convention","message":"Inconsistent indentation detected.","cop_name":"Style/IndentationConsistency","corrected":null,"location":{"line":5,"column":4,"length":18}},{"severity":"convention","message":"Prefer {...} over do...end for single-line blocks.","cop_name":"Style/Blocks","corrected":null,"location":{"line":5,"column":11,"length":2}},{"severity":"convention","message":"Space missing after semicolon.","cop_name":"Style/SpaceAfterSemicolon","corrected":null,"location":{"line":5,"column":18,"length":1}},{"severity":"warning","message":"`end` at 6, 2 is not aligned with `def` at 2, 1","cop_name":"Lint/DefEndAlignment","corrected":null,"location":{"line":6,"column":3,"length":3}},{"severity":"convention","message":"Final newline missing.","cop_name":"Style/TrailingBlankLines","corrected":null,"location":{"line":7,"column":4,"length":0}}]},{"path":"lib/hoge.rb","offenses":[{"severity":"convention","message":"Missing top-level class documentation comment.","cop_name":"Style/Documentation","corrected":null,"location":{"line":1,"column":1,"length":5}},{"severity":"convention","message":"Carriage return character detected.","cop_name":"Style/EndOfLine","corrected":null,"location":{"line":1,"column":1,"length":12}},{"severity":"convention","message":"Use 2 (not 1) spaces for indentation.","cop_name":"Style/IndentationWidth","corrected":null,"location":{"line":2,"column":1,"length":1}},{"severity":"warning","message":"Unused method argument - `a`. If it's necessary, use `_` or `_a` as an argument name to indicate that it won't be used. You can also write as `h(*)` if you want the method to accept any arguments but don't care about them.","cop_name":"Lint/UnusedMethodArgument","corrected":null,"location":{"line":2,"column":8,"length":1}},{"severity":"convention","message":"Use 2 (not 1) spaces for indentation.","cop_name":"Style/IndentationWidth","corrected":null,"location":{"line":3,"column":2,"length":1}},{"severity":"convention","message":"Inconsistent indentation detected.","cop_name":"Style/IndentationConsistency","corrected":null,"location":{"line":4,"column":4,"length":14}},{"severity":"convention","message":"Prefer `reduce` over `inject`.","cop_name":"Style/CollectionMethods","corrected":null,"location":{"line":4,"column":7,"length":6}},{"severity":"warning","message":"`end` at 5, 2 is not aligned with `def` at 2, 1","cop_name":"Lint/DefEndAlignment","corrected":null,"location":{"line":5,"column":3,"length":3}},{"severity":"convention","message":"Final newline missing.","cop_name":"Style/TrailingBlankLines","corrected":null,"location":{"line":6,"column":4,"length":0}}]}],"summary":{"offense_count":21,"target_file_count":2,"inspected_file_count":2}}
~~~

JSON を整形してみた。

~~~json
{
  "metadata": {
    "rubocop_version": "0.24.1",
    "ruby_engine": "ruby",
    "ruby_version": "2.1.0",
    "ruby_patchlevel": "-1",
    "ruby_platform": "x86_64-cygwin"
  },
  "files": [
    {
      "path": "lib/hige.rb",
      "offenses": [
        {
          "severity": "convention",
          "message": "Missing top-level class documentation comment.",
          "cop_name": "Style/Documentation",
          "corrected": null,
          "location": {
            "line": 1,
            "column": 1,
            "length": 5
          }
        },
        {
          "severity": "convention",
          "message": "Carriage return character detected.",
          "cop_name": "Style/EndOfLine",
          "corrected": null,
          "location": {
            "line": 1,
            "column": 1,
            "length": 12
          }
        },
        {
          "severity": "convention",
          "message": "Use 2 (not 1) spaces for indentation.",
          "cop_name": "Style/IndentationWidth",
          "corrected": null,
          "location": {
            "line": 2,
            "column": 1,
            "length": 1
          }
        },
        {
          "severity": "warning",
          "message": "Unused method argument - `a`. If it's necessary, use `_` or `_a` as an argument name to indicate that it won't be used. You can also write as `h(*)` if you want the method to accept any arguments but don't care about them.",
          "cop_name": "Lint/UnusedMethodArgument",
          "corrected": null,
          "location": {
            "line": 2,
            "column": 8,
            "length": 1
          }
        },
        {
          "severity": "convention",
          "message": "Use 2 (not 1) spaces for indentation.",
          "cop_name": "Style/IndentationWidth",
          "corrected": null,
          "location": {
            "line": 3,
            "column": 2,
            "length": 1
          }
        },
        {
          "severity": "convention",
          "message": "Inconsistent indentation detected.",
          "cop_name": "Style/IndentationConsistency",
          "corrected": null,
          "location": {
            "line": 4,
            "column": 4,
            "length": 15
          }
        },
        {
          "severity": "convention",
          "message": "Prefer `map` over `collect`.",
          "cop_name": "Style/CollectionMethods",
          "corrected": null,
          "location": {
            "line": 4,
            "column": 7,
            "length": 7
          }
        },
        {
          "severity": "convention",
          "message": "Inconsistent indentation detected.",
          "cop_name": "Style/IndentationConsistency",
          "corrected": null,
          "location": {
            "line": 5,
            "column": 4,
            "length": 18
          }
        },
        {
          "severity": "convention",
          "message": "Prefer {...} over do...end for single-line blocks.",
          "cop_name": "Style/Blocks",
          "corrected": null,
          "location": {
            "line": 5,
            "column": 11,
            "length": 2
          }
        },
        {
          "severity": "convention",
          "message": "Space missing after semicolon.",
          "cop_name": "Style/SpaceAfterSemicolon",
          "corrected": null,
          "location": {
            "line": 5,
            "column": 18,
            "length": 1
          }
        },
        {
          "severity": "warning",
          "message": "`end` at 6, 2 is not aligned with `def` at 2, 1",
          "cop_name": "Lint/DefEndAlignment",
          "corrected": null,
          "location": {
            "line": 6,
            "column": 3,
            "length": 3
          }
        },
        {
          "severity": "convention",
          "message": "Final newline missing.",
          "cop_name": "Style/TrailingBlankLines",
          "corrected": null,
          "location": {
            "line": 7,
            "column": 4,
            "length": 0
          }
        }
      ]
    },
    {
      "path": "lib/hoge.rb",
      "offenses": [
        {
          "severity": "convention",
          "message": "Missing top-level class documentation comment.",
          "cop_name": "Style/Documentation",
          "corrected": null,
          "location": {
            "line": 1,
            "column": 1,
            "length": 5
          }
        },
        {
          "severity": "convention",
          "message": "Carriage return character detected.",
          "cop_name": "Style/EndOfLine",
          "corrected": null,
          "location": {
            "line": 1,
            "column": 1,
            "length": 12
          }
        },
        {
          "severity": "convention",
          "message": "Use 2 (not 1) spaces for indentation.",
          "cop_name": "Style/IndentationWidth",
          "corrected": null,
          "location": {
            "line": 2,
            "column": 1,
            "length": 1
          }
        },
        {
          "severity": "warning",
          "message": "Unused method argument - `a`. If it's necessary, use `_` or `_a` as an argument name to indicate that it won't be used. You can also write as `h(*)` if you want the method to accept any arguments but don't care about them.",
          "cop_name": "Lint/UnusedMethodArgument",
          "corrected": null,
          "location": {
            "line": 2,
            "column": 8,
            "length": 1
          }
        },
        {
          "severity": "convention",
          "message": "Use 2 (not 1) spaces for indentation.",
          "cop_name": "Style/IndentationWidth",
          "corrected": null,
          "location": {
            "line": 3,
            "column": 2,
            "length": 1
          }
        },
        {
          "severity": "convention",
          "message": "Inconsistent indentation detected.",
          "cop_name": "Style/IndentationConsistency",
          "corrected": null,
          "location": {
            "line": 4,
            "column": 4,
            "length": 14
          }
        },
        {
          "severity": "convention",
          "message": "Prefer `reduce` over `inject`.",
          "cop_name": "Style/CollectionMethods",
          "corrected": null,
          "location": {
            "line": 4,
            "column": 7,
            "length": 6
          }
        },
        {
          "severity": "warning",
          "message": "`end` at 5, 2 is not aligned with `def` at 2, 1",
          "cop_name": "Lint/DefEndAlignment",
          "corrected": null,
          "location": {
            "line": 5,
            "column": 3,
            "length": 3
          }
        },
        {
          "severity": "convention",
          "message": "Final newline missing.",
          "cop_name": "Style/TrailingBlankLines",
          "corrected": null,
          "location": {
            "line": 6,
            "column": 4,
            "length": 0
          }
        }
      ]
    }
  ],
  "summary": {
    "offense_count": 21,
    "target_file_count": 2,
    "inspected_file_count": 2
  }
}
~~~

### Offense Count Formatter

違反数の種別ごとにグループ化し、件数の降順で表示する。

~~~bash
$ rubocop lib --format offenses

4   Style/IndentationWidth
3   Style/IndentationConsistency
2   Lint/DefEndAlignment
2   Lint/UnusedMethodArgument
2   Style/CollectionMethods
2   Style/Documentation
2   Style/EndOfLine
2   Style/TrailingBlankLines
1   Style/Blocks
1   Style/SpaceAfterSemicolon
--
21  Total
~~~

## RuboCopまとめ記事
http://qiita.com/tbpgr/items/edbfecb6a6789dd54f47

## 参照
* RuboCop GitHub
https://github.com/bbatsov/rubocop