Created
February 8, 2015 09:27
-
-
Save JoshCheek/7adc25a46e735510558d to your computer and use it in GitHub Desktop.
Why I will not use Ruby's OptionParser
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Have to hijack the global environment, b/c that's how invasive it is! | |
def self.wtf | |
to_return = {exception: nil, stdout: nil, stderr: nil} | |
require 'stringio' | |
$stdout = StringIO.new | |
$stderr = StringIO.new | |
to_return[:returned] = yield | |
rescue Exception | |
to_return[:exception] = $! | |
ensure | |
to_return[:stdout] = $stdout.string | |
to_return[:stderr] = $stderr.string | |
$stdout = STDOUT | |
$stderr = STDERR | |
return to_return | |
end | |
require 'optparse/time' | |
parser = OptionParser.new do |o| | |
o.version = '1.2.3' | |
o.on '-x' | |
end | |
# Parsing has the side effect of printing directly to stdout | |
wtf { parser.parse ['-v'] }[:stdout] # => "program 1.2.3\n" | |
wtf { parser.parse ['--version'] }[:stdout] # => "program 1.2.3\n" | |
wtf { parser.parse ['-h'] }[:stdout] # => "Usage: program [options]\n -x\n" | |
wtf { parser.parse ['--help'] }[:stdout] # => "Usage: program [options]\n -x\n" | |
# Parsing some arguments might cause your program to suddenly quit... | |
wtf { parser.parse ['-v'] }[:exception] # => #<SystemExit: exit> | |
wtf { parser.parse ['--version'] }[:exception] # => #<SystemExit: exit> | |
wtf { parser.parse ['-h'] }[:exception] # => #<SystemExit: exit> | |
wtf { parser.parse ['--help'] }[:exception] # => #<SystemExit: exit> | |
# Note that while it takes flags for help and version, it does not list these | |
wtf { parser.parse ['-h'] }[:stdout] # => "Usage: program [options]\n -x\n" | |
# Normal parsing seems to do nothing (removes parsed vars, but doesn't return anything useful, and doesn't change any state) | |
pre_inspect = parser.inspect # => "#<OptionParser:0x007f8e1c8d27a8 @stack=[#<OptionParser::List:0x007f8e1c04ab08 @atype={Object=>[/.*/m, #<Proc:0x007f8e1c04a090@/Users/josh/.rubies/ruby-2.1.2/lib/ruby/2.1.0/optparse.rb:1618>], NilClass=>[/.*/m, #<Proc:0x007f8e1c049fc8@/Users/josh/.rubies/ruby-2.1.2/lib/ruby/2.1.0/optparse.rb:1620>], String=>[/.+/m, #<Proc:0x007f8e1c049f00@/Users/josh/.rubies/ruby-2.1.2/lib/ruby/2.1.0/optpa... | |
parser.parse ['arg', '-x'] # => ["arg"] | |
pre_inspect == parser.inspect # => true | |
# Guerilla patches ARGV | |
ARGV.getopts("ab:", "foo", "bar:") # => {"a"=>false, "b"=>nil, "foo"=>false, "bar"=>nil} | |
# But only ARGV, so if you wanted to use this, you'd have to also have the global dep | |
[].getopts("ab:", "foo", "bar:") rescue $! # => #<NoMethodError: undefined method `getopts' for []:Array> | |
# Parses options that weren't specified and don't make sense | |
# and prints directly to stderr about it | |
wtf { OptionParser.new.parse ['-v'] }[:stderr] # => "program: version unknown\n" | |
# Doesn't complete on its version or help flags, also, more printing to stdout | |
wtf { parser.parse ['--*-completion-bash', '-'] }[:stdout] # => "-x\n" | |
# Raises exceptions instead of setting errors | |
wtf { parser.parse! ['-i'] } # => {:exception=>#<OptionParser::InvalidOption: -i>, :stdout=>"", :stderr=>""} | |
# Parses time very poorly | |
to_parse = "...take one down, pass it around, 10 bottles of beer on the wall!" | |
parsed = nil | |
parser.on('-t T', Time) { |t| parsed = t }.parse ['-t', to_parse] # => [] | |
parsed # => 2015-02-10 00:00:00 -0700 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Wow. This is a fabulous explanation of what's wrong with Ruby's default option parser.
Now I need to go check Trollop and see how many of these it does :-)
Thanks!