From eb65befab2423713471e7777e6b3d02e0766ec5a Mon Sep 17 00:00:00 2001 From: Joel McCracken Date: Sun, 6 Oct 2013 13:19:56 -0400 Subject: [PATCH] Current work on improving OptionParser documentation --- lib/optparse.rb | 295 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 218 insertions(+), 77 deletions(-) diff --git a/lib/optparse.rb b/lib/optparse.rb index 4ec891e..992dd8b 100644 --- a/lib/optparse.rb +++ b/lib/optparse.rb @@ -117,8 +117,120 @@ # #=> # # Usage: example.rb [options] # # -n, --name=NAME Name to say hello to -# # -h, --help Prints this help# +# # -h, --help Prints this help # +# === Required Arugments +# +# For options that require an argument, option specification strings may include an +# option name in all caps. If an option is used without the required argument, +# an exception will be raised. +# require 'optparse' +# +# options = {} +# OptionParser.new do |parser| +# parser.on("-r", "--require LIBRARY", +# "Require the LIBRARY before executing your script") do |lib| +# puts "You required #{lib}!" +# end +# end.parse! +# +# Used: +# +# bash-3.2$ ruby optparse-test.rb -r +# optparse-test.rb:9:in `
': missing argument: -r (OptionParser::MissingArgument) +# bash-3.2$ ruby optparse-test.rb -r my-library +# You required my-library! +# +# === Type Coercion +# +# OptionParser supports the ability to coerce command line arguments +# into objects for us. +# +# OptionParser comes with a few ready-to-use kinds of type +# coercion. They are: +# +# - Date -- Anything accepted by +Date.parse+ +# - DateTime -- Anything accepted by +DateTime.parse+ +# - Time -- Anyting accepted by +Time.httpdate+ or +Time.parse+ +# - URI -- Anything accepted by +URI.parse+ +# - Shellwords -- Anything accepted by +Shellwords.shellwords+ +# - String -- Any non-empty string +# - Integer -- Any integer. Will convert octal. (e.g. 124, -3, 040) +# - Float -- Any float. (e.g. 10, 3.14, -100E+13) +# - Numeric -- Any integer, float, or rational (1, 3.4, 1/3) +# - DecimalInteger -- Like +Integer+, but no octal format. +# - OctalInteger -- Like +Integer+, but no decimal format. +# - DecimalNumeric -- Decimal integer or float. +# - TrueClass -- Accepts '+, yes, true, -, no, false' and +# defaults as +true+ +# - FalseClass -- Same as +TrueClass+, but defaults to +false+ +# - Array -- Strings separated by ',' (e.g. 1,2,3) +# - Regexp -- Regular expressions. Also includes options. +# +# We can also add our own coercions, which we will cover soon. +# +# ==== Using Built-in Conversions +# +# As an example, the built-in +Time+ conversion is used. The other built-in +# conversions behave in in the same way. +# OptionParser will attempt to parse the argument +# as a +Time+. If it succeeeds, that time will be passed to the +# handler block. Otherwise, an exception will be raised. +# +# require 'optparse' +# require 'optparse/time' +# OptionParser.new do |parser| +# parser.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time| +# p time +# end +# end.parse! +# +# Used: +# bash-3.2$ ruby optparse-test.rb -t nonsense +# ... invalid argument: -t nonsense (OptionParser::InvalidArgument) +# from ... time.rb:5:in `block in ' +# from optparse-test.rb:31:in `
' +# bash-3.2$ ruby optparse-test.rb -t 10-11-12 +# 2010-11-12 00:00:00 -0500 +# bash-3.2$ ruby optparse-test.rb -t 9:30 +# 2014-08-13 09:30:00 -0400 +# +# ==== Creating Custom Conversions +# +# The +accept+ method on OptionParser may be used to create converters. +# It specifies which conversion block to call whenever a class is specified. +# The example below uses it to fetch a +User+ object before the +on+ handler receives it. +# +# require 'optparse' +# +# User = Struct.new(:id, :name) +# +# def find_user id +# not_found = ->{ raise "No User Found for id #{id}" } +# [ User.new(1, "Sam"), +# User.new(2, "Gandalf") ].find(not_found) do |u| +# u.id == id +# end +# end +# +# op = OptionParser.new +# op.accept(User) do |user_id| +# find_user user_id.to_i +# end +# +# op.on("--user ID", User) do |user| +# puts user +# end +# +# op.parse! +# +# output: +# bash-3.2$ ruby optparse-test.rb --user 1 +# # +# bash-3.2$ ruby optparse-test.rb --user 2 +# # +# bash-3.2$ ruby optparse-test.rb --user 3 +# optparse-test.rb:15:in `block in find_user': No User Found for id 3 (RuntimeError) # === Complete example # # The following example is a complete Ruby program. You can run it and see the @@ -131,108 +243,137 @@ # require 'pp' # # class OptparseExample -# # CODES = %w[iso-2022-jp shift_jis euc-jp utf8 binary] # CODE_ALIASES = { "jis" => "iso-2022-jp", "sjis" => "shift_jis" } # +# class ScriptOptions +# attr_accessor :library, :inplace, :encoding, :transfer_type, +# :verbose +# def initialize +# self.library = [] +# self.inplace = false +# self.encoding = "utf8" +# self.transfer_type = :auto +# self.verbose = false +# end +# end +# # # # # Return a structure describing the options. # # # def self.parse(args) -# # The options specified on the command line will be collected in *options*. -# # We set default values here. -# options = OpenStruct.new -# options.library = [] -# options.inplace = false -# options.encoding = "utf8" -# options.transfer_type = :auto -# options.verbose = false +# # The options specified on the command line will be collected in +# # *options*. # -# opt_parser = OptionParser.new do |opts| -# opts.banner = "Usage: example.rb [options]" +# @options = ScriptOptions.new +# option_parser.parse!(args) +# @options +# end # -# opts.separator "" -# opts.separator "Specific options:" +# attr_reader :parser, :options # -# # Mandatory argument. -# opts.on("-r", "--require LIBRARY", -# "Require the LIBRARY before executing your script") do |lib| -# options.library << lib -# end +# def option_parser +# @parser ||= OptionParser.new do |parser| +# parser.banner = "Usage: example.rb [options]" +# parser.separator "" +# parser.separator "Specific options:" # -# # Optional argument; multi-line description. -# opts.on("-i", "--inplace [EXTENSION]", -# "Edit ARGV files in place", -# " (make backup if EXTENSION supplied)") do |ext| -# options.inplace = true -# options.extension = ext || '' -# options.extension.sub!(/\A\.?(?=.)/, ".") # Ensure extension begins with dot. -# end +# # add additional options +# perform_inplace_option +# delay_execution_option +# execute_at_time_option +# specify_record_separator_option +# list_example_option +# specify_encoding_option +# optional_option_argument_with_keyword_completion_option +# boolean_verbose_option # -# # Cast 'delay' argument to a Float. -# opts.on("--delay N", Float, "Delay N seconds before executing") do |n| -# options.delay = n +# parser.separator "" +# parser.separator "Common options:" +# # No argument, shows at tail. This will print an options summary. +# # Try it and see! +# parser.on_tail("-h", "--help", "Show this message") do +# puts parser +# exit # end -# -# # Cast 'time' argument to a Time object. -# opts.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time| -# options.time = time +# # Another typical switch to print the version. +# parser.on_tail("--version", "Show version") do +# puts ::Version.join('.') +# exit # end +# end +# end # -# # Cast to octal integer. -# opts.on("-F", "--irs [OCTAL]", OptionParser::OctalInteger, -# "Specify record separator (default \\0)") do |rs| -# options.record_separator = rs -# end +# def perform_inplace_option +# # Specifies an optional option argument +# parser.on("-i", "--inplace [EXTENSION]", +# "Edit ARGV files in place", +# " (make backup if EXTENSION supplied)") do |ext| +# options.inplace = true +# options.extension = ext || '' +# options.extension.sub!(/\A\.?(?=.)/, ".") # Ensure extension begins with dot. +# end +# end # -# # List of arguments. -# opts.on("--list x,y,z", Array, "Example 'list' of arguments") do |list| -# options.list = list -# end +# def delay_execution_option +# # Cast 'delay' argument to a Float. +# parser.on("--delay N", Float, "Delay N seconds before executing") do |n| +# options.delay = n +# end +# end # -# # Keyword completion. We are specifying a specific set of arguments (CODES -# # and CODE_ALIASES - notice the latter is a Hash), and the user may provide -# # the shortest unambiguous text. -# code_list = (CODE_ALIASES.keys + CODES).join(',') -# opts.on("--code CODE", CODES, CODE_ALIASES, "Select encoding", -# " (#{code_list})") do |encoding| -# options.encoding = encoding -# end +# def execute_at_time_option +# # Cast 'time' argument to a Time object. +# parser.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time| +# options.time = time +# end +# end # -# # Optional argument with keyword completion. -# opts.on("--type [TYPE]", [:text, :binary, :auto], -# "Select transfer type (text, binary, auto)") do |t| -# options.transfer_type = t -# end # -# # Boolean switch. -# opts.on("-v", "--[no-]verbose", "Run verbosely") do |v| -# options.verbose = v -# end +# def specify_record_separator_option +# # Cast to octal integer. +# parser.on("-F", "--irs [OCTAL]", OptionParser::OctalInteger, +# "Specify record separator (default \\0)") do |rs| +# options.record_separator = rs +# end +# end # -# opts.separator "" -# opts.separator "Common options:" +# def list_example_option +# # List of arguments. +# parser.on("--list x,y,z", Array, "Example 'list' of arguments") do |list| +# options.list = list +# end +# end # -# # No argument, shows at tail. This will print an options summary. -# # Try it and see! -# opts.on_tail("-h", "--help", "Show this message") do -# puts opts -# exit -# end +# def specify_encoding_option +# # Keyword completion. We are specifying a specific set of arguments (CODES +# # and CODE_ALIASES - notice the latter is a Hash), and the user may provide +# # the shortest unambiguous text. +# code_list = (CODE_ALIASES.keys + CODES).join(',') +# parser.on("--code CODE", CODES, CODE_ALIASES, "Select encoding", +# " (#{code_list})") do |encoding| +# options.encoding = encoding +# end +# end # -# # Another typical switch to print the version. -# opts.on_tail("--version", "Show version") do -# puts ::Version.join('.') -# exit -# end +# +# def optional_option_argument_with_keyword_completion_option +# # Optional '--type' option argument with keyword completion. +# parser.on("--type [TYPE]", [:text, :binary, :auto], +# "Select transfer type (text, binary, auto)") do |t| +# options.transfer_type = t # end +# end # -# opt_parser.parse!(args) -# options -# end # parse() # -# end # class OptparseExample +# def boolean_verbose_option +# # Boolean switch. +# parser.on("-v", "--[no-]verbose", "Run verbosely") do |v| +# options.verbose = v +# end +# end # +# end # class OptparseExample # options = OptparseExample.parse(ARGV) # pp options # pp ARGV -- 2.1.0