RuboCop 0.48.0 のCHANGELOGを読む

RuboCopのバージョン(0.48.0)がリリースされました。




https://github.com/bbatsov/rubocop/releases/tag/v0.48.0


CHANGELOGから新機能を見ていこうと思います。



新規Cop追加
============

Copとは、RuboCopにおいてひとつのルールを指す言葉です。例えば、「インデントが正しいかチェックする」「非推奨メソッドを使っていないかチェックする」などが1つのCopの単位になります。 

この章では、0.48.0で新たに追加されたCopをひとつずつ紹介します。


Style/EmptyLineAfterMagicComment
------

- PR https://github.com/bbatsov/rubocop/pull/3889
- Document http://rubocop.readthedocs.io/en/latest/cops_style/#styleemptylineaftermagiccomment

Ruby にはマジックコメントという特殊なコメントが存在します。
例えば Ruby 2.3 からは`frozen_string_lietral`というマジックコメントが存在し、これを`true`にすることで文字列リテラルが自動的に`freeze`されます。

```ruby
# frozen_string_literal: true

p 'a'.frozen? # => true
```

この Cop はこのようなマジックコメントの直後に空行があることをチェックします。
マジックコメントと通常のコードの間にコメントを入れることで、マジックコメントが存在することをわかりやすくすることが出来ます。


Style/MixinGrouping
------


- Issue https://github.com/bbatsov/rubocop/issues/3936
- PR https://github.com/bbatsov/rubocop/pull/3982
- Document http://rubocop.readthedocs.io/en/latest/cops_style/#stylemixingrouping


複数のモジュールをクラスに`include`する場合、2通りの書き方が存在します。

```ruby
class A
  include B
  include C
end

class A
  include C, B
end
```

> 引数に複数のモジュールを指定した場合、 最後の引数から順にインクルードします。
>
> https://docs.ruby-lang.org/ja/latest/method/Module/i/include.html

とある通り、逆順に`include`される点に少し注意が必要です。

この Cop では、この2つの`include`のスタイルを統一します。
デフォルトでは前者の`include`を2回書くスタイルを推奨します。

もし後者の`include C, B`のようなスタイルを使用したい場合、`.rubocop.yml`に以下のように書く必要があります。

```yaml
Style/MixinGrouping:
  EnforcedStyle: grouped
```

Rails/RelativeDateConstant
---------

- PR https://github.com/bbatsov/rubocop/issues/4003
- Document http://rubocop.readthedocs.io/en/latest/cops_rails/#railsrelativedateconstant

```ruby
# bad
class SomeClass
  EXPIRED_AT = 1.week.since
end
```

Rails のモデルなどに以上のようなコードを書いてしまうと、多くの場合バグとなるでしょう。
この`EXPIRED_AT`はアプリケーションの起動時間の値となってしまうため、想定通りの値とならないでしょう。

この Cop はこのようなコードを指摘します。上記のコードは以下のように書き直すべきでしょう。

```ruby
class SomeClass
  def self.expired_at
    1.week.since
  end
end
```


Style/EmptyLinesAroundBeginBody
-----------

- PR https://github.com/bbatsov/rubocop/pull/3984
- Document http://rubocop.readthedocs.io/en/latest/cops_style/#styleemptylinesaroundbeginbody

```ruby
begin

  foo
  bar

end
```

この Cop は、上記のような`begin-end`ブロックの本文の周りに無駄な空行があるコードを警告します。






Style/EmptyLinesAroundExceptionHandlingKeywords
---------

- PR https://github.com/bbatsov/rubocop/pull/3995
- Document http://rubocop.readthedocs.io/en/latest/cops_style/#styleemptylinesaroundexceptionhandlingkeywords



```ruby
begin
  do_something

rescue

  do_something2

else

  do_something3

ensure

  do_something4
end

def foo
  do_something

rescue

  do_something2
end
```

この Cop は、上記のように`rescue`などの例外処理キーワードの前後に空行があるコードを警告します。


Style/IndentHeredoc
---------

- PR https://github.com/bbatsov/rubocop/pull/4028
- Document http://rubocop.readthedocs.io/en/latest/cops_style/#indentheredoc

```ruby
def hello
  message = <<-END
    Welcome!
    Hello, World!
  END
  puts message
end

hello
```

このコードを実行すると、以下のように空白も含まれてメッセージが出力されてしまいます。

```
$ ruby hello.rb
    Welcome!
    Hello, World!
```


これはヒアドキュメント内のインデントがそのまま文字列に反映されてしまうためです。次のようにインデントをなくすことでこれを防ぐことが可能ですが、いささか不格好です。

```ruby
def hello
  message = <<-END
Welcome!
Hello, World!
  END
  puts message
end

hello
```

この Cop は上記のインデントされていないコードに警告を出し、よりスマートな解決方法を提示します。
解決方法には何種類かあるので見ていきましょう。

### 1. squiggly heredoc

Ruby 2.3 から squiggly heredoc と呼ばれる新しい構文が追加されました。`<<-`の代わりに`<<~`を使用します。

```ruby
def hello
  message = <<~END
    Welcome!
    Hello, World!
  END
  puts message
end

hello
```

```
$ ruby hello.rb
Welcome!
Hello, World!
```


TargetRubyVersion が Ruby 2.3 以上の場合、この Cop は上記の方法を推奨します。


### 2. ライブラリを使う

ライブラリを使用することで解決することも可能です。

```ruby
def hello
  message = <<-END.strip_heredoc
    Welcome!
    Hello, World!
  END
  puts message
end
```

例えば ActiveSupport では`String#strip_heredoc`が定義されており、これを使用することで不要な空白を削除することが可能です。
そして、この Cop は TargetRubyVersion が 2.2 以下かつ Rails を使用している場合は`String#strip_heredoc`を使用するスタイルを推奨します。

もし、Rails を使ってはいないけど ActiveSupport は使用している場合は、以下のように`.rubocop.yml`に追記して下さい。


```yaml
Style/IndentHeredoc:
  EnforcedStyle: active_support
```


Style/InverseMethods
--------

- PR https://github.com/bbatsov/rubocop/pull/4000
- Document http://rubocop.readthedocs.io/en/latest/cops_style/#styleinversemethods

`Integer#even?` `Integer#odd?`という、それぞれ偶数、奇数であれば`true`を返すメソッドが存在します。
この Cop は、そのような反対の意味を持つメソッドを否定しているコードを警告します。

```ruby
# bad
!n.even?

# good 上記のコードと等価
n.odd?
```

多くの場合無駄な否定が入らない`n.odd?`の方が読みやすくなるでしょう。



Lint/AmbiguousBlockAssociation
------------

- PR https://github.com/bbatsov/rubocop/pull/4090
- Issue https://github.com/bbatsov/rubocop/issues/3931
- Document http://rubocop.readthedocs.io/en/latest/cops_lint/#lintambiguousblockassociation

```ruby
some_method a { |val| puts val }
```

このコードには2通りの解釈があるように見えます。

- `some_method(a { |val| puts val })`
- `some_method(a) { |val| puts val }`

実際には前者に解釈されますが、カッコを省略した書き方は読む人に誤った解釈をさせてしまう可能性が高いです。

この Cop はカッコを省略した書き方を指摘し、カッコを入れるように推奨します。

Rails/ActiveSupportAliases
-------

- Issue https://github.com/bbatsov/rubocop/issues/3937
- PR https://github.com/bbatsov/rubocop/pull/3991
- Document http://rubocop.readthedocs.io/en/latest/cops_rails/#railsactivesupportaliases


ActiveSupport は、`String#start_with?`に対して`String#starts_with?`のようなエイリアスを提供しています。
この Cop はこのようなエイリアスを使用しないで、元々 Ruby に定義されているメソッドを使用するように推奨します。

Rails/Blank, Rails/Present
-------


- PR https://github.com/bbatsov/rubocop/pull/4133
- Documents
    - http://rubocop.readthedocs.io/en/latest/cops_rails/#railsblank
    - http://rubocop.readthedocs.io/en/latest/cops_rails/#railspresent

```ruby
foo.nil? || foo.empty?
!foo.nil? && !foo.empty?
```

上記のようなコードはそれぞれ`Object#blank?`, `Object#present?` を使用して書き換えることが出来ます。

この Cop はこのような不必要に複雑な条件を`blank?` / `present?` で書き換えられるコードを検出、指摘します。





Style/SymbolArray
------

- Issue https://github.com/bbatsov/rubocop/issues/4124
- PR https://github.com/bbatsov/rubocop/pull/4144
- Document http://rubocop.readthedocs.io/en/latest/cops_style/#stylesymbolarray


この Cop は以前から存在していましたが、今回のリリースまではデフォルトで無効になっていたため(恐らく)殆ど使われていませんでした。
そのため、新規追加 Cop として紹介させていただきます。

Ruby 2.0 から、`%i`および`%I`というシンボルの為のパーセント記法リテラルが追加されました。

```ruby
x = 10
p %i[foo#{x} bar] == [:'foo#{x}', :bar]  # => true
p %I[foo#{x} bar] == [:foo10, :bar]      # => true
```

この Cop はパーセント記法か普通のリテラルのどちらを使用するかを強制します。
デフォルトではパーセント記法を使用してリテラルを記述するように強制します。そのため、`[:foo, :bar]`のようなリテラルに対して警告を出します。

またこの Cop は Auto-Correct に対応しているため、スタイルを自動で修正することが可能です。

```ruby
# before
langs = [
  :ruby, :perl, :python,
  :java, :scala, :kotlin
]

# after `rubocop -a`
langs = %i(
  ruby perl python
  java scala kotlin
)
```



その他新機能 / 変更点
========

Style/MultilineMemoization
---------


- PR https://github.com/bbatsov/rubocop/pull/4019

この Cop は v0.44 で追加されました。 http://tech.sideci.com/entry/2016/10/20/110000

```ruby
foo ||= begin
  bar
  baz
end

foo ||= (
  bar
  baz
)
```

このようなメモ化を行う際のスタイルを統一する Cop ですが、いままでは前者の`begin-end`ブロックを使用するスタイルしかありませんでした。
今回のリリースで、後者の`()`を使用するスタイルも選択可能になりました。このスタイルを適用するには以下のコードを`.rubocop.yml`に追記して下さい。


```yaml
Style/MultilineMemoization:
  EnforcedStyle: braces
```



コマンドラインで雑にファイルを指定できるようになりました
--------

- PR https://github.com/bbatsov/rubocop/pull/3997


例えば git で変更が合ったファイルに対して RuboCop を適用したい場合、以下のように RuboCop を実行することが考えられます。

```bash
$ rubocop $(git diff --name-only)
```

しかし、diff に README.md などが含まれていた場合、README.md も RuboCop が解析しようとしてしまうため、今まではうまく動きませんでした。


今回のリリースから上記のコードが動くように変更されています。
RuboCop は `.rb` 拡張子付きのファイルや `Gemfile` などの特殊なファイル名のみを解析し、そうでないファイル(例: README.md)は明示的に引数に渡されたとしても解析を行いません。



TargetRailsVersion
-------


- PR https://github.com/bbatsov/rubocop/pull/4107


```yaml
AllCops:
  TargetRailsVersion: 5.0
```

これを`.rubocop.yml`に追記することで、指定した Rails のバージョンに適した解析が行われるようになりました。
デフォルトは 5.0 になっているため、Rails 4.x を使っている方は使用している Rails のバージョンを`.rubocop.yml`に追記すると良いでしょう。


# まとめ

この記事は以上になりますが、RuboCop 0.48.0ではこの他にも多くの機能追加、バグ修正が行われています。 より詳しい変更を知りたい方は、リリースノートをご覧ください。

[Release RuboCop 0.48 · bbatsov/rubocop](https://github.com/bbatsov/rubocop/releases/tag/v0.48.0)





# 過去のリリース

- [RuboCop 0.47.0 のCHANGELOGを読む - Qiita](http://qiita.com/pocke/items/ada412f69cff3ae273bb)
- [RuboCop 0.46.0 のCHANGELOGを読む - SideCI TechBlog](http://tech.sideci.com/entry/2016/12/01/150100)
- [RuboCop 0.45.0 のCHANGELOGを読む - SideCI TechBlog](http://tech.sideci.com/entry/2016/11/01/105900)
- [RuboCop 0.44.0 / 0.44.1 のCHANGELOGを読む - SideCI TechBlog](http://tech.sideci.com/entry/2016/10/20/110000)
- [RuboCop 0.43.0 の CHANGELOG を読む - SideCI TechBlog](http://tech.sideci.com/entry/2016/09/20/133051)
- [RuboCop 0.41 / 0.41.1 がリリースされました。 - SideCI TechBlog](http://tech.sideci.com/entry/2016/06/28/100415)