rubyflagsoptionparser

How to get the specified option flag from within OptionParser


I'd like to get the exact option flag that was specified on the command line from within Ruby's OptionParser.

For example, suppose I have the following code:

parser = OptionParser.new {                                                                                                 
  |opts|                                                                                                                                                                                                                                     
  opts.on('-f', '--file FILE', 'filename') {                                                                                            
    |arg|                                                                                                                   
    $filename = arg                                                                                                 
    # Here I'd like to know whether '-f' or '--file' was entered
    # on the command line.                                                                              
  }
  # ... etc. ...
}

I'd like to know whether the user happened to type '-f' or '--file' on the command line. Is this possible without writing two separate opts.on blocks?


Solution

  • I don't think you can get the flags being passed in when inside the OptionParser.new block. At that point it's too late. However, prior to OptionParser parsing the command-line, it's possible to look and see what's being passed in.

    ARGV contains the raw command-line. For instance, if this is the command-line invocation for some code:

    foo -i 1 -j 2
    

    then ARGV will contain:

    ["-i", "1", "-j", "2"]
    

    and, then it becomes pretty easy to grab the flags:

    ARGV.grep(/^-/) # => ["-i", "-j"]
    

    There are other OptionParser-like tools for Ruby, and those might let you access the flags being used, but I can't think of a reason I'd ever care to. Looking at your code it seems like you're not understanding how to use OptionParser:

    parser = OptionParser.new {                                                                                                 
      |opts|                                                                                                                                                                                                                                     
      opts.on('-f', '--file FILE', 'filename') {                                                                                            
        |arg|                                                                                                                   
        $filename = arg                                                                                                 
        # Here I'd like to know whether '-f' or '--file' was entered
        # on the command line.                                                                              
      }
      # ... etc. ...
    }
    

    Instead of doing it that way, I'd write it:

    options = {}
    OptionParser.new do |opts|                                                                                                                                                                                                                                     
      opts.on('-f', '--file FILE', 'filename') { |arg| options[:filename] = arg }
    end.parse!
    
    if options[:filename]
      puts 'exists' if File.exist?(options[:filename])
    end
    

    Then, later in your code you can check in the options hash to see if either of the -f or --file options was given, and what the value was. That it was one or the other of -f or --file shouldn't ever matter.

    If it does then you need to differentiate between the two flags, instead of treating them as if they're aliases:

    options = {}
    OptionParser.new do |opts|                                                                                                                                                                                                                                     
      opts.on('-f', 'filename') { |arg| options[:f] = arg }
      opts.on('--file FILE', 'filename') { |arg| options[:file] = arg }
    end.parse!
    
    if options[:file] || options[:f]
      puts 'exists' if File.exist?(options[:file] || options[:f])
    end