📜 ⬆️ ⬇️

Rake tutorial

Rake is a tool for automating the assembly of software code written in Ruby, similar to tools like make, Ant or Phing. Although between them there is a huge difference. Unlike other tools, Rake does not provide external DSL (for example, an XML assembly file in Ant). Instead, all tasks are described in pure Ruby. This way you get full flexibility and can use the useful features of Ruby.

What are build tools?

If you have ever tried to install software from source codes on a Linux or Unix system, there is a high probability that you have to deal with make. The installation process usually looks the same. First you go to the directory with already unpacked source codes, then enter the following commands:

./configure
make
make install

')
The second and third lines are just a call to the make program. First of all, when running, make looks for a Makefile. It contains information about source codes and dependencies between them. make sorts the topological dependencies and tries to solve them in the proper order. It looks like this: first, the developer indicates the dependencies, and the build tool is responsible for processing them. make also saves time. If the source code has not changed since the last compilation, it will not be processed again, as this will be a complete loss of time. Build tools can be used not only to compile code, although this is their main task. In general, build tools are used to automate tedious and repetitive tasks.

Differences between Rake and the rest of the build tools.

As I said, there is one significant difference between Rake and other tools for building. Instead of writing a Makefile for make and build.xml for Ant and Phing, you simply write Ruby code. You will not have to master the syntax of new build tools if you decide to replace one tool with another.
But theory is not enough, let's move on to practice.

Install Rake

Installing rake is easy enough, provided that you have Ruby gems on your computer. To install rake, enter the following commands:

gem install rake


In most cases, you may need administrator privileges, so either go to the administrator username or use the sudo prefix.

sudo gem install rake


After the rake gem is installed, we can write our first example.

First Rake Example

The easiest way to define a Rake task is to write the following Ruby code:

task :default do
puts "Hello World!"
end


Rake tasks should always be in a file named Rakefile, Rakefile, rakefile.rb, or Rakefile.rb. The first two forms are used most often. After the Rakefile is saved, go to the folder with this file and run the following command:

$ rake
(in /home/lukasz/ruby/rake_examples)
Hello World!


The first rake task works fine.

So what really happened? When receiving our Rakefile, Rake looks for tasks in it that are simply calls to the task method. There can be many tasks in one Rakefile. When you run the file, you can transfer the name of the task you want to perform. If the task is not transferred, rake searches for the default task. That is why our Rake call did its job without querying for any additional parameters.

Let's try adding many tasks to one Rakefile:

task :ring do
puts "Bell is ringing."
end

task :enter do
puts "Entering home!"
end


If we try to run the rake command without any parameters, we get an error:

$ rake
(in /home/lukasz/ruby/rake_examples)
rake aborted!
Don't know how to build task 'default'

(See full trace by running task with --trace)


There is no default task in this file, so we must explicitly give them the name of the task:

$ rake enter
(in /home/lukasz/rake_examples)
Entering home!
$ rake ring
(in /home/lukasz/rake_examples)
Bell is ringing.


At first glance, our example works fine, but still an error has crept into the code, namely, we cannot enter the house without ringing the door. This is where the dependencies begin.

Add dependencies

Let's modify our file a bit:

task :ring do
puts "Bell is ringing."
end

task :enter => :ring do
puts "Entering home!"
end


Now, when you want to enter the house, the doorbell will first ring:

$ rake enter
(in /home/lukasz/ruby/rake_examples)
Bell is ringing.
Entering home!


Now Rake is responsible for the doorbell before entering. You can declare more complex dependencies and Rake will be responsible for solving them. You just specify everything you want and rake does all the tedious work for you.

The good news is that the dependency can be indicated not only when defining the task, but also later, depending on the fulfillment of the conditions of time. After all, we write tasks in the Ruby programming language, not a static XML file, remember?

To achieve the same effect with the doorbell, we can write:

task :ring do
puts "Bell is ringing."
end

task :enter do
puts "Entering home!"
end

task :enter => :ring


And the effect will be the same.

Description of the task.

Each task you write can be described with a few simple words. The description will serve you not only as a built-in comment, but also appear in the list of available tasks. Let's add descriptions:

desc 'Ring the bell'
task :ring do
puts "Bell is ringing."
end

desc 'Enter home'
task :enter => :ring do
puts "Entering home!"
end


To see the list of available tasks, run rake with the -T or --tasks option:

$ rake -T
(in /home/lukasz/ruby/rake_examples)
rake enter # Enter home
rake ring # Ring the bell


As I said, the build tools were made to simplify the compilation of the project. There's a lot
dependencies between individual files and rake, as well as many build tools, support this. This allows you to define a special type of tasks -a file task:

file 'products.sql' => 'products.xml' do
# build SQL INSERT clause and save it in products.sql file,
# basing on products.xml datafile
end


File task - in general - no different from regular tasks. The fact is that it will not work if the input file (products.xml in this case) does not exist. It will also not work if the result file (products.sql) is not older than the input file. If this behavior does not suit you, then you need to overwrite the output file each time you start a task, use regular tasks.

Fileutils


Rake includes a Fileutil module that provides many Unix-like methods, including mkdir, rmdir, cp, chmod, and touch.
Since the Fileutils module is already enabled, you can call these methods directly, without using operator frames.

task :manipulate_files do
mkdir 'new_dir'
mv 'new_dir', 'lukasz'
chmod 0777, 'lukasz'
touch 'lukasz/wrobel.txt'
rm_rf 'lukasz'
end


If you are familiar with the Linux / Unix command shell, you will learn this module in a very short time.
By the way, remember the problem files? If the output file is not older than the input file, the task file will not work. In case you want to perform such a check in regular tasks, you can use the Fileutils method, which is called uptodate.

task :check do
# ...

unless uptodate?(output_file, input_file)
# regenerate output_file
end
end


Filelist

Imagine a task file where many input files are combined to get a single output file. The most obvious way to determine the dependencies between files is:

one_file_to_rule_them_all = 'database.sql'
tables_sql = ['orders.sql', 'payments.sql', 'categories.sql']

file one_file_to_rule_them_all => tables_sql


This will work, but what if we create another SQL input file? We must remember to add it to our list.

I do not know about you, but I'm a little confused. As already mentioned, build tools have been developed to automate boring and repetitive tasks. And adding files to our list is a boring task. Fortunately, the author Rake also knew about it.

There is a FileList class that can be useful in such situations. Let's use it now:

one_file_to_rule_them_all = 'database.sql'

FileList['*.sql'].each {|table| file one_file_to_rule_them_all => table}


Forget about adding each individual SQL file to the list. Rake will do it for you.

annotation

There are a huge number of Rake functions that were not covered in this explanation, for example, clean, clobber, rdoc and gem tasks, pathmap, rules and namespaces. You will have a chance to find out about them later.
I hope this article will be a good starting point to get an idea about Rake. Rake has proven its worth and is now widely used in the Ruby world, so writing Rake tasks is an essential skill. Good luck in your own experiments with Rake.

PS The original article can be read here.

Source: https://habr.com/ru/post/111331/


All Articles