Rake

Is a build tool, like Make, written in Ruby and using Ruby as a build language.

  • Let you define tasks
  • Tasks can depend on other tasks
  • Tasks are only run if needed.
  • Tasks are only run once.

Task

  • Create a file.
  • Populate a DB from a CSV, XML file.
  • Dump DB to a file.
  • Automation. Something you do a lot.
  • See Rails for some great examples of Tasks.
Basics

First we will use Rake in an empty directory. Just to see how we can use rake outside of Rails.

  • Install rake. Can't imagine you don't already have it. gem install rake

  • Create a directory 'RakeStuff' and cd to that directory.

  • Create a file 'Rakefile'. Add the below code to that Rakefile.

  • Create a hello task using the task keyword/method.

     task :default do
       puts "say something"
     end
    
  • Run Task.
    $ rake hello

  • Show all tasks.
    $ rake -T or $ rake -D or $ rake -P

  • Show where a rake tasks is implemented.
    rake -W

  • Create another hello task with another action and run it.

     task :hello do
       puts "Hello from my first rake task"
    	end
    

    When running $rake hello this just gives the hello task another action.

  • Document the task.
    Use the desc keyword/method. Add 'desc "Some descriptive text" directly above the task.

     desc "Just say Hello"
     task :hello do
       puts "Hello from my first rake task"
     end
    

    $rake hello $rake -D hello

Namespaces

To avoid name collisions with other rake tasks, probably defined in gems or libraries. Use the namespace keywork/method.

Yes, namespaces can be nested.

namespace :rack_demo do
  namespace :simple do
    task :default do
      puts "say something"
    end
...
  end
end
Dependencies

Rake is very good at running tasks that depend on other tasks.

  • Create a set of tasks to bake a cake, in rakelib/cake.rake.
namespace :cake do

  desc "Bake a Cake"
  task :bake => [:mix_up, :go_to_store] do
    puts "Cake is baked"
  end

  task :mix_up => [:add_flower, :add_eggs] do
    puts "Mix up ingredients"
  end

  task :add_flower => :get_flower do
    puts "Adding flower"
  end

  task :add_eggs => :go_to_store do
    puts "Adding Eggs"
  end

  task :get_flower => [:go_to_store] do
  puts "Get Flower"
  end

  task :go_to_store do
    puts "Go to Store"
  end
end
	

Run this bake task.
$ rake cake:bake

Notice how the output.

Go to Store
Get Flower
Adding flower
Adding Eggs
Mix up ingredients
Cake is baked

This will create a dependency tree where the bake task depends on the mix_up task which depends on the add_flower and add_eggs tasks.

The add_flower task depends on the get_flower task which depends on the got_to_store task.

The add_eggs tasks just depends on the go_to_store task.

Notice how we do NOT invoke dependencies twice! Even when they are explicity added as a dependency.

Rake knows not to include a dependency that has already been met.

Running Unix commands

We can invoke Unix commands from within a rake task.

Add this to rakelib/env.rb.

namespace :rake_demo do

  task :show_env do
    sh 'env'
  end
end

rake rake_demo:show_env

Passing arguments to Rake and environment.
  • Show Unix Environment Variables.
    $ env

    Notice the RUBY_VERSION.

  • Access a Environment Variable in rake.

$ export RAILS_ENV='development'
$ rake rake_demo:do_it

... 
 desc "Pass an argument to rake"
  task :do_it do
    puts "Doing it in with the rails environment set to #{ENV['RAILS_ENV']}"
  end
...

Unset the environment variable and pass it directly as an argument.

$ unset RAILS_ENV
$ rake rake_demo:do_it RAILS_ENV='foo'

Rake in Rails.

Move all these *.rake files to a Rails app. This app.

Rails will look for all rake tasks in it's lib/tasks directory.

Add this task to the env.rake file.

 desc "Pass an argument to rake"
  task :show_users => [:environment] do
    names = User.all.map(&:name)
    puts "User names are #{names.join(', ')}"
  end