Book Image

Rake Task Management Essentials

By : Andrey Koleshko
Book Image

Rake Task Management Essentials

By: Andrey Koleshko

Overview of this book

Table of Contents (18 chapters)
Rake Task Management Essentials
Credits
About the Author
Acknowledgements
About the Reviewers
www.PacktPub.com
Preface
Index

Task dependencies – prerequisites


Sometimes, you have to write tasks that depend on other tasks. For example, when I'm going to seed data in my project, I want to clean all the persisting data that can break my code. In this case, we can say that our seed data task depends on the clean seed data task. The following code example shows us a Rakefile for this case:

task :clean do
  puts 'Cleaning data...'
end

task :seed => :clean do
  puts 'Seeding data...'
end

The preceding code executes the clean do task before running the seed task. The result of the execution of this task is shown below the following line of code:

$ rake seed
Cleaning data...
Seeding data...

It works as expected.

If you have to run the task from another namespace, pass its whole name as a string, as shown in the following code snippet:

namespace :db do
  task :clean do
    puts 'Cleaning data...'
  end
end

task :seed => 'db:clean' do
  puts 'Seeding data...'
end

However, if the dependent task is in the same namespace, you don't have to pass it as a string, as shown in the following code snippet:

namespace :db do
  task :clean do
    puts 'Cleaning data...'
  end

  task :seed => :clean do
    puts 'Seeding data...'
  end
end

Earlier in this chapter, we defined the default rake task. To be honest, we did it just to understand what happens on running rake without arguments and to introduce Rake in a few steps giving as less information as possible in an interactive way. However, in the practical word, nobody defines the default rake task with an action. Setting dependencies is a convenient feature. It allows the default task to refer to some other task as many times as you want without regression. For example, today, the default task runs a doc:generate task but tomorrow, we decide to run a test:run task instead. In such a situation, we can just change the prerequisite and that's it. So, always define your default rake task with the following template:

task :default => :some_task

It's also possible to pass many prerequisites for a task. The following line of code is an example of how to do this:

task :task1 => [:task2, :task3]

Multiple tasks definitions

A task might be specified more than once. Each specification adds its dependencies and implementation to the existing definition. This allows one part of a Rakefile to specify the actions and a different Rakefile (perhaps a separately generated one) to specify the dependencies.

For example, take a look a Rakefile that contains the following code:

task :name => [:prereq1, :prereq2] do
  # action
end

It can be rewritten as the following code:

task :name
task :name => [:prereq1]
task :name => [:prereq2]
task :name do
  # action
end

Passing arguments to the tasks

Assume that you have a rake task that sets the title for our blog and you want to pass it from the command line; this should be optional. If you don't pass the title of the blog, the default title should be set.

We have two solutions to solve this problem. The first solution is to pass parameters through the environment variable that is passed into the ENV variable in Ruby code (ENV is a hash-like accessor for environment variables, and it is available in any Ruby program). The second solution is using the built-in Rake syntax—you just pass variables to each task through square braces. The first use case doesn't allow you to pass variables for each task in isolation. The variables are shared among all the tasks in the Rakefile. So, the preferable style is the second choice. However, we are shown two alternatives, which will be discussed in the next sections.

The first alternative

The first alternative is a case where we pass variables using environment variables. The following code represents a Rakefile:

task :set_title do
  title = ENV['TITLE'] || 'Blog'
  puts "Setting the title: #{title}"
end

The following code is a usage example:

$ rake set_title TITLE='My Blog'
Setting the title: My Blog
$ rake set_title # default title should be set in this case
Setting the title: Blog

In the preceding example, the ENV variable approach can be used without any caution. The following code snippet represents the collision in sharing the variable between the tasks. Check the following Rakefile:

task :task1 do
  puts "#{ENV['TITLE']} in task1"
end

task :task2 do
  puts "#{ENV['TITLE']} in task2"
end

The following code is an example of usage:

$ rake task1 task2 TITLE='test'
test in task1
test in task2

You can see that the TITLE variable is accessible in both the tasks and is the same. Sometimes, you don't want to get this behavior and you need to pass the variables to each task individually.

A variable declared within a rake command will not persist in the environment. The following terminal output will confirm this statement:

$ export TITLE='Default Title'
$ rake set_title TITLE='My Blog'
Setting the title: My Blog
$ echo $TITLE
Default Title
The second variant

The second variant has a built-in Rake feature. The following is the Rakefile code:

task :set_title, [:title] do |t, args|
  args.with_defaults(:title => 'Blog')
  puts "Setting title: #{args.title}"
end

Note

Please ignore the t variable at this moment; you will see what it means and what its usages are in Chapter 2, Working with Files.

Look at args, which is a hash-like object of the Rake::TasksArguments class. It has a useful method that is used here, named with_defaults, to merge the given arguments from the command line and the default values. If you don't pass the variables through the command line, the default variable for the title will be set.

The following code depicts how it may be used:

$ rake "set_title[My Blog]"
Setting title: My Blog
$ rake set_title
Setting title: Blog

Here, to pass the argument as a string with space (My Blog), I have enclosed the rake task with the argument within quotes. It's not the only case where I have to enclose the task name within double quotes. There are some terminals that don't understand the squared parentheses in the command line and should escape them with \ at the end of the code line of the rake task that is enclosed within the double quotes.

You are also able to pass multiple arguments to the rake task by separating them with a comma, as shown in the following line of command:

$ rake "name[Andrey,Koleshko]"

The task declaration for the preceding task is as follows:

task :name, [:first_name, :last_name] do |t, args|
  puts "First name is #{args.first_name}"
  puts "Last  name is #{args.last_name}"
end

Finally, you are able to pass variable-length parameters to the task with a comma, as we did in the previous example. In this case, you may use the extras method on the given args variable:

task :email, [:message] do |t, args|
  puts "Message: #{args.message}"
  puts "Recipients: #{args.extras}"
  puts "All variables: #{args.to_a}"
end

In the following example, the first argument will be assigned to the message variable on the args variable and the remaining arguments will go to the extras method. If you want to have an array that passes all the variables including the one associated with the message variable, you can call the to_a method on the args variable, as demonstrated in the preceding Rakefile.

$ rake "email[Hello Rake, [email protected], [email protected]]"
Message: Hello Rake
Recipients: ["[email protected]", "[email protected]"]
All variables: ["Hello Rake", "[email protected]", "[email protected]"]