Forum: Ruby parsing unknown options

C40020a47c6b625af6422b5b1302abaf?d=identicon&s=25 Stefano Crocco (crocco)
on 2006-11-13 23:45
I'm not a ruby expert, so forgive me if the answer to my question is
obvious. I want to write a program which will load a plug-in
depending on an option passed in the command line. Each of the possible
plug-ins have their own options, which will also need to be parsed. For
example, if the main application accepts the -p option to select the
plug-in and the -a and -b options, I would like my program to be called
this way:

program -p myplugin -a -b -c -d

of course -c and -d are the options recognized by the plug-in. I'm not
sure on how to implement this. My initial idea was to use a two steps
approach:
1: parse the command line arguments looking only for the -p options and
ignoring the others. Once found the name of the plug-in, load it.
2: parse again the arguments, this time considering all the options,
including those accepted by the plug-in (which the plug-in itself will
tell the main program in some way).

The problem is that, as far as I can tell, OptParse will raise an
exception when it finds an unknown option (i.e as soon as it hits -c in
my example above). Is there a way around this behavior? Or does anybody
know of a better way to approach the whole problem?

Thanks in advance

Stefano
4db5dbdedcae4df2feca2f2d93330208?d=identicon&s=25 Paul Lutus (Guest)
on 2006-11-14 01:45
(Received via mailing list)
Stefano Crocco wrote:

> I'm not a ruby expert, so forgive me if the answer to my question is
> obvious.

This time, the answer really is obvious.

> The problem is that, as far as I can tell, OptParse will raise an
> exception when it finds an unknown option (i.e as soon as it hits -c in
> my example above). Is there a way around this behavior? Or does anybody
> know of a better way to approach the whole problem?

Sure. Parse the command line yourself. Scan the input arguments, select
those that begin with a dash, submit any second character to a case
statement. Use the case statement to distribute your actions. You would
have to do the latter no matter how you parsed the command line, and the
former is a few lines of code.

-----------------------------------------

#!/usr/bin/ruby -w

ARGV.each do |com|
   if com.length > 1 && com[0,1] == '-'
      case com[1,1]
      when 'a' then
         puts "Option a"
      when 'b' then
         puts "Option b"
      when 'c' then
         puts "Option c"
      when 'd' then
         puts "Option d"
      end
   end
end
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2006-11-14 03:11
(Received via mailing list)
Paul Lutus wrote:
> Stefano Crocco wrote:
...
>> The problem is that, as far as I can tell, OptParse will raise an
>> exception when it finds an unknown option (i.e as soon as it hits -c in
>> my example above). Is there a way around this behavior? Or does anybody
>> know of a better way to approach the whole problem?
>
> Sure. Parse the command line yourself.

I don't recommend it unless your syntax is simple or you like writing
command line parsers.

It just so happens that yesterday I wrote a command line parser that may
help in this case. I wrote it because getopt/long wasn't deleting option
arguments from ARGV, so it was hard to use with ARGF. My parser leaves
any unknown options it finds in ARGV. It has some other nice features[1]
and only a few limitations[2]. Basically, it does one thing: turn an
array of strings into a hash of recognized options and their arguments,
leaving unrecognized strings in the original array.

I didn't plan on releasing this today, but there's really no reason not
to. It's called argos[3]. For now it lives at:

http://redshift.sourceforge.net/argos.rb

The heart of it is simple enough (about 40 lines) to copy and paste into
a small ruby program file, if you don't want to require it as a library.

Here's a simple example:

     require 'argos'

     optdef = {
       "v"   => true,
       "n"   => proc {|arg| Integer(arg)}
     }

     argv = %w{-v -n10 filename}
     opts = Argos.parse_options(argv, optdef)
     p opts    # ==> {"v"=>true, "n"=>10}
     p argv    # ==> ["filename"]

[1] Features:

   Output is a hash of {option => value, ...}.

   Supports both long ("--foo") and short ("-f") options.

   A long option with an argument is --foo=bar or --foo bar.

   A short option with an argument is -fbar or -f bar.

   The options -x and --x are synonymous.

   Short options with no args can be combined as -xyz in place of
   -x -y -z.

   The string "--" terminates option parsing, leaving the rest
   untouched.

[2] Limitations:

   A particular option takes either 0 args or 1 arg. There are no
   optional arguments, in the sense of both "-x" and "-x3" being
   accepted.

   Options lose their ordering in the output hash (but they are
   parsed in order and you can keep track using state in the handler
   closures).

   There is no usage/help output.

[3] Argos was Odysseus' faithful dog, who was good at recognizing ;)
C40020a47c6b625af6422b5b1302abaf?d=identicon&s=25 Stefano Crocco (crocco)
on 2006-11-14 13:38
Thanks for the answers. I decided to take an approach similar to
building my own parser, but keeping my two steps approach:
- first:

  ARGV.each_with_index do |s, i|
    plugin=args[i+1] if s=='-p' or s=='--plugin' or s=~/-\w*p/
  end

(this should take care of the three possible formats: short option, long
option and several short options together, such as -abp plugin

- load the plugin
- use OptionParser to rescan the options

I'm still working on how to communicate the options recognized by the
plugin to the main program.

Stefano
4db5dbdedcae4df2feca2f2d93330208?d=identicon&s=25 Paul Lutus (Guest)
on 2006-11-14 18:07
(Received via mailing list)
Joel VanderWerf wrote:

> I don't recommend it unless your syntax is simple or you like writing
> command line parsers.

My point is that a software solution shouldn't be any more complex than
circumstances warrant. The OP might otherwise believe he needs to employ
a
package whose function he doesn't understand, to solve a problem he
doesn't
have.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-11-14 18:21
(Received via mailing list)
On Tue, 14 Nov 2006, Stefano Crocco wrote:

>
> - load the plugin
> - use OptionParser to rescan the options
>
> I'm still working on how to communicate the options recognized by the
> plugin to the main program.
>
> Stefano

OptionParser already handles unknown options:

   begin
     option_parser.parse! argv
   rescue OptionParser::InvalidOption => e
     # preverve unknown options
     e.recover argv
   end


-a
C40020a47c6b625af6422b5b1302abaf?d=identicon&s=25 Stefano Crocco (crocco)
on 2006-11-14 21:31
unknown wrote:
> On Tue, 14 Nov 2006, Stefano Crocco wrote:
>
>>
>> - load the plugin
>> - use OptionParser to rescan the options
>>
>> I'm still working on how to communicate the options recognized by the
>> plugin to the main program.
>>
>> Stefano
>
> OptionParser already handles unknown options:
>
>    begin
>      option_parser.parse! argv
>    rescue OptionParser::InvalidOption => e
>      # preverve unknown options
>      e.recover argv
>    end
>
>
> -a

Thanks for pointing this out. It's exactly what I was looking for, and I
completely missed it. I've modified your code to store in a array the
unrecognized options and their arguments, if any is provided:

unknown=[] #this is the array where the unknown options will be put

begin
  option_parser.parse! argv
rescue OptionParser::InvalidOption => e
  e.recover argv
  #recover just put the unknown option back into argv, so I extract it
again and put it into unknown
  unknown << argv.shift

  #if argv still contains some elements, and the first one doesn't start
with a -, i.e is the argument for the unknown option, I remove it as
well
  unknown << argv.shift if argv.size>0 and temp.first[0..0]!='-'
  # go on with parsing
  retry
end

puts unknown
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2006-11-15 10:05
(Received via mailing list)
On 14.11.2006 18:19, ara.t.howard@noaa.gov wrote:
>> (this should take care of the three possible formats: short option, long
> OptionParser already handles unknown options:
>
>   begin
>     option_parser.parse! argv
>   rescue OptionParser::InvalidOption => e
>     # preverve unknown options
>     e.recover argv
>   end

Thanks!  Learn something new every day.  I believe OptionParser to be an
excellent piece of software - actually this short example is just
another confirmation for that.  But I always found that documentation of
OptionParser was a bit weak.  Did I miss anything?  Clearly the docs on
ruby-doc.org are rudimentary.  Is there anyone that knows OptionParser
intimately and is willing to write up some documentation or at least add
some more examples to doc of class OptionParser that demonstrate
additional funcationality?  It might be sufficient to just collect
working pieces of OptionParser code from the community, massage it a bit
and place it into the default docs.  I would greatly appreciate that -
and probably others, too.  What do you think?

Kind regards

	robert
Ea24c17719a975fb38c107a60f4b3802?d=identicon&s=25 Vincent Fourmond (Guest)
on 2006-11-15 10:39
(Received via mailing list)
Robert Klemme wrote:
>>>
>>
> excellent piece of software - actually this short example is just
> another confirmation for that.  But I always found that documentation of
> OptionParser was a bit weak.  Did I miss anything?  Clearly the docs on
> ruby-doc.org are rudimentary.  Is there anyone that knows OptionParser
> intimately and is willing to write up some documentation or at least add
> some more examples to doc of class OptionParser that demonstrate
> additional funcationality?  It might be sufficient to just collect
> working pieces of OptionParser code from the community, massage it a bit
> and place it into the default docs.  I would greatly appreciate that -
> and probably others, too.  What do you think?

  I think that it would be a great idea. Personnaly, I always found that
looking at the code, documentation and trying was enough, but with
appropriate examples, that would be a lot easier. If the current
maintainers of OptionParser are reading this, that would be nice to tell
us how we could contribute to this ?

  Would it make sense to put that documentation on a personal page,
waiting to be included upstream ? I'd be willing to do that, if anyone
wants to contribute.

  Cheers !

	Vince
Ae36591847393e58ff189704f5eb18f2?d=identicon&s=25 Jeremy Hinegardner (Guest)
on 2006-11-15 18:30
(Received via mailing list)
On Wed, Nov 15, 2006 at 06:05:08PM +0900, Robert Klemme wrote:
> and probably others, too.  What do you think?
I've been using OptionParser a fair bit.  You can count me in if you
want to coordinate something.  I'll go through my code and pull out some
examples too.

enjoy,

-jeremy
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.