LoginSignup
13
8

More than 5 years have passed since last update.

RuboCop 0.48.0 のCHANGELOGを読む

Posted at

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

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

新規Cop追加

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

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

Style/EmptyLineAfterMagicComment

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

# frozen_string_literal: true

p 'a'.frozen? # => true

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

Style/MixinGrouping

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

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に以下のように書く必要があります。

Style/MixinGrouping:
  EnforcedStyle: grouped

Rails/RelativeDateConstant

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

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

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

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

Style/EmptyLinesAroundBeginBody

begin

  foo
  bar

end

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

Style/EmptyLinesAroundExceptionHandlingKeywords

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

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

hello

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

$ ruby hello.rb
    Welcome!
    Hello, World!

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

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

hello

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

1. squiggly heredoc

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

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

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

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

2. ライブラリを使う

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

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に追記して下さい。

Style/IndentHeredoc:
  EnforcedStyle: active_support

Style/InverseMethods

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

# bad
!n.even?

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

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

Lint/AmbiguousBlockAssociation

some_method a { |val| puts val }

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

  • some_method(a { |val| puts val })
  • some_method(a) { |val| puts val }

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

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

Rails/ActiveSupportAliases

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

Rails/Blank, Rails/Present

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

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

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

Style/SymbolArray

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

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

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 に対応しているため、スタイルを自動で修正することが可能です。

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

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

その他新機能 / 変更点

Style/MultilineMemoization

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

foo ||= begin
  bar
  baz
end

foo ||= (
  bar
  baz
)

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

Style/MultilineMemoization:
  EnforcedStyle: braces

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

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

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

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

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

TargetRailsVersion

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

過去のリリース

13
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
8