Rake and arguments for tasks

Rake is beautiful tool, helping automate many tasks using Ruby. When You want to pass some arguments You can add VAR=value on command line and then in task use ENV['VAR'] to access passed value. But it is not what You alway want. Sometimes You want more compact and clean way to pass arguments.

Starting with Rake 0.8.0 You can create tasks with arguments:

task :name, [:first_name, :last_name] do |t, args|
     args.with_defaults(:first_name => "John", :last_name => "Dough")
     puts "First name is #{args.first_name}"
     puts "Last  name is #{args.last_name}"
end

Now You can pass some arguments:

C:\>rake name
(in C:/)
First name is John
Last  name is Dough

C:\>rake name[Jim,Weirich]
(in C:/)
First name is Jim
Last  name is Weirich

Cool. I guess I don’t need to explain how arguments and setting default values does work?

However I have noticed some error. First documentation skip needed key in example when task have some dependency on other task (:needs) and argument names should be provided not as an array (for task without dependencies both array and list form are working). Here is example of task with two arguments and one dependency, which does work (I’m using Rake 0.8.3):

task :name, :first_name, :last_name, :needs => [:other] do |t, args|
     args.with_defaults(:first_name => "John", :last_name => "Dough")
     puts "First name is #{args.first_name}"
     puts "Last  name is #{args.last_name}"
   end

task :other  do
end

What You can do with args?

Here it is modified task from Chad Fowlers Rails Recipes to dump data from database to fixtures. Handy to populate fixtures with some data entered with WWW interface:

desc 'Create YAML test fixtures from data in an existing database.
Defaults to development database. Set RAILS_ENV to override. Use args
table and limit to dump one table and limit number of records'
task :extract_fixtures, :table, :limit, :needs => :environment do |t, args|
  args.with_defaults(:table => nil, :limit => nil)
  limit = args.limit.nil? ? "" : "LIMIT #{args.limit}"
  sql = "SELECT * FROM %s #{limit}"
  skip_tables = ["schema_info" ]
  if args.table.nil?
     tables = ActiveRecord::Base.connection.tables - skip_tables
  else
    tables = [ "#{args.table}"]
  end

  ActiveRecord::Base.establish_connection
  tables.each do |table_name|
    i = "000"
    File.open("#{RAILS_ROOT}/test/fixtures/#{table_name}.yml" , 'w' ) do |file|
      data = ActiveRecord::Base.connection.select_all(sql % table_name)
      file.write data.inject({}) { |hash, record|
        hash["#{table_name}_#{i.succ!}" ] = record
        hash
      }.to_yaml
    end
  end
end

You can dump all fixtures or only single table and limit it to first X entries. I find it useful recipe, I hope it can be used by someone else, too.

Join the Conversation

12 Comments

  1. Thank you very much for this article! As a newbie, it gave me lots of insights.

    Maybe the following info saves some time for other n00bs like me:
    “rake extract_fixtures ‘mymodel'” gives:
    “Don’t know how to build task ‘mymodel'”.

    I think it should be called:
    “rake extract_fixtures[‘mymodel’]”

  2. Thanks. The :needs element was the key to understanding the new syntax. Other references show it differently and that does not work with the new args syntax.

  3. Just wanted to say thanks for this.
    I found the post extremely helpfull whilst creating some rake tasks that needed arguments passing to them.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.