Search code examples
rubyoptparse

Help me get options off the ground for my little script


I'm trying to get my script to do different things based on options. But... I don't know ruby, at all. I can't even tell you what an array really is. Here's what I got:

require 'optparse'
require 'pp'

# the options eventually get put here
options = {}

optparse = OptionParser.new do|opts|

# the help info
opts.banner = "Usage: script.rb [options] input-file output-file"

# This sets the default of 'flag' to 'false' and says it should be
# 'true' if the '-f' option is present
options[:flag] = false
  opts.on( '-f', '--flag', "Flag has been set" ) do
  options[:flag] = true
  end
end

optparse.parse!

# if no input-file or output-file is given, spit out the help
if ARGV.empty?
  puts optparse
  exit(-1)
end

# If the flag is true then tell me so, if not, tell me it isn't.
if options[:flag] = true
  pp "Flag is true"
else
  pp "Flag is false"
end

Thanks in advance, and sorry for trying to code without knowing how to code. I bow to you oh great ones.


Solution

  • The options Hash

    options is not an Array, it's Hash. In a hash, there are objects stored, each with a special key of their own. In your case, the key is :flag, so that whenever you call options[:flag], you will get whatever is stored there.

    options = {}
    

    This just creates a new Hash which is empty.

    The options parser

    Let's take it from the beginning: Your code starts at

    optparse = OptionParser.new do|opts|
      ...
    end
    

    You create an instance of an OptionParser. This is a class that helps you, well, parse options. The new() method actually can take a block, which is a special Ruby command. If you don't know what an Array is, you'll maybe need to read a bit more about Ruby blocks because it's a rather special language element.

    Anyway, what it does is create an object named opts which will handle the arguments passed to your script. You can see this object in |opts| (within the pipes) and it's the block variable -- you've read about blocks now, have you?

    First it helps to print a banner with the banner() method. Later, it will check with the on() method whether there was an argument passed.

    Also, remember that you now have your empty options Hash from before. In this case we want to look for a -f option passed, so we call

    opts.on( '-f', '--flag', "Flag has been set" ) do
    

    As mentioned before, the on() method looks for its first parameter ('-f'), or an alternative like '--flag'. It also has a description. If the option was passed, the line below will be executed, because we want to remember if the option was passed or not:

    options[:flag] = true
    

    Now, your options hash contains the key :flag and we know that it is true.

    Note: optparse.parse! will actually just start all the parsing. Remember that we've created this Option Parser object before, but it didn't really do anything on its own yet. Therefore, it has this method called parse!(). The exclamation mark is something people like to use in Ruby for some methods. You'll come across it sometimes. Anyway, if you don't call parse!, nothing will happen. This is just the way Ruby's option parser is built.

    Checking the options

    Now at the end of the script you will assume that all your options are in the options hash, as the option parser parsed everything before. Just look if the element at the key :flag has been set to true:

    if options[:flag] == true
    

    And voila! Important: You forgot double == in your code! You want to make a comparison and using = would set the key to true no matter what. So please remember that for conditional expressions you need == and not =!

    Note: We could have also just looked for the key to be there. As the hash was empty before, it didn't have any key at all. After the option -f was parsed, the hash included the key :flag. So instead of looking for the value, which obviously can only be true, we could just look for the key:

    if options.key?(:flag)
      # => the flag was set
    end
    

    Adding more options

    Just like the on() method in your example you can add another one. Just remember to take another key for your hash, for example :execute.

    opts.on( '-x', '--execute', "Do something!" ) do
      options[:execute] = true
    end