Reputation: 2901
I am trying to write a script that get some arguments where some of them might be empty.
It seems that Ruby's OptionParser is not allowing that and throws (OptionParser::InvalidArgument)
.
Code:
require 'optparse'
options = {}
OptionParser.new do |opt|
opt.on('--might_be_empty might_be_empty', String) { |o| options[:might_be_empty] = o }
end.parse!
puts "might_be_empty: #{options[:might_be_empty]}"
Happy flow:
ruby ./for_stack.rb --might_be_empty "some_real_data"
might_be_empty: some_real_data
When the value is empty:
ruby ./for_stack.rb --might_be_empty ""
./for_stack.rb:10:in `<main>': invalid argument: --might_be_empty (OptionParser::InvalidArgument)
How can I tell the OptionParser to allow empty strings?
Upvotes: 2
Views: 773
Reputation: 34308
Leave coercion type unspecified, or use Object
instead of String
. Both behave the same.
opt.on('--might_be_empty might_be_empty') { ... }
# ..or
opt.on('--might_be_empty might_be_empty', Object) { ... }
Test:
ruby ./for_stack.rb --might_be_empty "some_real_data"
might_be_empty: some_real_data
ruby ./for_stack.rb --might_be_empty ""
might_be_empty:
Upvotes: 5
Reputation: 160549
Option Parser allows optional values:
Running this several times:
require 'optparse'
options = {}
OptionParser.new do |opt|
opt.on('--might_be_empty [arg]') { |o| options[:might_be_empty] = o }
end.parse!
puts 'options[:might_be_empty].has_key? is %s' % options.has_key?(:might_be_empty)
puts 'options[:might_be_empty] is "%s"' % options[:might_be_empty]
puts 'options[:might_be_empty] is a %s' % options[:might_be_empty].class
pp ARGV
Shows me:
$ ruby test.rb -m
options[:might_be_empty].has_key? is true
options[:might_be_empty] is ""
options[:might_be_empty] is a NilClass
[]
$ ruby test.rb -m foo
options[:might_be_empty].has_key? is true
options[:might_be_empty] is "foo"
options[:might_be_empty] is a String
[]
$ ruby test.rb -m 1
options[:might_be_empty].has_key? is true
options[:might_be_empty] is "1"
options[:might_be_empty] is a String
[]
This is documented a couple times in the sample code but not explicitly stated in the text:
def perform_inplace_option(parser)
# Specifies an optional option argument
parser.on("-i", "--inplace [EXTENSION]",
"Edit ARGV files in place",
"(make backup if EXTENSION supplied)") do |ext|
self.inplace = true
self.extension = ext || ''
self.extension.sub!(/\A\.?(?=.)/, ".") # Ensure extension begins with dot.
end
end
Also note that you don't have to coerce the returned value because it's already a String. Any values passed in from the command-line are strings as they're snatched from ARGV.
Upvotes: 0
Reputation: 11035
According to the docs for OptionParser Type Coercion, passing String
isn't just a "do nothing":
String – Any non-empty string
However, if you just leave the Argument pattern off of on
(which directs you to the docs for make_switch
):
Acceptable option argument format, must be pre-defined with #accept or #accept, or Regexp. This can appear once or assigned as String if not present, otherwise causes an ArgumentError.
While slightly confusing that it's "assigned as String if not present", it's not "assigned as a non-empty String if not present", and it will default to passing you any String, and work as you want it to:
opt.on('--might_be_empty might_be_empty') { |o| options[:might_be_empty] = o }
# is optional
% ruby example.rb
might_be_empty:
# if passed, must have a value
% ruby example.rb --might_be_empty
Traceback (most recent call last):
example.rb:8:in '<main>': missing argument: --might_be_empty (OptionParser::MissingArgument)
# can pass an empty string
% ruby example.rb --might_be_empty ""
might_be_empty:
# can pass any string
% ruby example.rb --might_be_empty "not empty"
might_be_empty: not empty
If you don't want to just leave the argument pattern off, you can create custom conversions, though this seems like overkill to me.
Upvotes: 1