9

Reffering that answer I was trying to use OptionParser to parse rake arguments. I simplified example from there and I had to add two ARGV.shift to make it work.

require 'optparse'

namespace :user do |args|

  # Fix I hate to have here
  puts "ARGV: #{ARGV}"
  ARGV.shift
  ARGV.shift
  puts "ARGV: #{ARGV}"

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

    puts "user: #{options[:user]}"

    exit 0
  end
end

This is the output:

$ rake user:create -- -u foo
ARGV: ["user:create", "--", "-u", "foo"]
ARGV: ["-u", "foo"]
user: foo

I assume ARGV.shift is not the way it should be done. I would like to know why it doesn't work without it and how to fix it in a proper way.

Community
  • 1
  • 1
pawel7318
  • 3,383
  • 2
  • 28
  • 44
  • 1
    is there any way to avoid using `exit(0)` and `rake` not throwing `"Don't know how to build task 'foo'"` when you try with `rake user:create -- -u foo`? what if you do not want `rake` to stop there? `OptionParser#parse` doesn't allow to use `-u=foo`... – rellampec Jan 18 '20 at 00:08

4 Answers4

7

You can use the method OptionParser#order! which returns ARGV without the wrong arguments:

options = {}

o = OptionParser.new

o.banner = "Usage: rake user:create [options]"
o.on("-u NAME", "--user NAME") { |username|
  options[:user] = username
}
args = o.order!(ARGV) {}
o.parse!(args)
puts "user: #{options[:user]}"

You can pass args like that: $ rake foo:bar -- '--user=john'

rubycademy.com
  • 509
  • 5
  • 16
3

I know this does not strictly answer your question, but did you consider using task arguments?

That would free you having to fiddle with OptionParser and ARGV:

namespace :user do |args|
  desc 'Creates user account with given credentials: rake user:create'
  task :create, [:username] => :environment do |t, args|
    # when called with rake user:create[foo],
    # args is now {username: 'foo'} and you can access it with args[:username]
  end
end

For more info, see this answer here on SO.

Community
  • 1
  • 1
awendt
  • 13,195
  • 5
  • 48
  • 66
0

Try this:

require 'optparse'

namespace :programs do |args|
  desc "Download whatever"
  task :download => [:environment] do

    # USAGE: rake programs:download -- rm
    #-- Setting options $ rake programs:download -- --rm
    options = {}
    option_parser = OptionParser.new
    option_parser.banner = "Usage: rake programs:download -- rm"
    option_parser.on("-r", "--rm","Remove s3 files downloaded") do |value|
      options[:remove] = value
    end
    args = option_parser.order!(ARGV) {}
    option_parser.parse!(args)
    #-- end

    # your code here
  end
end
anothermh
  • 9,815
  • 3
  • 33
  • 52
  • 1
    Welcome to Stack Overflow. Please check [answer] for tips on giving the best answers. For example, it would be helpful if you showed the most relevant code in your answer and some context for the links in case they are unavailable when future users come with similar questions. – Kateract Apr 20 '16 at 19:46
-1

You have to put a '=' between -u and foo:

$ rake user:create -- -u=foo

Instead of:

$ rake user:create -- -u foo

rubycademy.com
  • 509
  • 5
  • 16
  • With `ARGV.shift` it work with or without `=`. Unfortunately without `ARGV.shift` it doesn't work whenever I use `=` or not. – pawel7318 Jan 23 '15 at 13:44
  • 1
    The question is how to parse general arguments in Rake, instead of how to pass arguments in rails' Rake. – Xiao Hanyu Mar 20 '16 at 13:35