【Ruby/Rake】Rails以外の環境でRakeタスクを作成・実行する

2020年8月16日Ruby

追記: 2026/11/03

全体的に記述がシンプルすぎたので、追記しました。
追記時点からは3年前の記事ですが、内容自体は現状でも有効なものなので、加筆・修正しました。


Rakeといえは、RubyでかけるMakefileのようなもの。
しかし、私はMakefileを書いたことがないので、単にRubyでちょっとしたタスクをコマンドとして呼び出せる便利ツールくらいに思っています。

このRakeですが、タスクの追加方法や設定等について調べて出てくるのはどうしてもRails環境が多いのが現状です。
railsは内部的にはRakeを呼んでいる(?)っぽいので、しょうがないといえばしょうがないですが・・・。
ということで、Railsではない環境でRakeタスクを作って実行する方法をメモしておきます。

準備

Rakeといっても、Gemとして配布されています。
default gemとしてすでに入っているとは思いますが、必要であれば明示的にGemfileに入れてあげましょう。

gem "rake"

そしてbundle install。
ほかのGemと同じなので困ることはないはずです。

Rakeタスクの実装

Rakefileの作成

Rakefileは、Rubyで記述するタスク等の設定ファイルです。
これは、プロジェクトルートに設置します。

Rakefileの中身としては、基本的には実行したいタスクを追加してあげればOKです。
Railsと同じようにlib/tasks/*.rakeという感じでタスクを個別のファイルで定義したい場合は、Rakefileの上部に以下のように記述すると<プロジェクトルート>/libにあるファイルを参照します。

Dir["./lib/tasks/*.rake"].sort.each {|file| load file}

なお、ここではRakeタスクをhoge.rakeとして定義する形を想定していますが、通常の.rbでも問題ありません。
ただ通常のRubyスクリプトなのか、Rakeタスクなのかをわかりやすくするために拡張子を分けておくことをお勧めします。

追記: 2026/11/03

Ruby 3.0以降からDir#globやDir#[]の結果がデフォルトでソートされるようになりました。
上記では明示的にソートしていますが、旧バージョンでも同じく動作させる場合や明示したい場合は上記で良いと思います。
そうでなければ、現行のRubyはv4系なので下記で問題ありません。

Dir["./lib/tasks/*.rake"].each {|file| load file}

一応、ソートされたタイミングで簡易的な記事も書いているのでそちらもどうぞ。

なぜloadで読み込むのか

Kernel?.loadのドキュメントに、requireとloadの違いについて記述されています。
引用すると、以下の通り。

Kernel?.require は同じファイルは一度だけしかロードしませんが、 Kernel?.load は無条件にロードします。また、require は拡張子.rb や .so を自動的に補完しますが、 load は行いません。 require はライブラリのロード、load は設定ファイルの読み込みなどに使うのが典型的な用途です。

require は「クラスやモジュールなどのライブラリを一度だけ取り込む」ための仕組みです。
Rakeタスクは、ライブラリではなくどちらかというとスクリプトに近いため、loadで読み出す方が用途として合っているのが理由かと思います。

タスクの定義

シンプルなタスクの定義

タスクの内容は、以下のように定義します。

 namespace :task do
   desc "シンプルなタスク"
   task :test do
     puts "test task!"
   end
   
   desc "引数ありの場合"
   task :arg_task, [:hoge] do |_, args|
     puts args[:hoge]
   end
 end

ファイル名ごとにnamespaceを切ってあげると、タスク名に困ることはなくなると思います。
例えば、エクスポートするタスクを組みたいが、Userデータのエクスポートと売上データのエクスポートを実装したければ、namespaceにexportとしつつ、タスク名にuserやsalesとすれば、bundle exec rake export:userのように実行可能です。
もしくは、Userデータに関するタスクはuser、売上データに関するタスクはsalesのようなnamespaceをつけ、それぞれにexportタスクを用意することでbundle exec rake user:exportやbundle exec rake sales:exportのように実行可能です。
この辺は、タスクをどの粒度でまとめるか、という設計の問題なのでお好みでどうぞ。

そして、rakeタスクを実行するときに引数を渡して実行することができます。
例えば、bundle exec rake task:arg_task[hogehoge]とするとコマンドラインから値を渡すことができます。

二つ目のタスクの通り、タスク名の後に配列で引数の名前を付けてあげる。
そしてブロックに2つの変数を作ってあげて、二つ目の変数に引数が入ってくるので指定した名前でアクセスすると取得できます。

複数のタスクを順序通りに実行する

タスクランナーとしてRakeを使う場合や、デプロイ作業の前にrubocopやrspecを動作させてチェックしたいなど、一連のタスクを順番に実行させたい場合があります。
そのときは、以下のように記述することで複数のタスクを順番通りに実行する1タスクとして定義・実行させることができます。
なお、以下の例ではnamespaceを一応つけてますが、なくてもタスクの定義としては問題ありません。

namespace :list do
  desc "initを実行後、compileを実行する"
  task "dist" => %w[initialize build] do
    puts "finish"
  end

  desc "処理の初期化"
  task "initialize" do
    puts "init process..."
  end

  desc "コンパイルする"
  task "build" do
    puts "building!!!"
  end
end

bundle exec rake list:distを実行すると、initializeタスクとbuildタスクを実行したのち、distタスクを実行します。

タスク名を指定せずに既定のタスクを実行する

defaultタスクを定義し、実行させたい既定のタスクを文字列リテラルで指定すればOKです。
上記のlist:distタスクをデフォルトタスクとして指定する場合は以下のようになります。

task default: "list:dist"

namespace :list do
  desc "initを実行後、compileを実行する"
  task "dist" => %w[initialize build] do
    puts "finish"
  end

  desc "処理の初期化"
  task "initialize" do
    puts "init process..."
  end

  desc "コンパイルする"
  task "build" do
    puts "building!!!"
  end
end

タスク名を指定せずにrakeを実行すると、デフォルトタスクが実行されます。

$> bundle exec rake
init process...
building!!!
finish

定義したタスクの一覧を確認する

上記のように複数のタスクを定義したり、タスクのカテゴリごとにファイルを分けたりしている場合、どのようなタスクが定義されているのかを確認できると便利です。
確認するときは、以下のコマンドで確認できます。
なお、タスク名と一緒にdescで指定した文字列がタスクの説明文として表示されます。

$> bundle exec rake -T
rake list:build        # コンパイルする
rake list:dist         # initを実行後、compileを実行する
rake list:initialize   # 処理の初期化
rake simple:aggregate  # ユーザーデータを集計してログに出力する

なお、デフォルトタスクやタスクにdescが設定しないタスクはこのリストに載りません。
タスクを定義したがタスク一覧に出力されない、という場合はdescで説明文が書かれているかを確認しましょう。

まとめ

今回は、非Rails環境でRakeタスクを追加・実装する方法をメモしておきました。
覚えておくと、ちょっとしたコマンドをRuby/Rakeで作れるので便利です。

RakeタスクはRails環境でしか使ったことがなかったので、素のRubyでも使えることが分かったのと、
ついでに実行時に引数を渡す方法もわかったので、簡単なコマンドをRakeで実装できるようになりました。
Rubyで良しなにスクリプトを書いた後、コマンドっぽく実行したいときに使えそうですね。

今回はここまで。

おわり。

Posted by しきゆら