<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Segment7: OptionParser Argument Casting</title>
    <link>http://blog.segment7.net/articles/2008/01/05/optionparser-argument-casting</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>The Blog</description>
    <item>
      <title>OptionParser Argument Casting</title>
      <description>&lt;p&gt;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&amp;#8217;s features that I really like is argument casting.&lt;/p&gt;


	&lt;p&gt;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:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;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&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The second argument to opts.on, Float, tells OptionParser to cast the option&amp;#8217;s value to a Float before passing it to the handler block.  When you run this example with a number as the argument, you&amp;#8217;ll see the value in options is a Float:&lt;/p&gt;


&lt;pre&gt;&amp;lt;samp&amp;gt;$ ruby op_test.rb --delay 1
{:delay=&amp;gt;1.0}&amp;lt;/samp&amp;gt;&lt;/pre&gt;

	&lt;p&gt;If you pass a value that can&amp;#8217;t be cast into a Float an OptionParser::InvalidArgument is raised:&lt;/p&gt;


&lt;pre&gt;&amp;lt;samp&amp;gt;$ 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&amp;lt;/samp&amp;gt;&lt;/pre&gt;

	&lt;p&gt;You can rescue this and provide an appropriate help message.&lt;/p&gt;


	&lt;p&gt;At the bottom you&amp;#8217;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.&lt;/p&gt;


	&lt;p&gt;In RubyGems, various arguments are automatically cast to the appropriate objects.  For example, when you specify a version with `gem install&amp;#8212;version &amp;#8217;= 1.2.3&amp;#8217;`, the argument &amp;#8217;= 1.2.3&amp;#8217; is turned into a Gem::Requirement:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;OptionParser.accept Gem::Requirement do |value|
  Gem::Requirement.new value
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Gem::Requirement.new knows how to cast a String and raises an exception if it can&amp;#8217;t, so we delegate to it to do the work.&lt;/p&gt;


	&lt;p&gt;If you only want to have a specially formatted string, you can provide a regular expression instead.  The DecimalInteger cast is defined like this:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;DecimalInteger = /\A[-+]?\d+(?:_\d+)*/io
accept(DecimalInteger) {|s,| s.to_i if s}&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;So the pattern referenced by the name is used to validate the argument.&lt;/p&gt;


	&lt;p&gt;You can also provide a pattern as the second argument.  The Float cast is defined like this:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;floatpat = %r"\A[-+]?[...]"io
accept(Float, floatpat) {|s,| s.to_f if s}&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Notice that for each of these, you still need to turn the string argument into the appropriate object.&lt;/p&gt;


&lt;h4&gt;OptionParser Built-in Casts&lt;/h4&gt;

	&lt;p&gt;With no extra requires, OptionParser can cast the following arguments for you:&lt;/p&gt;


&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Name&lt;th&gt;Requirements&lt;th&gt;Cast to
&lt;tr&gt;&lt;td&gt;Object, NilClass&lt;td&gt;Any string, no conversion&lt;td&gt;String
&lt;tr&gt;&lt;td&gt;String&lt;td&gt;Any non-empty string&lt;td&gt;String
&lt;tr&gt;&lt;td&gt;Integer&lt;td&gt;Binary (0b), octal (0), hexadecimal (0x), or decimal number&lt;td&gt;Integer
&lt;tr&gt;&lt;td&gt;Float&lt;td&gt;Floating point number&lt;td&gt;Float
&lt;tr&gt;&lt;td&gt;Numeric&lt;td&gt;Generic number format&lt;td&gt;Float for floats, Integer for integers
&lt;tr&gt;&lt;td&gt;OptionParser::DecimalInteger&lt;td&gt;Decimal integer&lt;td&gt;Integer
&lt;tr&gt;&lt;td&gt;OptionParser::OctalInteger&lt;td&gt;Octal, binary or hexadecimal number&lt;td&gt;Integer
&lt;tr&gt;&lt;td&gt;OptionParser::DecimalNumeric&lt;td&gt;Decimal number&lt;td&gt;Integer or Float
&lt;tr&gt;&lt;td&gt;TrueClass&lt;td&gt;+, -, yes, no, true, false, nil&lt;td&gt;true or false, defaults to true
&lt;tr&gt;&lt;td&gt;FalseClass&lt;td&gt;+, -, yes, no, true, false, nil&lt;td&gt;true or false, defaults to false
&lt;tr&gt;&lt;td&gt;Array&lt;td&gt;Comma-separated list&lt;td&gt;Array of Strings
&lt;tr&gt;&lt;td&gt;Regexp&lt;td&gt;Regular expression with options&lt;td&gt;Regexp
&lt;/table&gt;

	&lt;p&gt;If you require &amp;#8216;optparse/date&amp;#8217;:&lt;/p&gt;


&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Name&lt;th&gt;Requirements&lt;th&gt;Cast to
&lt;tr&gt;&lt;td&gt;DateTime&lt;td&gt;Anything handled by DateTime.parse&lt;td&gt;DateTime
&lt;tr&gt;&lt;td&gt;Date&lt;td&gt;Anything handled by Date.parse&lt;td&gt;Date
&lt;/table&gt;

	&lt;p&gt;If you require &amp;#8216;optparse/shellwords&amp;#8217;:&lt;/p&gt;


&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Name&lt;th&gt;Requirements&lt;th&gt;Cast to
&lt;tr&gt;&lt;td&gt;Shellwords&lt;td&gt;Anything handled by Shellwords.shellwords&lt;td&gt;Array of Strings
&lt;/table&gt;

	&lt;p&gt;If you require &amp;#8216;optparse/time&amp;#8217;:&lt;/p&gt;


&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Name&lt;th&gt;Requirements&lt;th&gt;Cast to
&lt;tr&gt;&lt;td&gt;Time&lt;td&gt;Anything handled by Time.parse&lt;td&gt;Time
&lt;/table&gt;

	&lt;p&gt;If you require &amp;#8216;optparse/uri&amp;#8217;:&lt;/p&gt;


&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Name&lt;th&gt;Requirements&lt;th&gt;Cast to
&lt;tr&gt;&lt;td&gt;&lt;span class="caps"&gt;URI&lt;/span&gt;&lt;td&gt;Anything handled by &lt;span class="caps"&gt;URI&lt;/span&gt;.parse&lt;td&gt;&lt;span class="caps"&gt;URI&lt;/span&gt;
&lt;/table&gt;
</description>
      <pubDate>Sat, 05 Jan 2008 20:56:03 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:fd44eb79-93fc-46c9-8065-cb3e2207e89c</guid>
      <author>drbrain@segment7.net (Eric Hodel)</author>
      <link>http://blog.segment7.net/articles/2008/01/05/optionparser-argument-casting</link>
      <category>Ruby</category>
    </item>
    <item>
      <title>"OptionParser Argument Casting" by Eric Hodel</title>
      <description>&lt;p&gt;There&amp;#8217;s also value completion, but I don&amp;#8217;t use that yet.&lt;/p&gt;</description>
      <pubDate>Sat, 05 Jan 2008 22:49:21 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:1681b5b2-0634-4f87-80b7-60f4e9416c6b</guid>
      <link>http://blog.segment7.net/articles/2008/01/05/optionparser-argument-casting#comment-847</link>
    </item>
    <item>
      <title>"OptionParser Argument Casting" by Dr Nic</title>
      <description>&lt;p&gt;Sweet. I did not know about value casting.&lt;/p&gt;</description>
      <pubDate>Sat, 05 Jan 2008 21:31:31 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:caeba580-2a29-43cc-8817-7478bd4baa04</guid>
      <link>http://blog.segment7.net/articles/2008/01/05/optionparser-argument-casting#comment-846</link>
    </item>
  </channel>
</rss>
