Rake in depth
Tasks and prerequisites
A Rakefile is a list of named tasks, and a task can name the tasks that must run first. rake with no argument runs the task called default:
task default: :test
desc "Run the tests"
task test: :prepare do
puts "running tests"
end
task :prepare do
puts "preparing"
end
rake
preparing running tests
The prerequisite runs once per invocation, even if two tasks name it. That is what makes rake ci possible: one task depends on lint, test and build, and each of those pulls its own setup.
rake -T
rake build # Build the report rake db:create # Create the database rake db:seed # Seed the database rake test # Run the tests
rake -T lists the tasks that have a desc. A task without one is a helper, and hiding it from the list is the point of the distinction.
Namespaces
A namespace prefixes the task names and keeps a project from growing a flat list. The prerequisite syntax inside a namespace resolves to the same namespace first:
namespace :db do
desc "Create the database"
task :create do
puts "created"
end
desc "Seed the database"
task seed: :create do
puts "seeded"
end
end
rake db:seed
created seeded
task seed: :create inside db means db:create, not a top-level create. The full name is available from anywhere as db:seed, and a top-level task can depend on "db:seed" as a string.
File tasks
file is the task that knows about timestamps: it runs only when the target is missing or older than a prerequisite. That is make without the syntax:
file "build/report.txt" => ["data.csv"] do |t|
mkdir_p "build"
File.write(t.name, "rows: #{File.readlines("data.csv").size}\n")
puts "wrote #{t.name}"
end
desc "Build the report"
task build: "build/report.txt"
rake build
mkdir -p build wrote build/report.txt
Run it again without touching data.csv and there is no output at all: the target is newer than the source, so the task is up to date. A build system that rebuilds everything every time is a Rakefile without file tasks.
multitask
multitask declares that two prerequisites do not depend on each other, so rake -m may run them at the same time:
multitask lint: [:rubocop, :whitespace] do
puts "lint done"
end
task :rubocop do
puts "rubocop"
end
task :whitespace do
puts "whitespace"
end
rake lint
whitespace rubocop lint done
The prerequisite order is not guaranteed, which is the point: a task that needs a particular order is a task with prerequisites, not a multitask.
What to watch for
A task name with a colon is a namespace, a name with a slash is a file.
Mixing them produces a task that runs once and then never again, or one
that runs every time; read the name before debugging the body.
sh raises when the command fails; a plain
backtick or system does not. A CI task that must
stop on the first failure uses sh "bundle exec rake
test".
Next: A real CLI with OptionParser
Article author: Arthur Isaev