LoginSignup
8
11

More than 3 years have passed since last update.

Rubyのrakeについての基礎知識

Last updated at Posted at 2020-03-03

rakeとは

Rake は Make によく似た機能を持つ Ruby で書かれたシンプルなビルドツールです。

世間では、ビルドツールというとMakeやApache Antが有名で、よく使われている。 Rakeは、これらのいいとこ取りをした上で、特有のフィーチャーを追加した新しいビルドツールであり、複雑なビルドを柔軟に書きこなすことができる。その秘密は内部DSLという仕組みにあり、このおかげでビルドの記述にRubyの強力な文法をそのまま使うことができる。この自由度の高さは、ビルドの記述に独自の言語の使用を選択したMakeとAntには無い強みだ。

rakeとはrubyで書いたビルドツールのこと。
makeでいうMakefileの代わりに、Rakefileというファイルを作成して実行することができる
RakefileはRubyのDSLで書くことができるのでrubyさえわかれば記述が可能なので楽

rakeの用語についてのまとめ

用語 意味
task Rakeファイルの基本単位。
ファイルタスク ファイル生成に特化したタスク
アクション taskのブロック内の実行されるコードのこと
invoke タスクを実行する。実行されたことのあるアクションは実行しない。依存しているタスクも呼び出だす
execute タスクを実行する。常にアクションを実行する。依存関係にあるタスクは実行しない

invokeとexcuteについてはこちらの記事が非常にわかりやすい。

rakeタスク内で別のタスクを呼び出す
http://qiita.com/paty-fakename/items/5df189681c92ce1e8004

Rakefileを作成してみる

Rakefileという名称でファイルを作成し、下記を記述する

task :hello do
  puts 'hello world'
end

rakeコマンドを入力してタスクを実行すると結果が返ってくる

$ rake hello

#=> do task hello!

依存関係を作って実行してみる

今度は以下のコードをRakefileに書いてください

task "dist" => ["init", "compile"]

task "init"

task "compile"

以下で実行。
-tオプションをつけると実行内容が表示される。

$ rake -t dist

** Invoke dist (first_time)
** Invoke init (first_time)
** Execute init
** Invoke compile (first_time)
** Execute compile
** Execute dist

distを実行すると、initとcompileが順番に実行されたのがわかると思います
taskはハッシュを引数にすると、task同士の依存を書くことができます

ちなみにrakeというコマンドを入力した場合は、defaultという名前のタスクが実行されるようになっている

task "default" => "dist"

task "dist" => ["init", "compile"] do
  puts "dist"
end

task "init" do
  puts "init"
end

task "compile" do
  puts "compile"
end

なので上記のようにRakefileを書き換えてrakeを実行するとdefaultのタスクが実行されて依存関係のあるdistが実行される

$ rake

#=> init
#=> compile
#=> dist

fileタスク

先ほどまでtaskブロックで実行してきたが、rakeにはファイル作成に特化したタスクもある

fileタスクの第一引数には実行するファイルのパスを指定する
taskと結びつけることによって、rake実行時にrake test_txtとして名称を指定して実行できる

# fileタスクをtaskと結びつける
task test_txt: './test.txt'

desc 'test.txtの中身を読み込んで、read.txtを作成する'
file './test.txt' do
  puts 'write read.txt'

  File.open('./test.txt', 'w') do |f|
    f << "success"
  end
end

descというのが新たに出てきているが、ここにはタスクの説明を書くのに使用する
実行すると、test_dir/test.txtが作成される

$ rake test_txt

#=> write test.txt

fileタスクの利点

このfileタスクは下記の場合のみ実行される

  • 指定したファイルパスにファイルがない場合
  • ファイルが作成されている場合、依存先のファイルの更新日時を調べそれが目的ファイルより新しくなっている場合

つまり、ファイルを新規に作成しなければならないときか、ファイルが変更されたときのみ実行できる。なので、ファイル操作の条件判定などを自分で書く必要がなくなる

なので先ほどのtest_txtを2回やっても、test.txtが作成済みなので何も実行されない。

$ rake test_txt

#=> (何も実行されない)

依存関係のあるfileタスクを書く

fileタスクの引数をハッシュ形式にすると依存が書ける
'実行予定のファイルパス' => '依存しているファイルパス'という形式で書く

先ほどのファイルを少し改変して、test_dir/test.txtを作成したあと、それを利用してread.txtというファイルを作成する

task read: './read.txt'

desc 'test.txtの中身を読み込んで、read.txtを作成する'
file './read.txt' => './test.txt' do
  puts 'write read.txt'

  File.open('./read.txt', 'w') do |f|
    # test.txtの中身を読みこんでread.txtに書き込む
    f << File.read('./test.txt')
  end
end

desc 'test.txtを作成する'
file './test.txt' do
  puts 'create test.txt'
  File.open('./test.txt', 'w') do |f|
    f << "success"
  end
end

test.txtがないときにこれおを実行すると、test.txtとread.txtが作成される

$ rake read

#=> write test.txt
#=> create read.txt

上記で書いたようにfileタスクはファイルがない場合か、依存ファイルが変更された場合のみ実行される。なのでもう一度実行してもタスクは実行されない

$ rake read

#=> (何も実行されない)

試しに依存ファイルのtest_dir/test.txtの中身を変更してみる

test.txt
success
success2 # この行を追加

するとread.txtに関するタスクだけが実行されるように表示される。
もちろんread.txtの中身も書き換わっている

rake read

#=> write read.txt

fileタスクを利用してc言語のソースをコンパイルしてみる

冒頭でMakeに似たビルドツールという風に書いたように、C言語のソースをコンパイルするタスクも書くことができる。下記のようにhello worldを実行するだけのC言語のファイルがあったとする

hello.c
#include <stdio.h>

int main(int argc, const char * argv[]) {

  printf("hello world!\n");
  return 0;
}

先ほどの依存関係の実行と同じように下記のように書く

CC = "gcc"

task :default => "hello"

# helloというファイルを作成するためにはhello.oが必要
file "hello" => "hello.o" do
  sh "#{CC} -o hello hello.o"
end

# hello.oというオブジェクトファイルをコンパイルするためにはhello.cというファイルが必要
file "hello.o" => "hello.c" do
  sh "#{CC} -c hello.c"
end

実行するとhelloというファイルができる
taskにdefaultを指定しているので、rakeだけで実行できる

$ rake

ファイルが作成されたので実行して世界にあいさつ

$ ./hello

# => hello world!

RailsのRakeタスクはどう動作するのか

Rakefileがあるとrakeコマンドが実行できることはわかったと思うが、Railsでタスクを作成するときはlib/tasksに作成するのが基本である。

RailsのRakfileは以下のようになっている。

require_relative "config/application"

Rails.application.load_tasks

このload_tasksは以下で定義されている

rails/railties/lib/rails/engine.rb
def load_tasks(app = self)
  require "rake"
  run_tasks_blocks(app)
  self
end

# ~省略~

def run_tasks_blocks(*) #:nodoc:
  super
  paths["lib/tasks"].existent.sort.each { |ext| load(ext) }
end

pathslib/tasksがあるかどうかexistentで判断して、あればloadするという流れになっている。

参考

rubyリファレンス rake
https://docs.ruby-lang.org/ja/2.7.0/library/rake.html

RubyによるビルドツールRakeの覚え書き
http://www2s.biglobe.ne.jp/~idesaku/sss/tech/rake/

8
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
11