Command-Line Options and Arguments


Ruby Way
By Hal Fulton
Slots : 1.0
Table of Contents

Rumors of the death of the command line are greatly exaggerated. Although we live in the age of the GUI, every day thousands of us retreat to the older text-based interfaces for one reason or another.

Ruby has many of its roots in Unix, as we've said. Yet even in the Windows world, there is such a thing as a command line; and frankly, we don't see it going away any time soon.

When operating at this level, parameters and switches are used to communicate with the program at the time of its invocation. We show here how to deal with these parameters (or arguments) and switches (or options).

Parsing Command-Line Options

The getoptlong library is probably the most commonly used command-line parser. (The getopts.rb library is considered obsolete because it has more limited functionality.) It can accept both single-letter and longer option names, and it recognizes the double hyphen () as meaning the end of all the options. Its behavior is essentially the same as its GNU counterpart, for those who are familiar with that code.

The GetoptLong class must be instantiated, giving a parser object. This object can then be set up with the allowed command-line options and used to retrieve them one at a time.

The parser object has a set_options method that takes a list of arrays. Each array contains one or more options (as strings) and one argument flag, which tells whether an argument is allowed for that option. The options in each array are considered synonyms; the first one mentioned is the canonical name of the option, as returned by a get operation.

As an example, suppose that we have a tool with these options: -h or help will print help information, -f or file will specify a filename argument, and -l or lines will truncate the output after the specified number of lines (defaulting to 100).

We could begin in this way:


 require "getoptlong" parser = parser.set_options(          ["-h", "help", GetoptLong::NO_ARGUMENT],          ["-f", "file", GetoptLong::REQUIRED_ARGUMENT],          ["-l", "lines", GetoptLong::OPTIONAL_ARGUMENT]) 

Now we can use a loop to call get repeatedly (see Listing 8.1); we can fake a post-test loop because we are using begin and end anyway. A synonym for get is get_option; there are also iterators named each and each_option, which are identical.

Listing 8.1 Getting Command-Line Options
 filename = nil lines = 0               # Default means no truncating loop do   begin     opt, arg = parser.get     break if not opt     # Only for debugging purposes...     puts (opt + " => " + arg)      case opt        when "-h"          puts "Usage: ..."          break           # Stop processing if -h        when "-f"          filename = arg  # Save the file argument        when "-l"          if arg != ""            lines = arg   # Save lines arg (if given)          else            lines = 100   # Default for truncating          end      end    rescue => err      puts err      break    end end puts "filename = #{ filename} " puts "lines    = #{ lines} " 

Note that get returns nil for a nonexistent option but a null string for a nonexistent argument. This could be a bug.

Note also that we are catching errors here. Four possible exceptions that could be raised are summarized here:


 AmbiguousOption       A long option name seems to have been abbreviated,                       but it isn't unique. InvalidOption         The option is unknown. MissingArgument       The option is missing its argument. NeedlessArgument      The option has an argument when it isn't expected to                       take an argument. 

Errors are normally reported to stderr when they occur, but the quiet= accessor can be set to true to override this.

There are other features of getoptlong, which we haven't discussed here. See the documentation for further details.

There are also other possibilities out there, such as OptionParser, which offer somewhat different functionality and usage. Refer to the Ruby Application Archive for more information.

Working with ARGF

The special global constant ARGF represents the pseudo-file resulting from a concatenation of every file named on the command line. It behaves similar to an IO object in most ways.

When you have a bare input method (without a receiver), you are typically using a method mixed in from the Kernel module. (Examples are gets and readlines.) The actual source of input will default to STDIN if no files are on the command line. If there are files, however, input will be taken from them. End of file will be reached only at the end of the last file.

If you prefer, you can access ARGF explicitly.


 # Copy all files to stdout puts ARGF.readlines 

Perhaps contrary to most people's expectations, end of file is set after each file. The previous code fragment will output all the files. This one will output only the first:


 until ARGF.eof?   puts ARGF.gets end 

Whether this is a bug or a feature, we will leave it up to you to decide. Of course, there are other unexpected surprises that might actually be pleasant. The input isn't simply a stream of bytes flowing through our program; we can actually perform operations such as seek and rewind on ARGF as though it were a real file.

There is a file method associated with ARGF; it returns an IO object corresponding to the file that is currently being processed. As such, the value it returns will change as the files on the command line are processed in sequence.

What if we don't want command-line arguments to be interpreted as files? The solution is to not use the bare (receiverless) call of the input methods. If you want to read standard input, you can use STDIN as the receiver, and all will work as expected.

Working with ARGV

The global constant ARGV represents the list of arguments passed to the Ruby program via the command line. This is essentially an array.


 n = ARGV.size argstr = '"' + ARGV*"," + '"' puts "I was given #{ n}  arguments..." puts "They are: #{ argstr} " puts "Note that ARGV[0] = #{ ARGV[0]} " 

Assume that we invoke this little program with the arguments red green blue on the command line. It then produces this output:


 I was given 3 arguments. They are: "red,green,blue" Note that ARGV[0] = red 

Obviously there is no need for an argument count as in the old days; that information is part of the array.

Another thing that might trip up old-timers is the assignment of the zeroth argument to an actual argument (rather than, for example, the script name). The arguments themselves are zero-based rather than one-based, as in C and the various shell languages.




The Ruby Way
The Ruby Way, Second Edition: Solutions and Techniques in Ruby Programming (2nd Edition)
ISBN: 0672328844
EAN: 2147483647
Year: 2000
Pages: 119
Authors: Hal Fulton

Similar book on Amazon © 2008-2017.
If you may any questions please contact us: