Search code examples
rubyrakecapistranometaprogramming

Rake metaprogramming: How to create multiple tasks from list


Actually something I want for a Capistrano script (which is rake-based).

How do I convert several tasks like this:

desc 'Runs rake db:seed'
task :seed do
  on roles :db do
    within release_path do
      with rails_env: fetch(:rails_env) do
        execute :rake, "db:seed"
      end
    end
  end
end

Into something like this:

task_list = %i(
  db:seed
  db:reset
  db:migrate
  db:seed:testusers
  db:seed:testorders
)

task_list.each do |task_name|
  desc %(Runs rake #{task_name})
  task :task_name do
    on roles :db do
      within release_path do
        with rails_env: fetch(:rails_env) do
          execute :rake, task_name
        end
      end
    end
  end

end

My problem being that the task_name is being used as a key for an environment setting in the task definition.

How can I define multiple tasks this way?


Solution

  • How about:

    task_list = %i(
      db:seed
      db:reset
      db:migrate
      db:seed:testusers
      db:seed:testorders
    )
    
    task_list.each do |task_name|
      desc %(Runs rake #{task_name})
      task {task_name => [:set_rails_env]} do
        on primary fetch(:migration_role) do
          within release_path do
            with rails_env: fetch(:rails_env) do
              execute :rake, task_name
            end
          end
        end
      end
    end
    

    Edit: Seeing that you changed the signature from task_name: [:dependency] to the simpler task_name, you would have to do:

    task_list.each do |task_name|
      desc %(Runs rake #{task_name})
      task task_name do
        ...
      end
    end
    

    The reason for the above is that task_name: :foo is syntactic sugar for :task_name => :foo. Since you want your key to be dynamically evaluated, you change the hash to read task_name => :foo, where task_name is a variable holding a symbol.

    In other words - You don't want your task to be called literally task_name - You want it to be called that which your variable task_name contains.