Is it possible to use OptionParser with short options such as -oo?

Hi there,

I’m trying to wrap a command line tool with a Ruby script in order to be
able to clean up and validate any user supplied arguments before calling
the tool. I’m therefore trying to use OptionParser to parse the command
line arguments and pass them on to the tool after processing.

However, the tool accepts short arguments that have multi character
names. For example, ‘-o filename’ and ‘-oo filename’ where the double
‘o’ signifies that the file should be overwritten and not appended to.
OptionParser can’t cope with multi char short options so what can I do
here? Can I extend OptionParser in any way or should I try and manually
parse for these short options before calling option parser? Doesn’t
seem too clean that way.

Cheers.

On Fri, Mar 1, 2013 at 1:45 PM, Shareef J. [email protected] wrote:

I’m trying to wrap a command line tool with a Ruby script in order to be
able to clean up and validate any user supplied arguments before calling
the tool. I’m therefore trying to use OptionParser to parse the command
line arguments and pass them on to the tool after processing.

However, the tool accepts short arguments that have multi character
names.

I think this is self contradictory: short options are one character
options. :slight_smile:

For example, ‘-o filename’ and ‘-oo filename’ where the double
‘o’ signifies that the file should be overwritten and not appended to.
OptionParser can’t cope with multi char short options so what can I do
here? Can I extend OptionParser in any way or should I try and manually
parse for these short options before calling option parser? Doesn’t
seem too clean that way.

That doesn’t seem to fit the model of OptionParser well. You would
have to define that -o takes an optional argument but if you do that
it’ll use the second “o” as argument.

irb(main):017:0> op = OptionParser.new do |opts|
irb(main):018:1* opts.on(‘-o=[arg]’) {|v| o += 1; o_val << v if v}
irb(main):019:1> end
=> Usage: irb [options]
-o=[arg]

irb(main):020:0> op.parse %w{-o}
=> []
irb(main):021:0> o
=> 1
irb(main):022:0> o_val
=> []
irb(main):023:0> o = 0; o_val = []
=> []
irb(main):024:0> op.parse %w{-o val}
=> [“val”]
irb(main):025:0> o
=> 1
irb(main):026:0> o_val
=> []
irb(main):027:0> o = 0; o_val = []
=> []
irb(main):028:0> op.parse %w{-oo val}
=> [“val”]
irb(main):029:0> o
=> 1
irb(main):030:0> o_val
=> [“o”]

If the tool has an option --dry-run or similar I’d simply add that to
the command line and see what it reports. Other than that I’d
probably avoid the validation. Reason is that you need to change your
validation every time the tool’s API changes - and you have the
validation code in two places.

Kind regards

robert

@Robert - Expert solution :slight_smile:

Robert, thanks for that. Unfortunately the validation needs to be there
so I’ll have to roll my own solution. Was just hoping that I could
reuse a library.

Actually, with minimal hacking I’ve managed to get it to do what I want.
Here’s the patch file for anyone interested. I’m running 1.9.2.

$ cat optparse.patch
— optparse.rb 2013-03-04 10:58:37.789740398 +0000
+++ optparse.rb.modified 2013-03-04 10:55:44.866359326 +0000
@@ -1154,6 +1154,15 @@
end
sdesc << “-#{q}”
short << Regexp.new(q)

  •  when /^-(.\S)(.+)?/
    
  •    q, a = $1, $2
    
  •    if a
    
  •      o = notwice(NilClass, klass, 'type')
    
  •      default_style = default_style.guess(arg = a)
    
  •      default_pattern, conv = search(:atype, o) unless 
    

default_pattern

  •    end
    
  •    sdesc << "-#{q}"
    
  •    short << q
     when /^-(.)(.+)?/
       q, a = $1, $2
       if a
    

@@ -1281,7 +1290,7 @@
end

     # short option
  •    when /\A-(.)((=).*|.+)?/m
    
  •    when /\A-(.(?:.)?)((=).*|.+)?/m
         opt, has_arg, eq, val, rest = $1, $3, $3, $2, $2
         begin
           sw, = search(:short, opt)

Am 04.03.2013 12:05, schrieb Shareef J.:

Actually, with minimal hacking I’ve managed to get it to do what I want.
Here’s the patch file for anyone interested. I’m running 1.9.2.

You could always parse and modify the command line arguments
before passing them on to OptionParser.

Then you wouldn’t have to meddle with library internals.