Skip navigation

I often forget some of the more semi-complicated ways of doing things in the programs I write.  Typically I’ll just cut and paste from a previous bit of code I’ve written and adapt that bit to what I’m doing (essentially, filing the serial numbers off the code).  If I don’t have example code handy, I’ll go to Google and see what examples are out there for whatever I’m trying to do.  This works pretty well since I’m rarely trying to tread new ground and there are a lot of folks out there on the internet who are much smarter/more experienced than me.\r \r One time when this did not work happened recently.  I was doing a Ruby script and wanted to use command-line options.  All of the examples I saw had something similar to the following:\r

require 'optparse'\r \r options = {}\r OptionParser.new do |opts|\r opts.banner = "Usage: opts.rb [options]"\r opts.on("-f", "--file", "File name") do |f|\r options[:file] = f\r end\r opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|\r options[:verbose] = v\r end\r end.parse!\r p RUBY_VERSION\r p options\r p ARGV

\r This worked fine for options without arguments, but when I tried to pass in an argument, something similar to the following happened:\r

hostname> ./opts.rb -f foo -v\r "1.8.7"\r {:file=>true, :verbose=>true}\r ["foo"]

\r The value I wanted to pass to ‘-f’ was ending up as a generic argument.  Somehow I needed to grab that and shove it into the option[:file] variable.\r \r Here’s the updated code:\r \r  \r

require 'optparse'\r \r options = {}\r OptionParser.new do |opts|\r opts.banner = "Usage: opts.rb [options]"\r opts.on("-f", "--file", "File name") do |v|\r options[:file] = ARGV.shift\r end\r opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|\r options[:verbose] = v\r end\r end.parse!\r p RUBY_VERSION\r p options\r p ARGV

\r And here’s what it looks like when you run this version:\r

hostname> ./opts.rb -f foo -v\r "1.8.7"\r {:file=>"foo", :verbose=>true}\r []

\r Mission accomplished!  This may have changed in Ruby 1.9.3 and the previous version works as expected, but I’m stuck on old, slow-to-move production systems so this is the way I’ll be using going forward.  If someone notices an issue with how this is implemented, please let me know along with a proper way to accomplish what I’m trying to do and I’ll be happy to check it out (and update this post to that effect).