Report abuse


			
# 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