RuboCop のバージョン 0.49.0 がリリースされました。
https://github.com/bbatsov/rubocop/releases/tag/v0.49.0
CHANGELOG から変更を見ていこうと思います。
破壊的変更
Layout Department
今回のリリースでは、新たに Layout Department が新設されました(ちなみに、Department とは RuboCop 用語で、Cop のグループのことです)。 Layout Department はインデントや行の整列、空白などコードのレイアウトに関する Cop が所属しています。
今回の Layout Department の新設に伴い、Style Department から70個の Cop が Layout Department に移動となりました。
そのため、移動対象となる Cop の設定を.rubocop.yml
で行っている場合、設定の書き換えが必要となります。
例:
# 旧 Style/SpaceInsideHashLiteralBraces: EnforcedStyle: no_space # 新 Layout/SpaceInsideHashLiteralBraces: EnforcedStyle: no_space
この書き換えを自動で行うツールを提供していますので、アップデートの際は是非お使い下さい。
新規Cop追加
Copとは、RuboCopにおいてひとつのルールを指す言葉です。例えば、「インデントが正しいかチェックする」「非推奨メソッドを使っていないかチェックする」などが1つのCopの単位になります。
この章では、0.49.0で新たに追加されたCopをひとつずつ紹介します。
Rails/ApplicationJob / Rails/ApplicationRecord
- Issue: https://github.com/bbatsov/rubocop/issues/4236
- PR: https://github.com/bbatsov/rubocop/pull/4279
- Document: http://rubocop.readthedocs.io/en/latest/cops_rails/#railsapplicationjob http://rubocop.readthedocs.io/en/latest/cops_rails/#railsapplicationrecord
Rails 5 からActiveRecord::Base
やActiveJob::Base
を直接継承するスタイルから、ApplicationRecord
などの共通の親クラスを定義してそれを個々のクラスで継承するスタイルへと変わりました。
この Cop は、ActiveRecord::Base
を直接継承しているようなコードに警告を出します。
# bad class User < ActiveRecord::Base end # good class User < ApplicationRecord end
なお、Rails 5よりも古いバージョンを使用している場合、TargetRailsVersion
を指定することでこれらの Cop を無効にすることが可能です。
# .rubocop.yml # Rails 4.0 を使っている場合 AllCops: TargetRailsVersion: 4.0
Performance/Caller
- PR: https://github.com/bbatsov/rubocop/pull/4078
- Document: http://rubocop.readthedocs.io/en/latest/cops_performance/#performancecaller
Kernel.caller
メソッドを使用することで、スタックトレースを配列で入手することが出来ます。
https://docs.ruby-lang.org/ja/latest/method/Kernel/m/caller.html
def foo bar end def bar p caller end foo # => ["test.rb:2:in `foo'", "test.rb:9:in `<main>'"]
この際caller
にcaller(1, 1)
のように範囲を渡すことで、指定した範囲のみのトレースを取得することが可能です。
限られた範囲のみのトレースが必要だと分かっている場合(例えば、caller.first
で最初だけがほしい場合など)は、範囲を渡して取得するトレースの範囲を狭めることでパフォーマンスの改善が見込めます。
この Cop は上記のような不必要に広い範囲のトレースを取得しているコードに対して警告を出します。
# bad caller.first # good caller(1, 1)
Style/FormatStringToken
- Issue: https://github.com/bbatsov/rubocop/issues/3438
- PR: https://github.com/bbatsov/rubocop/pull/4255
- Document: http://rubocop.readthedocs.io/en/latest/cops_style/#styleformatstringtoken
Ruby では文字列をフォーマットする際、いくつかの方法があります。
# printf などでよく見る方式 format('%s', 'Hello') # 名前付きバージョン。 format('%<greeting>s', greeting: 'Hello') # テンプレート。`s`が無いため、greeting には String 以外の値も入れられる。 format('%{greeting}', greeting: 'Hello')
この Cop は、この内の2つ目の方法を使うことを推奨します。 2つ目の方法は、1つ目の方法と比べて%s に greeting という名前がついているので、より説明的です。 また、3つ目と比べて、タイプチェックを行うため防御的と言えます。
format('%<length>d', length: 'foo') # => ArgumentError: invalid value for Integer(): "foo"
ただし、2つ目と3つ目は等価ではないことに注意して下さい。
2つ目は与えられた引数をフォーマットします。
そのため、%f
などを使用する場合に差異が出ます。
format('%<length>f', length: 42) # => "42.000000" format('%{length}', length: 42) # => "42"
Lint/ScriptPermission
- PR: https://github.com/bbatsov/rubocop/pull/4342
- Document: http://rubocop.readthedocs.io/en/latest/cops_lint/#lintscriptpermission
Shebang と呼ばれる特殊なコメントをファイルの先頭に置くことにより、そのファイルを読み込むインタプリタを指定することが出来ます。
#!/usr/bin/env ruby puts 'hello'
これを利用する際は、対象のファイルが実行可能である必要があります。
この Cop は、Shebang が存在するファイルが実行可能となっていることを検証します。 例えば、先程の例に挙げた Ruby コードが、パーミッション644のファイルとして保存されていた場合、この Cop は警告を出します。
Style/YodaCondition
- Issue: https://github.com/bbatsov/rubocop/issues/4145
- PR: https://github.com/bbatsov/rubocop/pull/4174
- Document: http://rubocop.readthedocs.io/en/latest/cops_style/#styleyodacondition
一般的に、Yoda Condition と呼ばれるテクニックが存在します。 これは条件式での誤った代入を避けるためのテクニックです。
# 一般的な if if x == 42 end # Yoda Condition の if if 42 == x end
このように Yoda Condition では条件式の変数と値の配置が逆になります。
この書式のメリットとして、イコールを抜かしてしまった場合(x = 42
/ 42 = x
)は Syntax Error になるため、誤ってイコールを抜くのを防ぐことが出来ます。
ですが、この記法はあまり可読性が高いとは言えず、また MRI は if x = 42
のような条件式内で定数を代入している文に対して警告を出します。
そのため、この Cop は Yoda Condition を避けるように警告を出します。
# bad if 42 == x end # good if x == 42 end
なお、この Cop は以下のような数値比較のコードも Yoda Condition だとみなします。
if 0 <= x && x <= 42 end
このようなコードを許可したい場合、この Cop を無効にするべきでしょう。
# In .rubocop.yml Style/YodaCondition: Enabled: false
また、この Cop にはいくつかバグがあるようなので、使用したい場合でも次のバージョンがリリースされるまでは無効にしておいても良いかも知れません。
Style/MultipleComparison
- PR: https://github.com/bbatsov/rubocop/pull/4021
- Document: http://rubocop.readthedocs.io/en/latest/cops_style/#stylemultiplecomparison
Ruby では、「変数が複数の値のどれかに当てはまること」をArray#include?
を使用してスマートに書くことが出来ます。
# bad - a が3回も登場して長い if a == 'a' || a == 'b' || a == 'c' end # good - a が一度しか登場せず、スッキリしている if ['a', 'b', 'c'].include? a end
この Cop は、上記のような条件式をスマートに書くように推奨します。
なお、good としている書き方は、スマートですが bad としている書き方よりも若干遅いです。
require 'benchmark' a = 'c' Benchmark.bm(20) do |x| x.report('== ||') {10000000.times{a == 'a' || a == 'b' || a == 'c'}} x.report('Array#include?'){10000000.times{['a', 'b', 'c'].include? a}} end
user system total real == || 1.190000 0.000000 1.190000 ( 1.190595) Array#include? 1.510000 0.000000 1.510000 ( 1.514413)
そのため、パフォーマンスが要求されるケースでは、bad とされているスタイルをあえて使う必要があることもあるでしょう。
Lint/RescueType
- PR: https://github.com/bbatsov/rubocop/pull/4358
- Document: http://rubocop.readthedocs.io/en/latest/cops_lint/#lintrescuetype
rescue
にクラス/モジュール以外の値を指定した場合、Ruby は「例外が起きた際」に TypeError を発生させます。
begin puts 'hello' # => hello rescue 42 # => 特に何も起きない end begin raise rescue 42 # => class or module required for rescue clause (TypeError) end
そのため、万が一クラス以外の値をrescue
に指定してしまっていた場合、発見が遅れることが考えられます。
この Cop は上記のようなコードを検出します。
その他新機能など
--parallel
オプション
並列実行をサポートする--parallel
オプションが追加されました。
このオプションを付与することで、RuboCop は解析を並列に行います。
そのため、複数コアを積んでいるマシンで RuboCop を使用する際には、--parallel
を付与することでより高速に RuboCop を実行することが可能でしょう。
$ time rubocop total 50.82s user 50.55s system 0.25s CPU 99% cmd rubocop $ time rubocop --parallel total 13.86s user 90.43s system 0.63s CPU 657% cmd rubocop --parallel
まとめ
この記事は以上になりますが、RuboCop 0.49.0ではこの他にも多くの機能追加、バグ修正が行われています。 より詳しい変更を知りたい方は、リリースノートをご覧ください。
Release RuboCop 0.49 · bbatsov/rubocop
過去のリリース
- RuboCop 0.48.0 のCHANGELOGを読む - Qiita
- RuboCop 0.47.0 のCHANGELOGを読む - Qiita
- RuboCop 0.46.0 のCHANGELOGを読む - SideCI TechBlog
- RuboCop 0.45.0 のCHANGELOGを読む - SideCI TechBlog
- RuboCop 0.44.0 / 0.44.1 のCHANGELOGを読む - SideCI TechBlog
- RuboCop 0.43.0 の CHANGELOG を読む - SideCI TechBlog
- RuboCop 0.41 / 0.41.1 がリリースされました。 - SideCI TechBlog