RuboCopのバージョン(0.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
されます。
# 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通りの書き方が存在します。
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
- PR https://github.com/bbatsov/rubocop/issues/4003
- Document http://rubocop.readthedocs.io/en/latest/cops_rails/#railsrelativedateconstant
# 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
- PR https://github.com/bbatsov/rubocop/pull/3984
- Document http://rubocop.readthedocs.io/en/latest/cops_style/#styleemptylinesaroundbeginbody
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
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
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
- PR https://github.com/bbatsov/rubocop/pull/4000
- Document http://rubocop.readthedocs.io/en/latest/cops_style/#styleinversemethods
Integer#even?
Integer#odd?
という、それぞれ偶数、奇数であればtrue
を返すメソッドが存在します。
この Cop は、そのような反対の意味を持つメソッドを否定しているコードを警告します。
# 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
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
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
というシンボルの為のパーセント記法リテラルが追加されました。
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