0

I am using Ruby OptionParser but can not figure out how to get non-option arguments as two lists.

myscript --option-one --option-two file1 file2 -- file10 file11

Is there a way to get from OptionParser two lists of files separately?

[file1, file2]
[file10, file11]

I do not care which of them remains in ARGV, just want to have two lists separately to submit them to different processing.

My current solution is

  1. adding a handler of -- as follows

    opts.on('--', 'marks the beginning of a different list of files') do
       ARGV.unshift(:separator)
    end
    

    this produces ARGV with the following content

    [ file1, file2, :separator, file10, file11 ]

  2. and then, outside of OptionParser and after parse! was called, I modify ARGV

    list1 = ARGV.shift(ARGV.index(:separator))
    ARGV.shift
    

Is there a more elegant way of accomplishing it?

Nik O'Lai
  • 3,586
  • 1
  • 15
  • 17
  • How are the files different, and why can't you introduce a new argument to handle the last two files. Something like `--option-two file1 file2 ---option-three file10 file11`. If you need a separator, they sound like they're a different option. – Adam Oct 20 '14 at 12:51
  • How do I tell `OptionParser` to remove file10 and file11 from ARGV? I know how to do it for a single file (`'--option-three FILENAME'`) but do not know how to do it for an undefined number of files – Nik O'Lai Oct 20 '14 at 12:56

1 Answers1

0

You're not using OptionParser correctly. It has the ability to create arrays/lists for you, but you have to tell it what you want.

You can define two separate options that each take an array, or, you could define one that takes an array and the other comes from ARGV after OptionParser finishes its parse! pass.

require 'optparse'

options = {}
OptionParser.new do |opt|
  opt.on('--foo PARM2,PARM2', Array, 'first file list') { |o| options[:foo] = o }
  opt.on('--bar PARM2,PARM2', Array, 'second file list') { |o| options[:bar] = o }
end.parse!

puts options 

Saving and running that:

ruby test.rb --foo a,b --bar c,d
{:foo=>["a", "b"], :bar=>["c", "d"]}

Or:

require 'optparse'

options = {}
OptionParser.new do |opt|
  opt.on('--foo PARM2,PARM2', Array, 'first file list') { |o| options[:foo] = o }
end.parse!

puts options 
puts 'ARGV contains: "%s"' % ARGV.join('", "')

Saving and running that:

ruby test.rb --foo a,b c d
{:foo=>["a", "b"]}
ARGV contains: "c", "d"

You don't need to define --. -- is handled by the shell, not the script. This is from man sh:

--        A  --  signals the end of options and disables further option processing.  Any arguments after the --
          are treated as filenames and arguments.  An argument of - is equivalent to --.
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
  • Thank you for you reply! I know about Array and comma-separated command line arguments. This is exactly what I'd like to avoid. Was just wondering if there is a way to do it. – Nik O'Lai Oct 20 '14 at 14:24
  • Try outputting ARGV from ruby script, `--` will be there. AFAIK, shell when its is parsing its own arguments, stops processing if `--` is seen. Other scripts (in other languages too) should attain to this rule and I break it, I know :) – Nik O'Lai Oct 20 '14 at 14:29
  • You can't have space-delimited parameters in an ARGV list and use OptionParser to gather them into the options of a particular parameter. Option parsers don't do that, at least none of the ones I've ever used will. You *can* roll your own starting with ARGV, but then you lose all the power they provide plus you get to discover all the problems their authors already encountered. – the Tin Man Oct 20 '14 at 14:42