Skip to content

Instantly share code, notes, and snippets.

@rcook
Created July 26, 2013 18:50
Show Gist options
  • Save rcook/6091305 to your computer and use it in GitHub Desktop.
Save rcook/6091305 to your computer and use it in GitHub Desktop.
Illustrates some of the shortcomings of Ruby's OptionParser class: it doesn't support required arguments out of the box and the design of the code that invokes the code block on "on" and "on_tail" methods requires binding to a variable to save options value, when this is really something that would be better achieved by passing the object into t…
#!/usr/bin/env ruby
# See http://stackoverflow.com/questions/1541294/how-do-you-specify-a-required-switch-not-argument-with-ruby-optionparser
require 'optparse'
require 'ostruct'
require 'pathname'
THIS_PATH = Pathname.new(__FILE__).realpath
THIS_DIR = THIS_PATH.dirname
THIS_BASE_NAME = THIS_PATH.basename
class MyOptionParser < OptionParser
attr_reader :required_arg_names
def initialize
@required_arg_names = []
super
end
def on_required(arg_sym, *args, &block)
on *args, &block
@required_arg_names << arg_sym
end
def on(*args, &block)
super *args do |value|
block.call(@options, value)
end
end
def on_tail(*args, &block)
super *args do
block.call(@options)
end
end
def run(args)
@options = OpenStruct.new
cloned_args = args.clone
begin
parse!(cloned_args)
rescue OptionParser::InvalidOption, OptionParser::MissingArgument
puts $!.to_s
puts
puts self
exit 1
end
missing_arg_names = @required_arg_names.select { |arg_name| @options.send(arg_name).nil? }
if !missing_arg_names.empty?
puts "missing required option: #{missing_arg_names.join(', ')}"
puts
puts self
exit 1
end
[@options, cloned_args]
end
end
option_parser = MyOptionParser.new do |parser|
parser.banner = "Usage: #{THIS_BASE_NAME} [options]"
parser.on_required(:merge_version, '--merge-version MERGE-VERSION', 'Specify merge version') do |options, value|
options.merge_version = value
end
parser.on_tail '-h', '--help', 'Show help' do
puts parser
exit
end
parser.on_tail '--version', 'Show version' do
puts OptionParser::Version.join('.')
exit
end
end
options, free_args = option_parser.run(ARGV)
p options
p free_args
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment