pockestrap

Programmer's memo

RuboCop Rake をリリースしました

github.com

これはなに

RuboCop Rakeは、Rake関連のファイルに対してのCopを集めたRuboCopプラグインです。

実はリリースは少し前からしていたのですが、晴れてRuboCop HQ下に移動した1のでリリース記事を書いてみました。

Cops

現在、RuboCop Rakeは3つのCopを持っています。

Rake/Desc

Rake/Descdescのないタスク定義を検出するCopです。

Rakeはdescのないタスクをrake -Tコマンドで表示しません。

# Rakefile

desc 'Task with description'
task :task_with_desc

task :task_without_desc
$ rake -T
rake task_with_desc  # Task with description

これはrake -Tの出力する一覧からタスク定義を探したい場合にとても不便です。 また、単にドキュメンテーションとしても有用でしょう。

Rake/MethodDefinitionInTask, Rake/ClassDefinitionInTask

Rake/MethodDefinitionInTaskは、タスク定義/ネームスペース定義内のメソッド定義を検出します。またRake/ClassDefinitionInTaskはそれのクラス/モジュール版です。

Rakeでは、ネームスペース定義内でもスコープはトップレベルです。つまり、ネームスペース定義内でメソッドを定義したとしても、それはトップレベルに定義されます。

# Rakefile
namespace :foo do
  class C
  end
end

p C # Cはトップレベルに定義されているので、ここでもアクセスできる。

これは分かって書いているならまだ良いのですが、namespaceがモジュールの名前空間も作成していると誤解して書いてしまうと事故の元となります。 トップレベルに定義されないと思って定義したクラスが、他のトップレベルのクラスを意図せず上書きしてしまうかもしれません。

このCopはそのようなコードを検出します。 ネームスペース内でクラスを定義したい場合はClass.newなどを使って衝突を回避するか、衝突の可能性があることを理解した上でこのCopをdisabledにすると良いでしょう。

Future

RuboCop RakeにはまだCopが3つしかありません。 ですが実装していないだけでCopのアイディアはいくつかあります。

重複したタスク/ネームスペースの定義

Rakeでは、重複したタスク/ネームスペースの定義があると、それらはマージされるようになっています。

# Rakefile
task :foo do
  p 'foo 1'
end

task :foo do
  p 'foo 2'
end
$ rake foo
"foo 1"
"foo 2"

おそらくこれらを2つに分けて書く必要はないでしょう。 タスクが2つに分かれて定義されることには、私は次のようないくつかの問題があると思います。

  • 挙動が自明ではない
    • メソッド定義のように片方がもう片方に隠されるとも想像できる。
  • 2つ定義していることに気が付かないかもしれない
    • この2つの定義が離れた位置にあったら、どちらか片方しか目に入らないために片方に気が付きづらくなる。
  • 単に無駄
    • 意味もなく分ける必要はない

このCopの実装は一見簡単そうですが、ネームスペースを考えると少し面倒そうです。

# Rakefile

# 次の2つは同じタスク
task :'foo:bar'

namespace :foo do
  task :bar
end

実装としてはon_xxxのパターンを使わず、investigationメソッドでファイル内すべてのタスク定義の名前を取り出して、その中の重複を調べる形になるのではないかなと思っています。

タスク名に:を使っているものを警告する

# bad
task :'foo:bar'

# good
namespace :foo do
  task :bar
end

やるだけですね。goodとbadが逆のパターンも簡単に実装できそうですが、需要があるのかわかりません。 そもそもこのCopに需要があるかも微妙ですね。タスク名にコロンを書きたくなることもあると思うし混在していて良いと思うので、デフォルトではdisabledでも良いかなと思っています。

まとめ

簡単にRuboCop Rakeの紹介をしました。 ぜひ使ってみてください。

また、Pull Request, Issueをお待ちしています。 RuboCopで検出できるRakeで書きがちな問題はまだまだあると思うので、そういうアイディアをIssueにもらえるだけでも助かります。