@@ -0,0 +1,308 @@
# 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
# -----------------------------------------------------------------------------