3

I'm currently building a simple program which will read and write file on standard output. I want to launch my program this way : ruby main.rb -f file1 file2 file3 ...

But with optParse I cannot get this to work I must include separator .. I need optParse because I handle multiple options (like verbose, help ...). So if I do this : ruby main.rb -f file1,file2 ... It works

How can I achieve this ?

Thanks !

Nicolas Charvoz
  • 1,509
  • 15
  • 41
  • 1
    You can see [here](http://ruby-doc.org/stdlib-2.3.0/libdoc/optparse/rdoc/OptionParser.html#class-OptionParser-label-Type+Coercion) Array's require comma separated values. They do say custom coercion's are coming so maybe in future ruby versions? – Anthony Feb 17 '16 at 15:15
  • It's common for CLIs to take a list of files as their last argument(s), as described in this answer: http://stackoverflow.com/questions/2449171/how-to-parse-an-argument-without-a-name-with-rubys-optparse It's not exactly what you're asking for, but might that approach work for your application? – Jordan Running Feb 17 '16 at 15:39

2 Answers2

3

If you don't have option parameters you pass or if all other parameters are optional, you can just pass the files the old-fashioned way: via ARGV. By default, command line options are separated by spaces, not commas.

If you absolutely need to support the -f option, you could add support for ARGV in addition

require "optparse"

options = {
  :files => []
}
opt_parse = OptionParser.new do |opts|
  opts.banner = "Usage: main.rb file(s) ..."

  opts.on("-f", "--files file1,file2,...", Array, "File(s)") do |f|
    options[:files] += f
  end

  opts.on_tail("-h", "--help", "Show this message") do
    puts opts
    exit
  end

end
opt_parse.parse!

options[:files] += ARGV

if options[:files].length == 0
  abort(opt_parse.help)
end

puts options[:files]

Using this method, you can even mix both styles:

$ main.rb -f -f file1,file2 file3 -f file4 file5
file1
file2
file4
file3
file5

(Note file5 is really being passed via ARGV, but it kinda looks like you are using a space as a separator.)

LW001
  • 2,452
  • 6
  • 27
  • 36
Kathryn
  • 1,557
  • 8
  • 12
0

There are a handful of ways to accept multiple values for a given argument with optparse. Some methods allow space-delimited lists, but each way has its pros and cons. The good news is that these methods can be used interchangeably, so you can always implement multiple methods and let the end-user use the one they like.

Given a script called process_files.rb, like so:

require 'optparse'

args = { files: [] }

OptionParser.new do |opts|
  # Option 1: use an array-type optparse argument
  opts.on('--files FILE1,FILE2,...', Array, 'A list of comma-separated files.') do |files|
    args[:files].concat(files)
  end

  # Option 2: use a single-value argument; expect it to be repeated multiple times
  opts.on('-f', '--file FILE', 'A single file. Repeat for multiple files.') do |file|
    args[:files] << file
  end

  # Option 3: take a string and split it using whatever delimiter you want
  opts.on('--colon-files FILE1:FILE2:...', 'A colon-delimited file list.') do |str|
    args[:files].concat(str.split(':'))
  end

  # Option 4: as above, but quoting the file list on the command line allows space delimiting
  opts.on('--spaced-files "FILE1 FILE2 ..."', 'A space-delimited file list.') do |str|
    args[:files].concat(str.split(/\s+/))
  end
end.parse!

# Option 5: Assume all remaining, unparsed arguments are whitespace-delimited files
args[:files].concat(ARGV)

puts args[:files].inspect

Here are the various ways to feed it a list of files:

$ ruby process_files.rb --files foo,bar,baz
["foo", "bar", "baz"]

$ ruby process_files.rb -f foo -f bar -f baz
["foo", "bar", "baz"]

$ ruby process_files.rb --colon-files foo:bar:baz
["foo", "bar", "baz"]

$ ruby process_files.rb --spaced-files 'foo bar baz'
["foo", "bar", "baz"]

$ ruby process_files.rb foo bar baz
["foo", "bar", "baz"]

$ ruby process_files.rb --files apple,banana -f cherry --colon-files date:elderberry \
    --spaced-files 'fig grape' honeydew
["apple", "banana", "cherry", "date", "elderberry", "fig", "grape", "honeydew"]

Ref: https://rubyreferences.github.io/rubyref/stdlib/cli/optparse.html

Ben Amos
  • 1,750
  • 15
  • 18