Search code examples
rubyoptparseoptionparser

Splitting ARGV into two file lists


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?


Solution

  • 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 --.