Jacob Swanner Development Blog

Rake: Task Arguments

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.