こんにちは、RuboCop大好き!Pockeです。
先日、RuboCopのバージョン0.43.0がリリースされました。
Release RuboCop 0.43 · bbatsov/rubocop
このリリースには、筆者を始めとするSideCIのメンバーによるPull Requestも11個含まれています。 今日はそのCHANGELOGから、気になる新機能を見ていきましょう。
新規Cop追加
Copとは、RuboCopにおいてひとつのルールを指す言葉です。例えば、「インデントが正しいかチェックする」「非推奨メソッドを使っていないかチェックする」などが1つのCopの単位になります。 この章では、0.43.0で新たに追加されたCopをひとつずつ紹介します。
Style/DocumentationMethod
- PR https://github.com/bbatsov/rubocop/pull/3296
- Issue https://github.com/bbatsov/rubocop/issues/2968
このCopはPublicメソッドに対してドキュメントコメントを書くことを促します。
解説
class MyClass # Method1 does something. def method1 # ... end def method2 # ... end private def method3 # ... end end
例えば上記のようなClass定義をこのCopで検査した場合、def method2
の部分に下記のような指摘が行われます。
test.rb:7:3: C: Missing method documentation comment. def method2 ... ^^^^^^^^^^^
def method1
ではドキュメントコメントが書かれているため、またdef method3
ではプライベートメソッドを定義しているため、指摘は発生しません。
まとめ
長く保守していくコードでは、ドキュメントコメントの有無がメンテナンスを行う上で重要となります。
コーディング規約としてコメントを書くことを強制したい場合、このCopを有効活用することが出来るでしょう。
なお、コメントを書く必要が薄いメソッドも多いためか、このCopはデフォルトでは無効になっています。
そのため、このCopを使用したい場合は.rubocop.yml
などで明示的に有効にする必要があります。
Style/SafeNavigation
このCopはSafe navigation operatorが使用できる場合、それを使用することを促します。
Safe navigation operatorは、Ruby 2.3で新たに追加された演算子です。
foo&.bar
の様に使用します。これはfoo.nil? ? nil : foo.bar
のように動作します。
参考: サンプルコードでわかる!Ruby 2.3の主な新機能 - Qiita
解説
if foo foo.bar end foo.bar if foo foo && foo.bar
上記のような文は、全てfoo&.bar
で代替することが可能です。
そのため、上記コードに対して検査を行うと、以下のような指摘が行われます。
test.rb:1:1: C: Use safe navigation (&.) instead of checking if an object exists before calling the method. if foo ... ^^^^^^ test.rb:5:1: C: Use safe navigation (&.) instead of checking if an object exists before calling the method. foo.bar if foo ^^^^^^^^^^^^^^ test.rb:7:1: C: Use safe navigation (&.) instead of checking if an object exists before calling the method. foo && foo.bar ^^^^^^^^^^^^^^
まとめ
Safe navigation operator を使用することでコードをシンプルに保つことが可能です。
導入してみてはいかがでしょうか。
なおSafe navigation operatorはRuby2.3から追加された演算子であるため、このCopを動作させるには.rubocop.yml
で明示的にRubyのバージョンを指定する必要があります。
以下のコードを.rubocop.yml
に追記して下さい。
AllCops: TargetRubyVersion: 2.3
Rails/SafeNavigation
このCopもStyle/SafeNavigation
と同様、Safe navigation operatorが使用できる場合にそれを使用することを促します。
Style/SafeNavigation
と異なる点は、ActiveSupportで追加されるtry!
メソッドを対象にすることです。
解説
foo.try!(:bar)
例えば、上記のコードはfoo&.bar
と同等です。そのため、上記のコードを検査すると以下の指摘が行われます。
test.rb:1:1: C: Use safe navigation (&.) instead of try!. foo.try!(:bar) ^^^^^^^^^^^^^^
まとめ
ActiveSupport
が提供する拡張に依存しないコードを書くことが出来るため、積極的にSafe navigation operatorを使うように矯正できるこのCopは有用でしょう。
なお、このCopを有効にするには以下のコードを.rubocop.yml
に追記する必要があります。
AllCops: TargetRubyVersion: 2.3 Rails: Enabled: true
Rails/NotNullColumn
Railsアプリケーションのマイグレーションファイル内で、NOT NULL
制約がついておりデフォルト値がついていないカラムの追加を検出します。
解説
class AddNotNullColumn < ActiveRecord::Migration[5.0] def change add_column :users, :name, :string, null: false end end
上記のようなマイグレーションを実行すると、(使用しているRDBMSにもよりますが)多くの場合エラーが発生してマイグレーションが失敗してしまいます。
またMySQLを使用している場合にはエラーは出ないものの、既存のレコードのname
カラムに対してはMySQLが勝手にデフォルト値を設定します。
そのため、このCopは上記のコードに対して下記の指摘を行います。
db/migrate/test.rb:3:40: C: Do not add a NOT NULL column without a default value add_column :users, :name, :string, null: false ^^^^^^^^^^^
この指摘を回避するには、null: false, default: ''
のようにデフォルト値を指定する必要があります。
まとめ
開発時と運用時で異なるRDBMSを使用していたり複数のRDBMSのサポートを行っている場合、このCopは問題の早期発見に役立つでしょう。
なお、このCopを有効にするには以下のコードを.rubocop.yml
に追記する必要があります。
Rails: Enabled: true
Style/VariableNumber
- PR https://github.com/bbatsov/rubocop/pull/3416
- Issue https://github.com/bbatsov/rubocop/issues/3167
このCopは、変数名に数字を含める際のスタイルを統一します。
解説
変数名に数字を含める場合、以下のような3通りのケースが考えられます。
# 変数名にそのまま数字を続ける var1 = 1 # 変数名と数字の間にアンダースコアを入れる var_1 = 1 # 数字をそもそも使わない var_one = 1
このCopを使用することで、この3つのスタイルのうちどれかに統一することが可能です。
それぞれ.rubocop.yml
に以下のコードを追記します。
# var1 に統一する場合 Style/VariableNumber: EnforcedStyle: normalcase # var_1 に統一する場合 Style/VariableNumber: EnforcedStyle: snake_case # var_one の様に数字を含ませないよう統一する場合 Style/VariableNumber: EnforcedStyle: non_integer
まとめ
プロジェクトで変数の命名規則が決まっている場合、このCopを有効活用することが出来るでしょう。
特に命名規則が決まっていない場合、以下のコードを.rubocop.yml
に追記することでこのCopを無効にすることが可能です。
Style/VariableNumber: Enabled: false
Performance/SortWithBlock
このCopは、パフォーマンス上の観点から不要なsort
メソッドの呼び出しをsort_by
メソッドに置き換えます。
解説
Rubyには、ソートを行う為のメソッドがsort
とsort_by
の2つ定義されています。
配列の中身をString
に変換した上で辞書式順序でソートしたい場合、sort
メソッドでは以下のように書きます。
array.sort{|a, b| a.to_s <=> b.to_s}
しかし、この書き方では後述するsort_by
メソッドより低速になってしまいます。
sort
メソッドは比較を行う度にブロックを呼び出すため、比較の回数だけto_s
が呼ばれてしまいます。
sort_by
を使用すると、この点を解消することが可能です。
array.sort_by(&:to_s)
sort_by
では全ての要素に1度ずつしかto_s
を呼び出さないため、このケースではsort
を使用するよりも高速にソートを行うことが可能となります。
このCopを使用して最初に例にあげたコードを検査すると、以下のような指摘を行います。
test.rb:1:7: C: Use sort_by(&:to_s) instead of sort { |a, b| a.to_s <=> b.to_s }. array.sort{|a, b| a.to_s <=> b.to_s} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
まとめ
このCopを使用することで、パフォーマンス上の問題となりうる点を自動的に検出することが可能です。
また、このCopはAuto Correct機能に対応しているため、-a
オプションを付与してRuboCopを実行することで対象のコードを自動で修正することが可能です。
Lint/UnifiedInteger
このCopは、Fixnum
, Bignum
クラスを参照している箇所を検出します。
解説
Ruby 2.4 では、Fixnum
, Bignum
クラスはInteger
クラスに統合される予定です。
参考: サンプルコードでわかる!Ruby 2.4の新機能と変更点 - Qiita
Ruby 2.4からはFixnum
, Bignum
クラスは両者ともInteger
クラスへの参照となります。
そのため、Fixnum
がコード中に書かれている場合は見た目と挙動が異なり、わかりづらいコードとなってしまいます。
このCopはそのような状態を防止するため、Fixnum
,Bignum
クラスの使用を指摘します。
例えば、以下のコードに対して以下の指摘を行います。
a.is_a? Fixnum a.is_a? Bignum a.is_a? Integer
test.rb:1:9: W: Use Integer instead of Fixnum. a.is_a? Fixnum ^^^^^^ test.rb:2:9: W: Use Integer instead of Bignum. a.is_a? Bignum ^^^^^^
まとめ
このCopを使用することで、上記のような紛らわしいコードを検出することが可能です。
また、このCopはRuby 2.4未満を使用している場合でも有効となっています。
Ruby2.4への移行を考えた際にこのCopが有効に働くこと、そもそもFixnum
やBignum
を使用するケースは少なくInteger
の間違いである可能性が高いこと、が理由です。
その他
この章では、新規Cop追加以外の新機能を見ていきます。
HTMLフォーマッタの出力に目次がつくようになりました
- PR https://github.com/bbatsov/rubocop/pull/3472
- Issue https://github.com/bbatsov/rubocop/issues/3379
rubocop --format html > index.html
の様にRuboCopを実行すると、RuboCopの結果をHTMLとして出力することが可能です。
今回のリリースでは、この出力に目次がつくようになりました。
筆者はあまりHTMLフォーマッタを使用しないのですが、このフォーマッタをよく使用するユーザーにとっては便利な機能かもしれません。
まとめ
この記事は以上になりますが、RuboCop 0.43.0ではこの他にも多くの機能追加、バグ修正が行われています。 より詳しい変更を知りたい方は、リリースノートをご覧ください。
Release RuboCop 0.43 · bbatsov/rubocop
また、SideCIでは今すぐRuboCop 0.43.0を利用することが可能です。是非お試し下さい!