Skip to content

Instantly share code, notes, and snippets.

@noonat
Created January 20, 2012 21:02
Show Gist options
  • Save noonat/1649543 to your computer and use it in GitHub Desktop.
Save noonat/1649543 to your computer and use it in GitHub Desktop.
Rake Quick Reference
# Rake Quick Reference
# by Greg Houston
# http://ghouston.blogspot.com/2008/07/rake-quick-reference.html
# -----------------------------------------------------------------------------
# Running Rake
# -----------------------------------------------------------------------------
# running rake from the command-line:
# rake --help
# --help shows all the command-line options, a few are listed here.
# rake
# (no arguments, runs the default task)
# rake uses the script: rakefile, Rakefile, rakefile.rb or Rakefile.rb
# rake will search parent directories for the file.
# rake -f build.rb
# -f specifies the rakefile file to run
# rake target target2
# target and target2 are the names of the tasks to run (instead of default)
# rake -n
# -n shows a dry-run of which tasks would get called
# rake -T
# -T shows all task which have descriptions
# rake -P
# -P shows task dependencies
# -----------------------------------------------------------------------------
# Tasks
# -----------------------------------------------------------------------------
task :default => :target
# defines a task named :default
# rake will run :default when no other task is specified on the command line
# => :target, makes the task named :target a prerequisite
# rake will ensure prerequisite tasks have completed before invoking this task
task :target => :source
# defines a task named :target with prerequisite :source
# e.g. rake will ensure :source is invoked before :target
task :source => [:x, :y]
# defines a task named :source
# => [:x, :y] shows how to set multiple prerequisites
# all prerequisites must complete before this task will execute
# right now we have defined a chain of prerequisites
# :default => :target => :source => [:x, :y]
# invoking :default will first invoke :x, :y, :source, :target
task :a => :b
task :b => :a
# rake will raise an error if you invoke tasks with circular dependencies:
# Circular dependency detected: TOP => a => b => a
task :hello_world do
puts 'hello world!'
end
# task behavior is given as a block of code using "do ... end"
# dont use ruby's { } block syntax, precedence rules will break it
# when the task is invoked, the block of code is executed
task :target => :z do
# ruby code
end
# since :target is already defined
# +adds+ the prerequisite :z
# +adds+ code to execute when :target is invoked
# tasks in rake have a collection of dependencies
# and a collection of blocks to execute
task :target2 => :source
# defines :target2 which also depends on :source
# rake will only invoke :source once, even if both
# :target and :target2 are invoked
# tasks are only invoked once!
task :example_target do
puts Rake::Task[:target].inspect
# Rake::Task holds a collection of all tasks. Access a task using: [name]
puts Rake::Task[:target].investigation
# investigation displays some details about a task.
# useful for figuring out why a task was called or not.
end
task :target do |t|
puts t.name #=> target
puts t.class #=> Rake::Task
end
# task code blocks can accept an option argument (t in this example)
# which is a reference to the task object.
task :call_invoke do
Rake::Task[:target].invoke
end
# calling invoke on a task directly (not recommended).
# :target is only run once, even if invoke is called many times.
# calling invoke will execute the prerequisites of :target
task :call_execute do
Rake::Task[:target].execute( nil )
end
# execute the task directly (not recommended).
# execute can run :target many times.
# calling execute will +not+ execute prerequisites.
task :example_failure do
raise 'i do not like green eggs and ham!'
end
# raising an exception is a good way to exit rake with a detailed error message
# most continuous integration tools will detect the failure
task :copy, :source, :target, :needs => :other_task do |t, args|
puts "copy #{args.source} to #{args.target}"
# args[:source] also works
end
# rake 0.8 adds support for task arguments
#
# task named :copy with arguments :source and :target, depends on :other_task
# t = task object
# args = arguments (instance of Rake::TaskArguments)
#
# command-line usage:
# rake copy[file1,file2]
# rake "copy[path with spaces/file1,file2]"
#
# rakefile usage:
# none (as of rake v0.8.1)
# calling .invoke and .execute is possible (not recommended)
task :copy_some_files do
cp 'one_file', 'destination'
cp 'another_file', 'destination', :verbose => true
end
# rake includes the FileUtils module which has many
# file system manipulation methods. FileUtils#cp copies a file.
# see http://www.ruby-doc.org/core/classes/FileUtils.html
# rake wraps FileUtils in Rake::FileUtils to add the :verbose option
task :additional_commands do
ruby 'my_ruby_script.rb' # run a ruby interpreter
sh 'build.bat' # run a shell command
safe_ln 'fileone.txt', 'filetwo.txt' # link or copy (as supported by OS)
split_all("a/b/c") #=> ['a', 'b', 'c'] (split directory into an array)
end
# rake adds a few new commands
# see http://rake.rubyforge.org/classes/FileUtils.html
multitask :c_and_d_in_parallel => [:c, :d]
# using multitask, immediate prerequisites are invoked on separate threads
# -----------------------------------------------------------------------------
# File and Directory Tasks
# -----------------------------------------------------------------------------
directory 'tests/out'
# defines a directory task named 'tests/out' which will
# create the 'tests/out' directory if it doesn't
# already exist.
file 'path/target.txt' => 'path/source.txt' do
cp 'path/source.txt', 'path/target.txt'
end
# defines a file task named 'path/target.txt' which will
# get invoked if the file 'path/source.txt' is newer.
# file tasks look at the timestamp of the prerequisites
def copy_file( source_file, target_file, task_symbol )
desc "cp from #{source_file}"
file target_file => [source_file] do |t|
cp source_file, target_file, :verbose => true
end
task task_symbol => target_file
end
# example of a method which creates tasks.
# copy_file makes a file task to copy the source_file to target_file
# copy_file make task named task_symbol to depend on the target_file
#
# usage:
copy_file( 'path/foo.txt', 'path/foobar.txt', :copy_foo )
# -----------------------------------------------------------------------------
# FileList
# -----------------------------------------------------------------------------
FileList['data/**/*', 'out/non-existing-file.txt']
# rake FileList can glob files from the disk,
# and/or collect files that dont exist.
# FileList globs are lazy, they are resolved when first used.
FileList['data/**/*'].exclude('*.txt')
# .exclude globs
# resolves against the file system, e.g. wont match files that don't exist
FileList['data/**/*'].exclude {|path| path =~ /delete_me/ }
# .exclude can use block to exclude everything where the block returns true.
# example: exclude files when path matches the regular expression /delete_me/
# FileList contains many other useful methods.
# see http://rake.rubyforge.org/classes/Rake/FileList.html
FileList['data/*'].each do |source|
target = source.sub('data', 'out')
file target => source do
cp source, target, :verbose => true
end
desc "copies all data files"
task :copy_data_files => target
end
# example using FileList to create tasks to perform a copy
file 'target.txt' => 'source.txt' do |f|
cp f.prerequisites[0], f.name, :verbose => true
end
# file tasks blocks can access the task object
# f.prerequisites[0] is 'source.txt'
# f.name is 'target.txt'
# -----------------------------------------------------------------------------
# String extensions
# -----------------------------------------------------------------------------
# Rake adds methods to String...
# see http://rake.rubyforge.org/classes/String.html
#
'path/file.txt'.ext( 'html') #=> path/file.html (replace extension)
'path/file.txt'.pathmap('%p') #=> 'path/file.txt' (full path)
'path/file.txt'.pathmap('%f') #=> 'file.txt' (file)
'path/file.txt'.pathmap('%n') #=> 'file' (file name, no ext)
'path/file.txt'.pathmap('%x') #=> '.txt' (file extension)
'path/file.txt'.pathmap('%X') #=> 'path/file' (full path, no extension)
'x/y/z/file.txt'.pathmap('%d') #=> 'x/y/z' (directory path)
'x/y/z/file.txt'.pathmap('%2d') #=> 'x/y' (directory path depth 2)
'x/y/z/file.txt'.pathmap('%-2d') #=> 'y/z' (directory path depth 2 from end)
'x/y/z/file.txt'.pathmap('%d%s%f') #=> 'x/y/z\file.txt' (%s = alt separator)
'x/y/z/file.txt'.gsub('/','\\') #=> 'x\y\z\file.txt' (gsub works better)
''.pathmap('%%') #=> '%' (percent sign)
'a/b/c'.pathmap('%{a,apple}p') #=> 'apple/b/c' use {} to replace using regex
'a/b/c'.pathmap('%{a,x;b,y}p') #=> 'x/y/c' use {;} to replace multiple patterns
'a/b/c'.pathmap('%{a,*}p') {|m| "(#{m})"} #=> '(a)/b/c' * calls block for match
# -----------------------------------------------------------------------------
# Namespace
# -----------------------------------------------------------------------------
namespace :ns do
task :target
end
task :default => "ns:target"
# defines a namespace named :ns
# defines a task named "ns:target"
# sets "ns:target" as a prerequisite of :default
# use namespace to organize code and avoid task name conflicts
namespace :ns do
task :alpha => :beta
task :beta
end
# within a namespace, you can refer to another task in the namespace directly
# you dont need
# task :alpha => 'ns:beta'
task :dog
task :farmer
namespace :animal do
task :cat => :dog
task :dog => :farmer
end
# namespaces will look for tasks within their own namespace
# animal:cat's prerequisite is animal:dog, not :dog
# i dont know of a way to reference :dog instead of animal:dog inside
# the namespace block. animal:dog hides :dog!
# animal:dog's prerequisite is :farmer (outer scope) since there isn't
# an animal:farmer defined.
task 'animal:cow' => :dog
# animal:cow is defined outside the namespace block
# animal:cow's prerequisite is :dog, not animal:dog
# animal:cow will look for prerequisites in the outer scope
# animal:cow will not automatically look for tasks in the animal namespace
namespace :animal do
task :calf => :cow
end
# animal:calf's prerequisite is the 'animal:cow' defined above. as expected.
namespace :demo do
file 'out/demo.txt' => ['in/demo.txt', :hello]
task :hello
end
# file task name is only 'out/demo.txt', the namespace doesn't change the name
# however the scope lookup applies, 'out/demo.txt' prereq is demo:hello
# -----------------------------------------------------------------------------
# Rules
# -----------------------------------------------------------------------------
rule /out\/.*\.txt/ => proc {|t| t.pathmap('data/%n.txt')} do |t|
cp t.source, t.name
end
task :use_rule => 'out/some_file.txt'
# see the rake documentation and tutorials for rules.
# rake allows defining rules, they describe how to generate a file from another
# in practice, i've found rules can get hard to read
# instead i generate tasks using a FileList (more readable)...
FileList.new('data/*.txt').each do |f|
target = f.pathmap('out/%f')
file target => f do
cp f, target, :verbose => true
end
task :use_rule => target
end
# -----------------------------------------------------------------------------
# Clean and Clobber
# -----------------------------------------------------------------------------
require 'rake/clean'
# creates two tasks: :clean and :clobber
# :clean is used to remove temporary files
# :clobber is used to remove all generated files
# also creates two constants: CLEAN and CLOBBER
# they are FileLists of files to remove
# :clean is a prerequisite of :clobber
# examples:
CLEAN << 'file_to_remove.txt'
CLEAN.include( '*_to_remove.txt' )
CLEAN.add( 'delete_me.txt' )
CLEAN.exclude( 'dont_remove.txt' )
# -----------------------------------------------------------------------------
# Import and Libraries
# -----------------------------------------------------------------------------
# rakefile usage:
# import 'more_tasks.rb'
# import is like require, except it loads +after+ the current file is finished.
# the rake command-line can specify a library folder (default is rakelib)
# rake -R=another_rakelib
# rake will automatically +import+ all *.rake files found in the directory
# -----------------------------------------------------------------------------
# Task Generation
# -----------------------------------------------------------------------------
# Sometimes you want to create a bunch of similar tasks. Task Generators
# are classes that create tasks.
#
# For example, building rdoc documentation from ruby source code may
# involve three tasks:
# rake rdoc # build rdoc
# rake clobber_rdoc # remove rdoc output
# rake rerdoc # force a rebuild of rdoc
#
# Rake provides a class which creates these tasks from a single call:
# see http://rake.rubyforge.org/classes/Rake/RDocTask.html
require 'rake/rdoctask'
Rake::RDocTask.new do |rd|
rd.main = "README.rdoc"
rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
end
# Rake::TestTask is another task generator, for running ruby unit tests
# tasks: test (has several command-line options)
# see http://rake.rubyforge.org/classes/Rake/TestTask.html
require 'rake/testtask'
Rake::TestTask.new do |t|
t.libs << "test"
t.test_files = FileList['test/test*.rb']
t.verbose = true
end
# Rake::GemPackageTask is another task generator, for packaging gems
# tasks: "package_dir/name-version.gem"
# see http://rake.rubyforge.org/classes/Rake/GemPackageTask.html
require 'rubygems'
spec = Gem::Specification.new do |s|
s.name = 'mygem'
s.version = '0.1'
# ...etc ...
end
require 'rake/gempackagetask'
Rake::GemPackageTask.new(spec) do |package|
package.need_zip = true
end
# Writting your own Task Generator is easy to develop.
# For example, GetPastie will create a task to download a pastie:
require 'rake/tasklib'
class GetPastie < Rake::TaskLib
attr_accessor :name, :id, :target
# initialize sets the name and calls a block to get
# the rest of the options
def initialize( name=:get_pastie )
@name = name
yield self if block_given?
define
end
# define creates the new task(s)
def define
raise "id must be defined" if @id.nil?
raise "target must be defined" if @target.nil?
require 'open-uri'
desc "download http://pastie.org/pastes/#{@id} to #{target}"
task @name do
open(@target,"w").write(open("http://pastie.org/pastes/#{@id}/download").read)
end
end
end
# creates the task :rake_quick_ref
GetPastie.new( :rake_quick_ref ) do |t|
t.id = 239387 # the first quick ref published
t.target = 'out/pastie_239387.rb'
end
# -----------------------------------------------------------------------------
# Tips
# -----------------------------------------------------------------------------
# tracing is turned on using the command-line -t flag
# rake -t
# or within the rake file...
Rake.application.options.trace = true
# name=value pairs given at the end of the command-line are accessible
# using the ENV hash
#
# for example:
# rake mytask CONFIG=DEBUG
task :show_config do
puts ENV['CONFIG'] #=> DEBUG
end
# for and example of combining command-line args with configuration options
# see Rake::TestTask
task :x # referenced above
task :y
task :z
@Frydac
Copy link

Frydac commented Jun 11, 2016

Thx, this seems like a pretty handy resource.

However, I can't get a task with arguments and depending on another task to work like you describe.
For example:

task :t1 do
    puts 't1'
end

task :t2, :arg1 do |t, args|
    Rake::Task[:t1].invoke
    puts 't2', args[:arg1]
end

task :t3, :arg1 => :t1 do |t, args|
    puts 't3', args[:arg1]
end

I can only get it to work with an explicit call to invoke as in t2, not with the hash like definition in t3 like you seem to suggest in your reference. Am I missing something?
Using rake, version 10.4.2.

EDIT: got it to work by specifying the argument as an array:

task :t3, [:arg1] => :t1 do |t, args|
    puts 't3', args[:arg1]
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment