1201

I have a rake task that needs to insert a value into multiple databases.

I'd like to pass this value into the rake task from the command line, or from another rake task.

How can I do this?

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Tilendor
  • 48,165
  • 17
  • 52
  • 58

21 Answers21

1184

You can specify formal arguments in rake by adding symbol arguments to the task call. For example:

require 'rake'

task :my_task, [:arg1, :arg2] do |t, args|
  puts "Args were: #{args} of class #{args.class}"
  puts "arg1 was: '#{args[:arg1]}' of class #{args[:arg1].class}"
  puts "arg2 was: '#{args[:arg2]}' of class #{args[:arg2].class}"
end

task :invoke_my_task do
  Rake.application.invoke_task("my_task[1, 2]")
end

# or if you prefer this syntax...
task :invoke_my_task_2 do
  Rake::Task[:my_task].invoke(3, 4)
end

# a task with prerequisites passes its 
# arguments to it prerequisites
task :with_prerequisite, [:arg1, :arg2] => :my_task #<- name of prerequisite task

# to specify default values, 
# we take advantage of args being a Rake::TaskArguments object
task :with_defaults, :arg1, :arg2 do |t, args|
  args.with_defaults(:arg1 => :default_1, :arg2 => :default_2)
  puts "Args with defaults were: #{args}"
end

Then, from the command line:

> rake my_task[1,false]
Args were: {:arg1=>"1", :arg2=>"false"} of class Rake::TaskArguments
arg1 was: '1' of class String
arg2 was: 'false' of class String

> rake "my_task[1, 2]"
Args were: {:arg1=>"1", :arg2=>"2"}

> rake invoke_my_task
Args were: {:arg1=>"1", :arg2=>"2"}

> rake invoke_my_task_2
Args were: {:arg1=>3, :arg2=>4}

> rake with_prerequisite[5,6]
Args were: {:arg1=>"5", :arg2=>"6"}

> rake with_defaults
Args with defaults were: {:arg1=>:default_1, :arg2=>:default_2}

> rake with_defaults['x','y']
Args with defaults were: {:arg1=>"x", :arg2=>"y"}

As demonstrated in the second example, if you want to use spaces, the quotes around the target name are necessary to keep the shell from splitting up the arguments at the space.

Looking at the code in rake.rb, it appears that rake does not parse task strings to extract arguments for prerequisites, so you can't do task :t1 => "dep[1,2]". The only way to specify different arguments for a prerequisite would be to invoke it explicitly within the dependent task action, as in :invoke_my_task and :invoke_my_task_2.

Note that some shells (like zsh) require you to escape the brackets: rake my_task\['arg1'\]

davetron5000
  • 24,123
  • 11
  • 70
  • 98
Nick Desjardins
  • 12,814
  • 3
  • 18
  • 10
  • This doesn't tell me how to run the rake task with arguments from another task. It covers only command line usage – Tilendor May 06 '09 at 16:47
  • 5
    To invoke a task within a namespace simpy do: Rake::Task['namespace:task'].invoke – gaqzi Aug 07 '09 at 01:22
  • Actually amazed, I've looked for the answer to this so many times and it's always been rake task arg1=2 arg2=3. This is much simpler when the arguments are in series. – opsb Oct 21 '10 at 10:30
  • Thanks, I particularly needed to pass arguments to prerequisite task, your examples work perfectly. – Rob Jan 13 '11 at 15:24
  • @Rob, @Nick: "particularly needed to pass arguments to prerequisite task". I can't see an example explicitly passing parameters to prereq task.. Did I miss something? Is there a way to do this, rather than invoking? – inger Mar 22 '11 at 16:49
  • Is there a way to call a task more than one time in a row? I tried `5.times { Rake::Task[:my_task].invoke }` and it only worked for the first time. – igorsantos07 Aug 18 '11 at 04:23
  • 1
    That's a separate question, Igoru, but the reason your call to invoke only runs once is that rake is dependency-oriented, so it will only execute a task if it is needed. For generic tasks that means if it hasn't already run. To explicitly execute a task regardless of its dependencies or if it is needed, call execute instead of invoke. – Nick Desjardins Aug 18 '11 at 18:38
  • 12
    Note: According to rake, this syntax for accepting variables in tasks is deprecated: `WARNING: 'task :t, arg, :needs => [deps]' is deprecated. Please use 'task :t, [args] => [deps]' instead.` – Ajedi32 Aug 15 '12 at 21:25
  • 76
    Note that zsh fails to parse the command line arguments correctly (`zsh: no matches found: ...`), so you need to escape the brackets: `rake my_task\['arg1'\]`. From http://robots.thoughtbot.com/post/18129303042/how-to-use-arguments-in-a-rake-task – Seth Bro Jul 17 '13 at 14:46
  • 2
    @SethBro YES. If only your comment hadn't been hidden behind the "See more comments" link I wouldn't have wasted 10 minutes unable to make this work. – GMA Jan 08 '14 at 08:27
  • 1
    Add `alias rake='noglob rake'` in your `.zshrc` and forget escaping the brackets. – Roberto Feb 24 '16 at 01:46
  • valid syntax for current rails (5) is: `task :task_name, [:var1, :var2] => :environment do |t, vars|`. Inside task vars looks like: `{:var1 => val, :var2 => val}` – res Sep 07 '16 at 08:45
  • For completeness: a task cannot explicitly specify (or override) values for its dependent task's arguments. – William Entriken Mar 16 '17 at 16:25
  • 4
    NOTE: **Do not add a space between arguments.** Use `rake my_task[1,2]` instead of `rake my_task[1, 2]`. Otherwise you get the dreaded `Don't know how to build task 'my_task[1,'` error and you'll be scratching your head for longer than you'd like to admit. – Joshua Pinter May 07 '18 at 23:28
  • for your last example with defaults, is that a recursive call to `with_defaults` or does the task name and the method name just happen to the be same? – vlsd May 28 '21 at 16:06
  • What's the point of escaping `x` and `y` in `rake with_defaults['x','y']`? What `rake` gets is `with_defaults[x,y]` anyway. – x-yuri Jul 05 '21 at 17:00
466

Options and dependencies need to be inside arrays:

namespace :thing do
  desc "it does a thing"
  task :work, [:option, :foo, :bar] do |task, args|
    puts "work", args
  end
  
  task :another, [:option, :foo, :bar] do |task, args|
    puts "another #{args}"
    Rake::Task["thing:work"].invoke(args[:option], args[:foo], args[:bar])
    # or splat the args
    # Rake::Task["thing:work"].invoke(*args)
  end

end

Then

rake thing:work[1,2,3]
=> work: {:option=>"1", :foo=>"2", :bar=>"3"}

rake thing:another[1,2,3]
=> another {:option=>"1", :foo=>"2", :bar=>"3"}
=> work: {:option=>"1", :foo=>"2", :bar=>"3"}

NOTE: variable task is the task object, not very helpful unless you know/care about Rake internals.

RAILS NOTE:

If running the task from Rails, it's best to preload the environment by adding => [:environment] which is a way to setup dependent tasks.

  task :work, [:option, :foo, :bar] => [:environment] do |task, args|
    puts "work", args
  end
Sajad Torkamani
  • 544
  • 1
  • 7
  • 18
Blair Anderson
  • 19,463
  • 8
  • 77
  • 114
  • 41
    Also, make sure you don't use spaces between the arguments. E.g don't do this: `rake thing:work[1, 2, 3]` as it won't work and you'll get an error `Don't know how to build task` – rpbaltazar Sep 29 '16 at 11:30
  • 18
    Also, make sure you enclose the argument in string. e.g from your command line run the rake task like so `rake thing:work'[1,2,3]'` – theterminalguy Jan 14 '17 at 08:01
  • @DamianSimonPeter you do not need to use strings. can simply do `rake thing:workd[true,false,cheese]` the values will be strings! – Blair Anderson Feb 10 '17 at 21:21
  • 67
    Unfortuanely, zsh can not parse the call correctly, you need type the command on zsh like this: `rake thing:work\[1,2,3\]`, or this `rake 'thing:work[1,2,3]'` – hutusi Jul 27 '17 at 06:51
  • This failed for me with the error `Don't know how to build task 'environment' (see --tasks)` Nick Desjardins answer worked great. – sakurashinken Apr 16 '18 at 04:02
  • 2
    @sakurashinken you can remove the `:environment` symbol from your task. rails applications have an :environment task... – Blair Anderson Apr 16 '18 at 05:57
  • 5
    Instead of having a note to explain that `t` means `task`, why not just use `task` as the param name? – Joshua Pinter May 05 '18 at 19:43
  • @BlairAnderson Explicitness. I love it! :-) – Joshua Pinter May 11 '18 at 18:59
  • 1
    Rake tasks seem to have an almost nonsensical layout for name, dependencies, and arguments. The conclusion - while it works - is not something you could have arrived at intuitively. – user2490003 Apr 15 '19 at 19:47
  • This is such a counter intuitive setup for a task runner / system. It's neither easily readable or easily writeable – user2490003 Sep 03 '19 at 14:36
384

In addition to answer by kch (I didn't find how to leave a comment to that, sorry):

You don't have to specify variables as ENV variables before the rake command. You can just set them as usual command line parameters like that:

rake mytask var=foo

and access those from your rake file as ENV variables like such:

p ENV['var'] # => "foo"
timurb
  • 5,405
  • 2
  • 22
  • 17
  • 4
    This is the best simplest answer IMO. It worked right away. What exactly does the `p` mean? – stevec Jun 02 '19 at 04:37
  • 1
    @user5783745 Like puts but instead of logging value.to_s to standard out it calls Obj.inspect and logs that to standard out. http://ruby-doc.org/core-2.0.0/Kernel.html#method-i-p – kqcef Jun 03 '19 at 18:23
  • Rake is utterly overengineered mess and this is the only way which worked. And it's not just me, this answer has the same amount of votes as the "correct" answer. – lzap Jan 21 '20 at 16:25
  • 1
    This worked, whereas the chosen answer did not for me -- and after seeing the answers, I think rake is another Rails abomination along with ActionView. I'm sure it solves a particular set of problems but it makes everyday tasks painful. – Kevin Triplett Mar 06 '23 at 13:31
  • 1
    very straight forward - in 2023 too! THANKS – Pavan Kumar V Jun 27 '23 at 10:19
  • nothing else worked for me. this immediately worked. thank you. – frostymarvelous Aug 07 '23 at 13:14
119

If you want to pass named arguments (e.g. with standard OptionParser) you could use something like this:

$ rake user:create -- --user test@example.com --pass 123

note the --, that's necessary for bypassing standard Rake arguments. Should work with Rake 0.9.x, <= 10.3.x.

Newer Rake has changed its parsing of --, and now you have to make sure it's not passed to the OptionParser#parse method, for example with parser.parse!(ARGV[2..-1])

require 'rake'
require 'optparse'
# Rake task for creating an account

namespace :user do |args|
  desc 'Creates user account with given credentials: rake user:create'
  # environment is required to have access to Rails models
  task :create do
    options = {}
    OptionParser.new(args) do |opts|
      opts.banner = "Usage: rake user:create [options]"
      opts.on("-u", "--user {username}","User's email address", String) do |user|
        options[:user] = user
      end
      opts.on("-p", "--pass {password}","User's password", String) do |pass|
        options[:pass] = pass
      end
    end.parse!

    puts "creating user account..."
    u = Hash.new
    u[:email] = options[:user]
    u[:password] = options[:pass]
    # with some DB layer like ActiveRecord:
    # user = User.new(u); user.save!
    puts "user: " + u.to_s
    puts "account created."
    exit 0
  end
end

exit at the end will make sure that the extra arguments won't be interpreted as Rake task.

Also the shortcut for arguments should work:

 rake user:create -- -u test@example.com -p 123

When rake scripts look like this, maybe it's time to look for another tool that would allow this just out of box.

Tombart
  • 30,520
  • 16
  • 123
  • 136
  • 13
    From my perspective this really is the best answer. Bypass environment variable kludges, strange syntax with task arguments, the additional benefit for standard `--option-names`. My only suggestion would be to use `exit` rather than `abort` as `abort` will leave you with a return code of 1 to the shell. If the rake task is a part of a higher-level script it's more common to assume a non-zero exit is some type of error. – Joe Dec 01 '13 at 16:12
  • 1
    I agree with Joe, this is the best answer. The natural thing is to use the same interface for passing options to rake as you would when passing options to a script. – Rik Smith-Unna Jan 14 '14 at 13:59
  • 1
    I agree this is the best answer. Ain't there a way to bypass the ugly `--`? Like passing `rake` arguments to the actual task or something? Like `task :my_task, :*args do |t, args|` or something? – Augustin Riedinger Apr 02 '14 at 10:56
  • 2
    Besides, I don't understand what the `{username}` is here for. Where is it used? Why isn't it there in `-u {username}`? Cheers – Augustin Riedinger Apr 03 '14 at 06:07
  • As far as I know there's no way how to bypass ugly `--` (just not using rake). `{username}` should be replaced by your real username. It's just a notation for variable, it's not interpreted by ruby. – Tombart Apr 03 '14 at 13:33
  • `exit("account created.")` is causing an error `rake aborted!` wouldn't `puts "account created"; exit(0)` be a better approach? – Justin Tanner Nov 20 '14 at 02:59
  • It worked for me after I `ARGV.shift` twice to remove `create:user` and `--` from `ARGV`. I'm sure it's not the way it should be done. I will appreciate if someone will show how to fix it properly. – pawel7318 Jan 23 '15 at 12:28
  • @pawel7318 Which version of Rake do you use? Rake doesn't seem to follow semantic versioning conventions, there is a compatibility breaking change since `10.4.0` – Tombart Jan 25 '15 at 15:43
  • 2
    The way how Rake parses ARGV was changed in `10.4.1` and reverted in `10.4.2`. https://github.com/ruby/rake/commit/86af0ef6d793b85068a44fb3407b23c9c9b09bc7 – Tombart Jan 25 '15 at 16:17
  • I'm using 10.4.2. I created new question [here](http://stackoverflow.com/questions/28110384/how-to-parse-rake-arguments-with-optionparser/28112320). – pawel7318 Jan 25 '15 at 19:29
  • What about when you're using bundle exec rake? – valheru Feb 16 '17 at 12:47
  • the side effect of using `exit 0` is this task exits Rake when it is finished. So if you have a task that calls 2 tasks, and it calls the above first, the second task won't run. – karatedog Jul 22 '21 at 22:06
59

I've found the answer from these two websites: Net Maniac and Aimred.

You need to have version > 0.8 of rake to use this technique

The normal rake task description is this:

desc 'Task Description'
task :task_name => [:depends_on_taskA, :depends_on_taskB] do
  #interesting things
end

To pass arguments, do three things:

  1. Add the argument names after the task name, separated by commas.
  2. Put the dependencies at the end using :needs => [...]
  3. Place |t, args| after the do. (t is the object for this task)

To access the arguments in the script, use args.arg_name

desc 'Takes arguments task'
task :task_name, :display_value, :display_times, :needs => [:depends_on_taskA, :depends_on_taskB] do |t, args|
  args.display_times.to_i.times do
    puts args.display_value
  end
end

To call this task from the command line, pass it the arguments in []s

rake task_name['Hello',4]

will output

Hello
Hello
Hello
Hello

and if you want to call this task from another task, and pass it arguments, use invoke

task :caller do
  puts 'In Caller'
  Rake::Task[:task_name].invoke('hi',2)
end

then the command

rake caller

will output

In Caller
hi
hi

I haven't found a way to pass arguments as part of a dependency, as the following code breaks:

task :caller => :task_name['hi',2]' do
   puts 'In Caller'
end
Tilendor
  • 48,165
  • 17
  • 52
  • 58
  • 15
    The format for this functionality has changed as this warning states: `'task :t, arg, :needs => [deps]' is deprecated. Please use 'task :t, [args] => [deps]' instead.` – madh Jan 15 '12 at 19:54
35

I couldn't figure out how to pass args and also the :environment until I worked this out:

namespace :db do
  desc 'Export product data'
  task :export, [:file_token, :file_path] => :environment do |t, args|
    args.with_defaults(:file_token => "products", :file_path => "./lib/data/")

       #do stuff [...]

  end
end

And then I call like this:

rake db:export['foo, /tmp/']
Nate Flink
  • 3,934
  • 2
  • 30
  • 18
32

Actually @Nick Desjardins answered perfect. But just for education: you can use dirty approach: using ENV argument

task :my_task do
  myvar = ENV['myvar']
  puts "myvar: #{myvar}"
end 

rake my_task myvar=10
#=> myvar: 10
fl00r
  • 82,987
  • 33
  • 217
  • 237
29

Another commonly used option is to pass environment variables. In your code you read them via ENV['VAR'], and can pass them right before the rake command, like

$ VAR=foo rake mytask
kch
  • 77,385
  • 46
  • 136
  • 148
  • Frankly I was hoping for rake task -- these --go --to -a program and my task could get them from ARGV. Unfortunately I'm not sure if that's possible however I am currently using your solution: rake var1=val1 var2=val2 – JasonSmith Aug 03 '10 at 11:24
  • 3
    @jhs: `rake blah -- --these --go --to --a-program` (note the `--` to tell rake that its switches have ended), see http://stackoverflow.com/questions/5086224/how-can-i-pass-named-arguments-to-a-rake-task/5086648#5086648 – mu is too short Feb 27 '11 at 04:39
  • @muistooshort unfortunately (not knowing how it worked back in '11) this will try to run all the arguments passed as if they were tasks. One of the half ugly solution is to create empty tasks based on ARGV,content so these task will indeed be run, they just won't do anything, the second is to `exit` at the end of the task. Exiting is the easier, but that will break any compound task that try to run the exiting task along others as `exit` will halt task execution and exit Rake. – karatedog Jul 22 '21 at 20:52
  • @karatedog Are you sure about that? I just tried it to make sure and it seems okay, am I missing something? – mu is too short Jul 22 '21 at 21:33
  • 1
    @muistooshort Right, passing arguments with double dash works. I cannot correct the previous comment, the error was on passing linux style command line arguments like: `--switch1 value1 --switch2 value2`. – karatedog Jul 22 '21 at 21:59
25
desc 'an updated version'
task :task_name, [:arg1, :arg2] => [:dependency1, :dependency2] do |t, args|
    puts args[:arg1]
end
Feng
  • 2,872
  • 3
  • 23
  • 20
  • To call this, go: `rake task_name[hello, world]` – Dex Apr 27 '14 at 04:16
  • 3
    from http://rake.rubyforge.org/files/doc/rakefile_rdoc.html "Just a few words of caution. The rake task name and its arguments need to be a single command line argument to rake. This generally means no spaces. If spaces are needed, then the entire rake + argument string should be quoted. Something like this: rake "name[billy bob, smith]" " – Gayle May 13 '14 at 13:47
24

I just wanted to be able to run:

$ rake some:task arg1 arg2

Simple, right? (Nope!)

Rake interprets arg1 and arg2 as tasks, and tries to run them. So we just abort before it does.

namespace :some do
  task task: :environment do
    arg1, arg2 = ARGV

    # your task...

    exit
  end
end

Take that, brackets!

Disclaimer: I wanted to be able to do this in a pretty small pet project. Not intended for "real world" usage since you lose the ability to chain rake tasks (i.e. rake task1 task2 task3). IMO not worth it. Just use the ugly rake task[arg1,arg2].

jassa
  • 20,051
  • 4
  • 26
  • 24
  • 4
    Needed to make this `_, arg1, arg2 = ARGV` as the first arg was seen to be the name of the rake task. But that `exit` is a neat trick. – fatty Sep 12 '16 at 23:40
  • `rake task[arg1,arg2] && rake task2 && rake task3` Not sure if that's less ugly than `rake task[arg1,arg2] task2 task3`. Probably less efficient though. – Nuclearman Nov 11 '16 at 10:03
  • 1
    `_, *args = ARGV` is perfect for capturing all subsequent arguments! Thanks heaps! – XtraSimplicity Nov 18 '18 at 04:21
13

I use a regular ruby argument in the rake file:

DB = ARGV[1]

then I stub out the rake tasks at the bottom of the file (since rake will look for a task based on that argument name).

task :database_name1
task :database_name2

command line:

rake mytask db_name

this feels cleaner to me than the var=foo ENV var and the task args[blah, blah2] solutions.
the stub is a little jenky, but not too bad if you just have a few environments that are a one-time setup

djburdick
  • 11,762
  • 9
  • 46
  • 64
13
namespace :namespace1 do
  task :task1, [:arg1, :arg2, :arg3] => :environment do |_t, args|
    p args[:arg1]
  end
end

calling

rake namespace1:task1["1","2","3"]

No need to provide environment while calling

in zsh need to enclose calling in quotes

rake 'namespace1:task1["1","2","3"]'

pppery
  • 3,731
  • 22
  • 33
  • 46
  • 1
    Actually, I think single quote goes after `rake`; i.e. `rake 'namespace1:task1["1","2","3"]'`. Otherwise thank you for helpful answer. – guero64 May 22 '22 at 14:34
6

To run rake tasks with traditional arguments style:

rake task arg1 arg2

And then use:

task :task do |_, args|
  puts "This is argument 1: #{args.first}"
end

Add following patch of rake gem:

Rake::Application.class_eval do

  alias origin_top_level top_level

  def top_level
    @top_level_tasks = [top_level_tasks.join(' ')]
    origin_top_level
  end

  def parse_task_string(string) # :nodoc:
    parts = string.split ' '
    return parts.shift, parts
  end

end

Rake::Task.class_eval do

  def invoke(*args)
    invoke_with_call_chain(args, Rake::InvocationChain::EMPTY)
  end

end
Daniel Garmoshka
  • 5,849
  • 39
  • 40
5

The ways to pass argument are correct in above answer. However to run rake task with arguments, there is a small technicality involved in newer version of rails

It will work with rake "namespace:taskname['argument1']"

Note the Inverted quotes in running the task from command line.

Asim Mushtaq
  • 445
  • 5
  • 14
4

One thing I don't see here is how to handle arbitrary arguments. If you pass arguments that are not listed in the task definition, they are still accessible under args.extras:

task :thing, [:foo] do |task, args|
  puts args[:foo]     # named argument
  puts args.extras    # any additional arguments that were passed
end
lobati
  • 9,284
  • 5
  • 40
  • 61
3

To pass arguments to the default task, you can do something like this. For example, say "version" is your argument:

task :default, [:version] => [:build]

task :build, :version do |t,args|
  version = args[:version]
  puts version ? "version is #{version}" : "no version passed"
end

Then you can call it like so:

$ rake
no version passed

or

$ rake default[3.2.1]
version is 3.2.1

or

$ rake build[3.2.1]
version is 3.2.1

However, I have not found a way to avoid specifying the task name (default or build) while passing in arguments. Would love to hear if anyone knows of a way.

Gal
  • 5,537
  • 1
  • 22
  • 20
3

I like the "querystring" syntax for argument passing, especially when there are a lot of arguments to be passed.

Example:

rake "mytask[width=10&height=20]"

The "querystring" being:

width=10&height=20

Warning: note that the syntax is rake "mytask[foo=bar]" and NOT rake mytask["foo=bar"]

When parsed inside the rake task using Rack::Utils.parse_nested_query , we get a Hash:

=> {"width"=>"10", "height"=>"20"}

(The cool thing is that you can pass hashes and arrays, more below)

This is how to achieve this:

require 'rack/utils'

task :mytask, :args_expr do |t,args|
  args.with_defaults(:args_expr => "width=10&height=10")
  options = Rack::Utils.parse_nested_query(args[:args_expr])
end

Here's a more extended example that I'm using with Rails in my delayed_job_active_record_threaded gem:

bundle exec rake "dj:start[ebooks[workers_number]=16&ebooks[worker_timeout]=60&albums[workers_number]=32&albums[worker_timeout]=120]"

Parsed the same way as above, with an environment dependency (in order load the Rails environment)

namespace :dj do
  task :start, [ :args_expr ] => :environment do |t, args|
    # defaults here...
    options = Rack::Utils.parse_nested_query(args[:args_expr])  
  end
end

Gives the following in options

=> {"ebooks"=>{"workers_number"=>"16", "worker_timeout"=>"60"}, "albums"=>{"workers_number"=>"32", "worker_timeout"=>"120"}}
Abdo
  • 13,549
  • 10
  • 79
  • 98
3

Most of the methods described above did not work for me, maybe they are deprecated in the newer versions. The up-to-date guide can be found here: http://guides.rubyonrails.org/command_line.html#custom-rake-tasks

a copy-and-paste ans from the guide is here:

task :task_name, [:arg_1] => [:pre_1, :pre_2] do |t, args|
  # You can use args from here
end

Invoke it like this

bin/rake "task_name[value 1]" # entire argument string should be quoted
hexinpeter
  • 1,470
  • 1
  • 16
  • 14
3

If you can't be bothered to remember what argument position is for what and you want do something like a ruby argument hash. You can use one argument to pass in a string and then regex that string into an options hash.

namespace :dummy_data do
  desc "Tests options hash like arguments"
  task :test, [:options] => :environment do |t, args|
    arg_options = args[:options] || '' # nil catch incase no options are provided
    two_d_array = arg_options.scan(/\W*(\w*): (\w*)\W*/)
    puts two_d_array.to_s + ' # options are regexed into a 2d array'
    string_key_hash = two_d_array.to_h
    puts string_key_hash.to_s + ' # options are in a hash with keys as strings'
    options = two_d_array.map {|p| [p[0].to_sym, p[1]]}.to_h
    puts options.to_s + ' # options are in a hash with symbols'
    default_options = {users: '50', friends: '25', colour: 'red', name: 'tom'}
    options = default_options.merge(options)
    puts options.to_s + ' # default option values are merged into options'
  end
end

And on the command line you get.

$ rake dummy_data:test["users: 100 friends: 50 colour: red"]
[["users", "100"], ["friends", "50"], ["colour", "red"]] # options are regexed into a 2d array
{"users"=>"100", "friends"=>"50", "colour"=>"red"} # options are in a hash with keys as strings
{:users=>"100", :friends=>"50", :colour=>"red"} # options are in a hash with symbols
{:users=>"100", :friends=>"50", :colour=>"red", :name=>"tom"} # default option values are merged into options
xander-miller
  • 529
  • 5
  • 12
0

I came up with this:

# CLI syntax 
rake sometasks:mytask -- myparam=value
# app/lib/tasks/sometasks.rake

def parse_options
    options = ActiveSupport::HashWithIndifferentAccess.new
    separator_index = ARGV.index("--")
    if separator_index
      option_array = ARGV.slice(separator_index + 1 , ARGV.length)
      option_pairs = option_array.map { |pair| pair.split("=") }
      option_pairs.each { |opt| options[opt[0]] = opt[1] || true }
    end
    options
end

namespace :sometasks do
  task :mytask do 
    options = parse_options
    myparam = options[:myparam]
    # my task ...
  end
end

This allows to pass any param, and should work while calling multiple rake tasks in a row, if each param is assigned a value.

There's probably room for improvement though.

nakwa
  • 1,157
  • 1
  • 13
  • 25
-5

While passing parameters, it is better option is an input file, can this be a excel a json or whatever you need and from there read the data structure and variables you need from that including the variable name as is the need. To read a file can have the following structure.

  namespace :name_sapace_task do
    desc "Description task...."
      task :name_task  => :environment do
        data =  ActiveSupport::JSON.decode(File.read(Rails.root+"public/file.json")) if defined?(data)
    # and work whit yoour data, example is data["user_id"]

    end
  end

Example json

{
  "name_task": "I'm a task",
  "user_id": 389,
  "users_assigned": [389,672,524],
  "task_id": 3
}

Execution

rake :name_task 
Kara
  • 6,115
  • 16
  • 50
  • 57
  • 4
    If you need a JSON instructions file for your Rake task, you're probably doing too many things in your Rake task. – ZiggyTheHamster Aug 20 '15 at 00:16
  • This is *way* over-complicating something that's incredibly simple. – jeffdill2 Dec 30 '15 at 21:29
  • We were using a rake task to do many complex things like a task. One of them was to be the input to an ETL process, and you could need many input fields to do it.We were using a rake task to do many complex things like a task. One of them was to be the input to an ETL process, and you could need many input fields to do it. If you are thinking that a Rake Task is for easiest thing only, maybe you aren't using in other complex context. Thanks for commenting. – tundervirld Nov 24 '20 at 18:14