OptionParser Argument Casting
drbrain |
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:
$ ruby op_test.rb --delay 1
{:delay=>1.0}
If you pass a value that can't be cast into a Float an OptionParser::InvalidArgument is raised:
$ 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
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 | Integer |
| Float | Floating point number | Float |
| Numeric | Generic number format | Float for floats, Integer for integers |
| OptionParser::DecimalInteger | Decimal integer | Integer |
| OptionParser::OctalInteger | Octal, binary or hexadecimal number | Integer |
| OptionParser::DecimalNumeric | Decimal number | Integer or Float |
| TrueClass | +, -, yes, no, true, false, nil | true or false, defaults to true |
| FalseClass | +, -, yes, no, true, false, nil | true or false, defaults to false |
| Array | Comma-separated list | Array of Strings |
| Regexp | Regular expression with options | Regexp |
If you require 'optparse/date':
| Name | Requirements | Cast to |
|---|---|---|
| DateTime | Anything handled by DateTime.parse | DateTime |
| Date | Anything handled by Date.parse | Date |
If you require 'optparse/shellwords':
| Name | Requirements | Cast to |
|---|---|---|
| Shellwords | Anything handled by Shellwords.shellwords | Array of Strings |
If you require 'optparse/time':
| Name | Requirements | Cast to |
|---|---|---|
| Time | Anything handled by Time.parse | Time |
If you require 'optparse/uri':
| Name | Requirements | Cast to |
|---|---|---|
| URI | Anything handled by URI.parse | URI |
Comments are disabled


