This post originated from an RSS feed registered with Ruby Buzz
by Eric Hodel.
Original Post: OptionParser Argument Casting
Feed Title: Segment7
Feed URL: http://blog.segment7.net/articles.rss
Feed Description: Posts about and around Ruby, MetaRuby, ruby2c, ZenTest and work at The Robot Co-op.
OptionParser is a command-line argument parsing library for Ruby that provides several really nice features. Using OptionParser tends to be verbose, but it is also very flexible. One of it’s features that I really like is argument casting.
Argument casting allows you to validate a command-line option and convert it from the user-supplied String into whichever object you like. The ri for OptionParser has an example similar to this one for casting a floating-point argument into a Float value:
require 'optparse'
options = {}
opts = OptionParser.new do |opts|
# Cast 'delay' argument to a Float.
opts.on("--delay N", Float,
"Delay N seconds before executing") do |n|
options[:delay] = n
end
end
opts.parse! ARGV
p options
The second argument to opts.on, Float, tells OptionParser to cast the option’s value to a Float before passing it to the handler block. When you run this example with a number as the argument, you’ll see the value in options is a Float:
If you pass a value that can’t be cast into a Float an OptionParser::InvalidArgument is raised:
<samp>$ ruby op_test.rb --delay X
[...]/optparse.rb:454:in `parse': invalid argument: --delay X (OptionParser::InvalidArgument)
[...]
from [...]/optparse.rb:1353:in `parse!'
from op_test.rb:13</samp>
You can rescue this and provide an appropriate help message.
At the bottom you’ll find some tables of the various casts that are built-in to OptionParser. If none of those do what you want, writing your own is very easy.
In RubyGems, various arguments are automatically cast to the appropriate objects. For example, when you specify a version with `gem install—version ’= 1.2.3’`, the argument ’= 1.2.3’ is turned into a Gem::Requirement:
OptionParser.accept Gem::Requirement do |value|
Gem::Requirement.new value
end
Gem::Requirement.new knows how to cast a String and raises an exception if it can’t, so we delegate to it to do the work.
If you only want to have a specially formatted string, you can provide a regular expression instead. The DecimalInteger cast is defined like this:
DecimalInteger = /\A[-+]?\d+(?:_\d+)*/io
accept(DecimalInteger) {|s,| s.to_i if s}
So the pattern referenced by the name is used to validate the argument.
You can also provide a pattern as the second argument. The Float cast is defined like this:
floatpat = %r"\A[-+]?[...]"io
accept(Float, floatpat) {|s,| s.to_f if s}
Notice that for each of these, you still need to turn the string argument into the appropriate object.
OptionParser Built-in Casts
With no extra requires, OptionParser can cast the following arguments for you:
Name
Requirements
Cast to
Object, NilClass
Any string, no conversion
String
String
Any non-empty string
String
Integer
Binary (0b), octal (0), hexadecimal (0x), or decimal number