There are times when we want to pass variable data to our tasks; whether it’s to act as a switch between different behaviors, or if it’s to provide needed input for our task to run properly. Whatever the case, it is a useful thing to know about when creating Rake tasks.
This is the fourth post in a series on Rake and I believe this post is the missing piece to complete the series. The topics of the previous posts include: an introduction to the Rakefile format, file tasks, and rule tasks.
The ENV-workaround
It’s quite common to use environment variables in order to pass variable data to Rake tasks – and this is how Rails’ Rake tasks do it.
Let’s start by declaring a task called first
which will read the VAR
environment variable:
task :first do
puts "VAR in `first` is #{ENV['VAR'].inspect}"
end
We’re using #inspect
here so that the value of our argument is explicitly
clear.
Now let’s look at running this task in a shell:
$ rake first
VAR in `first` is nil
$ VAR=a rake first
VAR in `first` is "a"
As you can see in the first invocation, if the environment variable is not set,
then the ENV
object will return nil
for our VAR
name. In the second
invocation, we’re using our shell’s facility to set an environment variable
while running a program, and that value is available to us while our task is
running.
None of this is Rake-specific; it’s just Ruby running on a Unix-like system. That said, Rake does provide another way of setting environment variables:
$ rake first VAR=b
VAR in `first` is "b"
As you can see, Rake will add options in the VAR=VALUE format to the ENV
object.
Proper Task Arguments
The example above shows a common approach you will see for how to supply variable data to Rake tasks, but Rake actually has real support for task arguments.
You declare task arguments with an Array as the second parameter to the task
method, and the values are accessible via the second parameter given to our
action block:
task :second, [:var] do |task, args|
puts "var in `second` is #{args.var.inspect}"
end
When invoking a task, parameters are placed inside of square brackets after the name of the task:
$ rake second[c]
var in `second` is "c"
Arguments are not required, your task will need to handle potential nil
values:
$ rake second
var in `second` is nil
But again, Rake provides a handy way of setting default values for our task
arguments, by called #with_defaults
on our args
object:
task :third, [:var] do |task, args|
args.with_defaults(var: 'default')
puts "var in `third` is #{args.var.inspect}"
end
Now when our task is invoked, we no longer need to worry about nil
argument
values:
$ rake third
var in `third` is "default"
$ rake third[d]
var in `third` is "d"
Arguments & Prerequisites
You might be wondering to yourself: how do you declare a task that has
arguments and prerequisites? Well, you pass a Hash as the second parameter to
the task
method; the key of the Hash contains your task’s arguments and the
value contains the prerequisites.
Let’s declare a task called fourth
that has an argument called var
and
depends on our task called third
:
task :fourth, [:var] => [:third] do |task, args|
args.with_defaults(var: 'fallback')
puts "var in `fourth` is #{args.var.inspect}"
end
Parameters given to your task will be passed to its prerequisites as well:
$ rake fourth
var in `third` is "default"
var in `fourth` is "fallback"
$ rake fourth[e]
var in `third` is "e"
var in `fourth` is "e"
In the above invocations, the first line of output comes from the third
task,
and the second line comes from the fourth
task.
Useful Example
Each post in this series has tried to include a useful example of a task using the aspect of Rake described in the post. But, for this post, I’m going to reference back to the example in the first post, as it used task arguments as well.