Class: Boson::OptionParser
- Inherits:
-
Object
- Object
- Boson::OptionParser
- Includes:
- API
- Defined in:
- lib/boson/option_parser.rb
Overview
This class concisely defines commandline options that when parsed produce a Hash of option keys and values. Additional points:
-
Setting option values should follow conventions in *nix environments. See examples below.
-
By default, there are 5 option types, each which produce different objects for option values.
-
The default option types can produce objects for one or more of the following Ruby classes: String, Integer, Float, Array, Hash, FalseClass, TrueClass.
-
Users can define their own option types which create objects for any Ruby class. See Options.
-
Each option type can have attributes to enable more features (see OptionParser.new).
-
When options are parsed by parse(), an indifferent access hash is returned.
-
Options are also called switches, parameters, flags etc.
-
Option parsing stops when it comes across a ‘–’.
Default option types:
- :boolean
-
This option has no passed value. To toogle a boolean, prepend with ‘–no-’. Multiple booleans can be joined together.
'--debug' -> {:debug=>true} '--no-debug' -> {:debug=>false} '--no-d' -> {:debug=>false} '-d -f -t' same as '-dft'
- :string
-
Sets values by separating name from value with space or ‘=’.
'--color red' -> {:color=>'red'} '--color=red' -> {:color=>'red'} '--color "gotta love spaces"' -> {:color=>'gotta love spaces'}
- :numeric
-
Sets values as :string does or by appending number right after aliased name. Shortened form can be appended to joined booleans.
'-n3' -> {:num=>3} '-dn3' -> {:debug=>true, :num=>3}
- :array
-
Sets values as :string does. Multiple values are split by a configurable character Default is ‘,’ (see OptionParser.new). Passing ‘*’ refers to all known :values.
'--fields 1,2,3' -> {:fields=>['1','2','3']} '--fields *' -> {:fields=>['1','2','3']}
- :hash
-
Sets values as :string does. Key-value pairs are split by ‘:’ and pairs are split by a configurable character (default ‘,’). Multiple keys can be joined to one value. Passing ‘*’ as a key refers to all known :keys.
'--fields a:b,c:d' -> {:fields=>{'a'=>'b', 'c'=>'d'} } '--fields a,b:d' -> {:fields=>{'a'=>'d', 'b'=>'d'} } '--fields *:d' -> {:fields=>{'a'=>'d', 'b'=>'d', 'c'=>'d'} }
This is a modified version of Yehuda Katz’s Thor::Options class which is a modified version of Daniel Berger’s Getopt::Long class (Ruby license).
Defined Under Namespace
Constant Summary collapse
- NUMERIC =
/(\d*\.\d+|\d+)/
- LONG_RE =
/^(--\w+[-\w+]*)$/
- SHORT_RE =
/^(-[a-zA-Z])$/i
- EQ_RE =
/^(--\w+[-\w+]*|-[a-zA-Z])=(.*)$/i
- SHORT_SQ_RE =
Allow either -x -v or -xv style for single char args
/^-([a-zA-Z]{2,})$/i
- SHORT_NUM =
/^(-[a-zA-Z])#{NUMERIC}$/i
- STOP_STRINGS =
%w{-- -}
Instance Attribute Summary collapse
-
#leading_non_opts ⇒ Object
readonly
Returns the value of attribute leading_non_opts.
-
#opt_aliases ⇒ Object
readonly
Returns the value of attribute opt_aliases.
-
#trailing_non_opts ⇒ Object
readonly
Returns the value of attribute trailing_non_opts.
Instance Method Summary collapse
-
#aliases ⇒ Object
List of option aliases.
-
#current_attributes ⇒ Object
Hash of option attributes for the currently parsed option.
-
#dasherize(str) ⇒ Object
Adds dashes to an option name i.e.
-
#default_usage(opt, val) ⇒ Object
Helper method to generate usage.
- #delete_leading_invalid_opts ⇒ Object
-
#formatted_usage ⇒ Object
(also: #to_s)
Generates one-line usage of all options.
-
#indifferent_hash ⇒ Object
Creates a Hash with indifferent access.
-
#initialize(opts) ⇒ OptionParser
constructor
Takes a hash of options.
-
#names ⇒ Object
List of option names.
-
#non_opts ⇒ Object
Array of arguments left after defined options have been parsed out by parse.
-
#option_attributes ⇒ Object
Hash of option names mapped to hash of its external attributes.
-
#parse(args, flags = {}) ⇒ Object
Parses an array of arguments for defined options to return an indifferent access hash.
-
#print_usage_table(options = {}) ⇒ Object
More verbose option help in the form of a table.
-
#types ⇒ Object
List of option types.
-
#undasherize(str) ⇒ Object
Removes dashes from a dashed option i.e.
Methods included from API
#get_fields_and_options, #render_table
Constructor Details
#initialize(opts) ⇒ OptionParser
Takes a hash of options. Each option, a key-value pair, must provide the option’s name and type. Names longer than one character are accessed with ‘–’ while one character names are accessed with ‘-’. Names can be symbols, strings or even dasherized strings:
Boson::OptionParser.new :debug=>:boolean, 'level'=>:numeric,
'--fields'=>:array
Options can have default values and implicit types simply by changing the option type for the default value:
Boson::OptionParser.new :debug=>true, 'level'=>3.1, :fields=>%w{f1 f2}
By default every option name longer than one character is given an alias, the first character from its name. For example, the –fields option has -f as its alias. You can override the default alias by providing your own option aliases as an array in the option’s key.
Boson::OptionParser.new [:debug, :damnit, :D]=>true
Note that aliases are accessed the same way as option names. For the above, –debug, –damnit and -D all refer to the same option.
Options can have additional attributes by passing a hash to the option value instead of a type or default:
Boson::OptionParser.new :fields=>{:type=>:array, :values=>%w{f1 f2 f3},
:enum=>false}
These attributes are available when an option is parsed via current_attributes(). Here are the available option attributes for the default option types:
- :type
-
This or :default is required. Available types are :string, :boolean, :array, :numeric, :hash.
- :default
-
This or :type is required. This is the default value an option has when not passed.
- :bool_default
-
This is the value an option has when passed as a boolean. However, by enabling this an option can only have explicit values with ‘=’ i.e. ‘–index=alias’ and no ‘–index alias’. If this value is a string, it is parsed as any option value would be. Otherwise, the value is passed directly without parsing.
- :required
-
Boolean indicating if option is required. Option parses raises error if value not given. Default is false.
- :alias
-
Alternative way to define option aliases with an option name or an array of them. Useful in yaml files. Setting to false will prevent creating an automatic alias.
- :values
-
An array of values an option can have. Available for :array and :string options. Values here can be aliased by typing a unique string it starts with or underscore aliasing (see Util.underscore_search). For example, for values foo, odd and obnoxiously_long, f refers to foo, od to odd and o_l to obnoxiously_long.
- :enum
-
Boolean indicating if an option enforces values in :values or :keys. Default is true. For :array, :hash and :string options.
- :split
-
For :array and :hash options. A string or regular expression on which an array value splits to produce an array of values. Default is ‘,’.
- :keys
-
:hash option only. An array of values a hash option’s keys can
have. Keys can be aliased just like :values.
- :default_keys
-
For :hash option only. Default keys to assume when only a value is given. Multiple keys can be joined by the :split character. Defaults to first key of :keys if :keys given.
- :regexp
-
For :array option with a :values attribute. Boolean indicating that each option value does a regular expression search of :values. If there are values that match, they replace the original option value. If none, then the original option value is used.
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/boson/option_parser.rb', line 139 def initialize(opts) @defaults = {} @opt_aliases = {} @leading_non_opts, @trailing_non_opts = [], [] # build hash of dashed options to option types # type can be a hash of opt attributes, a default value or a type symbol @opt_types = opts.inject({}) do |mem, (name, type)| name, *aliases = name if name.is_a?(Array) name = name.to_s # we need both nice and dasherized form of option name if name.index('-') == 0 nice_name = undasherize name else nice_name = name name = dasherize name end # store for later @opt_aliases[nice_name] = aliases || [] if type.is_a?(Hash) @option_attributes ||= {} @option_attributes[nice_name] = type @opt_aliases[nice_name] = Array(type[:alias]) if type.key?(:alias) @defaults[nice_name] = type[:default] if type[:default] if (type.key?(:values) || type.key?(:keys)) && !type.key?(:enum) @option_attributes[nice_name][:enum] = true end if type.key?(:keys) @option_attributes[nice_name][:default_keys] ||= type[:keys][0] end type = type[:type] || (!type[:default].nil? ? determine_option_type(type[:default]) : :boolean) end # set defaults case type when TrueClass then @defaults[nice_name] = true when FalseClass then @defaults[nice_name] = false else @defaults[nice_name] = type unless type.is_a?(Symbol) end mem[name] = !type.nil? ? determine_option_type(type) : type mem end # generate hash of dashed aliases to dashed options @opt_aliases = @opt_aliases.sort.inject({}) {|h, (nice_name, aliases)| name = dasherize nice_name # allow for aliases as symbols aliases.map! {|e| e.to_s.index('-') == 0 || e == false ? e : dasherize(e.to_s) } if aliases.empty? and nice_name.length > 1 opt_alias = nice_name[0,1] opt_alias = h.key?("-"+opt_alias) ? "-"+opt_alias.capitalize : "-"+opt_alias h[opt_alias] ||= name unless @opt_types.key?(opt_alias) else aliases.each {|e| h[e] = name if !@opt_types.key?(e) && e != false } end h } end |
Instance Attribute Details
#leading_non_opts ⇒ Object (readonly)
Returns the value of attribute leading_non_opts.
62 63 64 |
# File 'lib/boson/option_parser.rb', line 62 def leading_non_opts @leading_non_opts end |
#opt_aliases ⇒ Object (readonly)
Returns the value of attribute opt_aliases.
62 63 64 |
# File 'lib/boson/option_parser.rb', line 62 def opt_aliases @opt_aliases end |
#trailing_non_opts ⇒ Object (readonly)
Returns the value of attribute trailing_non_opts.
62 63 64 |
# File 'lib/boson/option_parser.rb', line 62 def trailing_non_opts @trailing_non_opts end |
Instance Method Details
#aliases ⇒ Object
List of option aliases
325 326 327 |
# File 'lib/boson/option_parser.rb', line 325 def aliases @opt_aliases.keys.map {|e| undasherize e } end |
#current_attributes ⇒ Object
Hash of option attributes for the currently parsed option. Any hash keys passed to an option are available here. This means that an option type can have any user-defined attributes available during option parsing and object creation.
300 301 302 |
# File 'lib/boson/option_parser.rb', line 300 def current_attributes @option_attributes && @option_attributes[@current_option] || {} end |
#dasherize(str) ⇒ Object
Adds dashes to an option name i.e. ‘date’ -> ‘–date’ and ‘d’ -> ‘-d’.
310 311 312 |
# File 'lib/boson/option_parser.rb', line 310 def dasherize(str) (str.length > 1 ? "--" : "-") + str end |
#default_usage(opt, val) ⇒ Object
Helper method to generate usage. Takes a dashed option and a string value indicating an option value’s format.
252 253 254 |
# File 'lib/boson/option_parser.rb', line 252 def default_usage(opt, val) opt + "=" + (@defaults[undasherize(opt)] || val).to_s end |
#delete_leading_invalid_opts ⇒ Object
334 335 336 |
# File 'lib/boson/option_parser.rb', line 334 def delete_leading_invalid_opts delete_invalid_opts @leading_non_opts end |
#formatted_usage ⇒ Object Also known as: to_s
Generates one-line usage of all options.
257 258 259 260 261 262 263 264 |
# File 'lib/boson/option_parser.rb', line 257 def formatted_usage return "" if @opt_types.empty? @opt_types.map do |opt, type| val = respond_to?("usage_for_#{type}", true) ? send("usage_for_#{type}", opt) : "#{opt}=:#{type}" "[" + val + "]" end.join(" ") end |
#indifferent_hash ⇒ Object
Creates a Hash with indifferent access
330 331 332 |
# File 'lib/boson/option_parser.rb', line 330 def indifferent_hash Hash.new {|hash,key| hash[key.to_sym] if String === key } end |
#names ⇒ Object
List of option names
320 321 322 |
# File 'lib/boson/option_parser.rb', line 320 def names @opt_types.keys.map {|e| undasherize e } end |
#non_opts ⇒ Object
Array of arguments left after defined options have been parsed out by parse.
65 66 67 |
# File 'lib/boson/option_parser.rb', line 65 def non_opts leading_non_opts + trailing_non_opts end |
#option_attributes ⇒ Object
Hash of option names mapped to hash of its external attributes
292 293 294 |
# File 'lib/boson/option_parser.rb', line 292 def option_attributes @option_attributes || {} end |
#parse(args, flags = {}) ⇒ Object
Parses an array of arguments for defined options to return an indifferent access hash. Once the parser recognizes a valid option, it continues to parse until an non option argument is detected.
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
# File 'lib/boson/option_parser.rb', line 212 def parse(args, flags={}) @args = args # start with symbolized defaults hash = Hash[@defaults.map {|k,v| [k.to_sym, v] }] @leading_non_opts = [] unless flags[:opts_before_args] @leading_non_opts << shift until current_is_option? || @args.empty? || STOP_STRINGS.include?(peek) end while current_is_option? case @original_current_option = shift when SHORT_SQ_RE unshift $1.split('').map { |f| "-#{f}" } next when EQ_RE, SHORT_NUM unshift $2 option = $1 when LONG_RE, SHORT_RE option = $1 end dashed_option = normalize_option(option) @current_option = undasherize(dashed_option) type = option_type(dashed_option) validate_option_value(type) value = create_option_value(type) # set on different line since current_option may change hash[@current_option.to_sym] = value end @trailing_non_opts = @args check_required! hash delete_invalid_opts if flags[:delete_invalid_opts] indifferent_hash.tap {|h| h.update hash } end |
#print_usage_table(options = {}) ⇒ Object
More verbose option help in the form of a table.
269 270 271 272 273 |
# File 'lib/boson/option_parser.rb', line 269 def print_usage_table(={}) fields = get_usage_fields [:fields] fields, opts = (fields, ) render_table(fields, opts, ) end |
#types ⇒ Object
List of option types
315 316 317 |
# File 'lib/boson/option_parser.rb', line 315 def types @opt_types.values end |
#undasherize(str) ⇒ Object
Removes dashes from a dashed option i.e. ‘–date’ -> ‘date’ and ‘-d’ -> ‘d’.
305 306 307 |
# File 'lib/boson/option_parser.rb', line 305 def undasherize(str) str.sub(/^-{1,2}/, '') end |