Class: ArgParser::Definition
- Inherits:
-
Object
- Object
- ArgParser::Definition
- Defined in:
- lib/arg-parser/definition.rb
Overview
Represents the collection of possible command-line arguments for a script.
Instance Attribute Summary collapse
-
#purpose ⇒ String
A short description of the purpose of the script, for display when showing the usage help.
-
#title ⇒ String
A title for the script, displayed at the top of the usage and help outputs.
Instance Method Summary collapse
-
#<<(arg) ⇒ Object
Adds the specified argument to the command-line definition.
-
#[](key) ⇒ Argument
The argument with the specified key.
-
#args ⇒ Array
All arguments that have been defined.
-
#errors ⇒ Object
Return an array of parse errors.
-
#flag_arg(key, desc, opts = {}, &block) ⇒ Object
Add a flag argument to the set of arguments in this command-line argument definition.
-
#flag_args ⇒ Array
The flag arguments that have been defined.
-
#flag_args? ⇒ Boolean
True if any flag arguments have been defined.
-
#has_key?(key) ⇒ Argument
The argument for the given key if it exists, or nil if it does not.
-
#initialize {|_self| ... } ⇒ Definition
constructor
Create a new Definition, which is a collection of valid Arguments to be used when parsing a command-line.
-
#keyword_arg(key, desc, opts = {}, &block) ⇒ Object
Add a keyword argument to the set of arguments in this command-line argument definition.
-
#keyword_args ⇒ Array
The keyword arguments that have been defined.
-
#keyword_args? ⇒ Boolean
True if any keyword arguments have been defined.
-
#non_positional_args ⇒ Array
The non-positional (i.e. keyword and flag) arguments that have been defined.
-
#non_positional_args? ⇒ Boolean
True if any non-positional arguments have been defined.
-
#parse(args = ARGV) ⇒ OpenStruct, false
Parse the
args
array of arguments using this command-line definition. -
#parser ⇒ Parser
A Parser instance that can be used to parse this command-line Definition.
-
#positional_arg(key, desc, opts = {}, &block) ⇒ Object
Add a positional argument to the set of arguments in this command-line argument definition.
-
#positional_args ⇒ Array
All positional arguments that have been defined.
-
#positional_args? ⇒ Boolean
True if any positional arguments have been defined.
-
#predefined_arg(lookup_key, opts = {}) ⇒ Object
Lookup a pre-defined argument (created earlier via Argument#register), and add it to this arguments definition.
-
#require_any_of(*keys) ⇒ Object
Individual arguments are optional, but at least one of
keys
arguments is required. -
#require_one_of(*keys) ⇒ Object
Individual arguments are optional, but exactly one of
keys
arguments is required. -
#requires_some? ⇒ Boolean
True if at least one argument is required out of multiple optional args.
-
#rest_arg(key, desc, opts = {}, &block) ⇒ Object
Add a rest argument to the set of arguments in this command-line argument definition.
-
#rest_args ⇒ RestArgument
The RestArgument defined for this command-line, or nil if no RestArgument is defined.
-
#rest_args? ⇒ Boolean
True if a RestArgument has been defined.
-
#show_help(out = STDOUT, width = 80) ⇒ Array
Generates a more detailed help screen.
-
#show_help? ⇒ Boolean
Whether user indicated they would like help on supported arguments.
-
#show_usage(out = STDERR, width = 80) ⇒ Object
Generates a usage display string.
-
#show_usage? ⇒ Boolean
Whether user indicated they would like help on usage.
-
#size ⇒ Integer
The number of arguments that have been defined.
-
#validate_requirements(args) ⇒ Array
Validates the supplied
args
Hash object, verifying that any argument set requirements have been satisfied. -
#value_args ⇒ Array
All the positional, keyword, and rest arguments that have been defined.
-
#wrap_text(text, width) ⇒ Array
Utility method for wrapping lines of
text
atwidth
characters.
Constructor Details
#initialize {|_self| ... } ⇒ Definition
Create a new Definition, which is a collection of valid Arguments to be used when parsing a command-line.
21 22 23 24 25 26 27 |
# File 'lib/arg-parser/definition.rb', line 21 def initialize @arguments = {} @short_keys = {} @require_set = Hash.new{ |h,k| h[k] = [] } @title = $0.respond_to?(:titleize) ? $0.titleize : $0 yield self if block_given? end |
Instance Attribute Details
#purpose ⇒ String
Returns A short description of the purpose of the script, for display when showing the usage help.
16 17 18 |
# File 'lib/arg-parser/definition.rb', line 16 def purpose @purpose end |
#title ⇒ String
Returns A title for the script, displayed at the top of the usage and help outputs.
13 14 15 |
# File 'lib/arg-parser/definition.rb', line 13 def title @title end |
Instance Method Details
#<<(arg) ⇒ Object
Adds the specified argument to the command-line definition.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/arg-parser/definition.rb', line 51 def <<(arg) case arg when PositionalArgument, KeywordArgument, FlagArgument, RestArgument if @arguments[arg.key] raise ArgumentError, "An argument with key '#{arg.key}' has already been defined" end if arg.short_key && @short_keys[arg.short_key] raise ArgumentError, "An argument with short key '#{arg.short_key}' has already been defined" end if arg.is_a?(RestArgument) && rest_args raise ArgumentError, "Only one rest argument can be defined" end @arguments[arg.key] = arg @short_keys[arg.short_key] = arg if arg.short_key else raise ArgumentError, "arg must be an instance of PositionalArgument, KeywordArgument, " + "FlagArgument or RestArgument" end end |
#[](key) ⇒ Argument
Returns the argument with the specified key.
41 42 43 44 |
# File 'lib/arg-parser/definition.rb', line 41 def [](key) arg = has_key?(key) arg or raise NoSuchArgumentError, "No argument defined for key '#{Argument.to_key(key)}'" end |
#args ⇒ Array
Returns all arguments that have been defined.
228 229 230 |
# File 'lib/arg-parser/definition.rb', line 228 def args @arguments.values end |
#errors ⇒ Object
Return an array of parse errors.
177 178 179 |
# File 'lib/arg-parser/definition.rb', line 177 def errors parser.errors end |
#flag_arg(key, desc, opts = {}, &block) ⇒ Object
Add a flag argument to the set of arguments in this command-line argument definition.
91 92 93 |
# File 'lib/arg-parser/definition.rb', line 91 def flag_arg(key, desc, opts = {}, &block) self << ArgParser::FlagArgument.new(key, desc, opts, &block) end |
#flag_args ⇒ Array
Returns the flag arguments that have been defined.
271 272 273 |
# File 'lib/arg-parser/definition.rb', line 271 def flag_args @arguments.values.select{ |arg| FlagArgument === arg } end |
#flag_args? ⇒ Boolean
Returns True if any flag arguments have been defined.
277 278 279 |
# File 'lib/arg-parser/definition.rb', line 277 def flag_args? flag_args.size > 0 end |
#has_key?(key) ⇒ Argument
Returns the argument for the given key if it exists, or nil if it does not.
32 33 34 35 |
# File 'lib/arg-parser/definition.rb', line 32 def has_key?(key) k = Argument.to_key(key) @arguments[k] || @short_keys[k] end |
#keyword_arg(key, desc, opts = {}, &block) ⇒ Object
Add a keyword argument to the set of arguments in this command-line argument definition.
83 84 85 |
# File 'lib/arg-parser/definition.rb', line 83 def keyword_arg(key, desc, opts = {}, &block) self << ArgParser::KeywordArgument.new(key, desc, opts, &block) end |
#keyword_args ⇒ Array
Returns the keyword arguments that have been defined.
259 260 261 |
# File 'lib/arg-parser/definition.rb', line 259 def keyword_args @arguments.values.select{ |arg| KeywordArgument === arg } end |
#keyword_args? ⇒ Boolean
Returns True if any keyword arguments have been defined.
265 266 267 |
# File 'lib/arg-parser/definition.rb', line 265 def keyword_args? keyword_args.size > 0 end |
#non_positional_args ⇒ Array
Returns the non-positional (i.e. keyword and flag) arguments that have been defined.
247 248 249 |
# File 'lib/arg-parser/definition.rb', line 247 def non_positional_args @arguments.values.reject{ |arg| PositionalArgument === arg || RestArgument === arg } end |
#non_positional_args? ⇒ Boolean
Returns True if any non-positional arguments have been defined.
253 254 255 |
# File 'lib/arg-parser/definition.rb', line 253 def non_positional_args? non_positional_args.size > 0 end |
#parse(args = ARGV) ⇒ OpenStruct, false
Parse the args
array of arguments using this command-line definition.
arguments defined as accessors, and the parsed or default values for each argument as values. If unsuccessful, returns false indicating a parse failure.
170 171 172 |
# File 'lib/arg-parser/definition.rb', line 170 def parse(args = ARGV) parser.parse(args) end |
#parser ⇒ Parser
Returns a Parser instance that can be used to parse this command-line Definition.
156 157 158 |
# File 'lib/arg-parser/definition.rb', line 156 def parser @parser ||= Parser.new(self) end |
#positional_arg(key, desc, opts = {}, &block) ⇒ Object
Add a positional argument to the set of arguments in this command-line argument definition.
75 76 77 |
# File 'lib/arg-parser/definition.rb', line 75 def positional_arg(key, desc, opts = {}, &block) self << ArgParser::PositionalArgument.new(key, desc, opts, &block) end |
#positional_args ⇒ Array
Returns all positional arguments that have been defined.
234 235 236 |
# File 'lib/arg-parser/definition.rb', line 234 def positional_args @arguments.values.select{ |arg| PositionalArgument === arg } end |
#positional_args? ⇒ Boolean
Returns True if any positional arguments have been defined.
240 241 242 |
# File 'lib/arg-parser/definition.rb', line 240 def positional_args? positional_args.size > 0 end |
#predefined_arg(lookup_key, opts = {}) ⇒ Object
Lookup a pre-defined argument (created earlier via Argument#register), and add it to this arguments definition.
124 125 126 127 128 129 130 131 |
# File 'lib/arg-parser/definition.rb', line 124 def predefined_arg(lookup_key, opts = {}) arg = Argument.lookup(lookup_key) arg.description = opts[:description] if opts[:description] arg.useage_break = opts[:usage_break] if opts.has_key?(:usage_break) arg.required = opts[:required] if opts.has_key?(:required) arg.default = opts[:default] if opts.has_key?(:default) self << arg end |
#require_any_of(*keys) ⇒ Object
Individual arguments are optional, but at least one of keys
arguments is required.
143 144 145 |
# File 'lib/arg-parser/definition.rb', line 143 def require_any_of(*keys) @require_set[:any] << keys.map{ |k| self[k] } end |
#require_one_of(*keys) ⇒ Object
Individual arguments are optional, but exactly one of keys
arguments is required.
136 137 138 |
# File 'lib/arg-parser/definition.rb', line 136 def require_one_of(*keys) @require_set[:one] << keys.map{ |k| self[k] } end |
#requires_some? ⇒ Boolean
True if at least one argument is required out of multiple optional args.
149 150 151 |
# File 'lib/arg-parser/definition.rb', line 149 def requires_some? @require_set.size > 0 end |
#rest_arg(key, desc, opts = {}, &block) ⇒ Object
Add a rest argument to the set of arguments in this command-line argument definition.
99 100 101 |
# File 'lib/arg-parser/definition.rb', line 99 def rest_arg(key, desc, opts = {}, &block) self << ArgParser::RestArgument.new(key, desc, opts, &block) end |
#rest_args ⇒ RestArgument
Returns the RestArgument defined for this command-line, or nil if no RestArgument is defined.
284 285 286 |
# File 'lib/arg-parser/definition.rb', line 284 def rest_args @arguments.values.find{ |arg| RestArgument === arg } end |
#rest_args? ⇒ Boolean
Returns True if a RestArgument has been defined.
290 291 292 |
# File 'lib/arg-parser/definition.rb', line 290 def rest_args? !!rest_args end |
#show_help(out = STDOUT, width = 80) ⇒ Array
Generates a more detailed help screen.
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 |
# File 'lib/arg-parser/definition.rb', line 330 def show_help(out = STDOUT, width = 80) lines = ['', ''] lines << title lines << title.gsub(/./, '=') lines << '' if purpose lines.concat(wrap_text(purpose, width)) lines << '' lines << '' end lines << 'USAGE' lines << '-----' pos_args = positional_args opt_args = size - pos_args.size usage_args = pos_args.map(&:to_use) usage_args << (requires_some? ? 'OPTIONS' : '[OPTIONS]') if opt_args > 0 usage_args << rest_args.to_use if rest_args? lines.concat(wrap_text(" #{RUBY_ENGINE} #{$0} #{usage_args.join(' ')}", width)) lines << '' if positional_args? max = positional_args.map{ |a| a.to_s.length }.max pos_args = positional_args pos_args << rest_args if rest_args? pos_args.each do |arg| if arg.usage_break lines << '' lines << arg.usage_break end desc = arg.description desc << "\n[Default: #{arg.default}]" unless arg.default.nil? wrap_text(desc, width - max - 6).each_with_index do |line, i| lines << " %-#{max}s %s" % [[arg.to_s][i], line] end end lines << '' end if non_positional_args? lines << '' lines << 'OPTIONS' lines << '-------' max = non_positional_args.map{ |a| a.to_use.length }.max non_positional_args.each do |arg| if arg.usage_break lines << '' lines << arg.usage_break end desc = arg.description desc << "\n[Default: #{arg.default}]" unless arg.default.nil? wrap_text(desc, width - max - 6).each_with_index do |line, i| lines << " %-#{max}s %s" % [[arg.to_use][i], line] end end end lines << '' lines.each{ |line| line.length < width ? out.puts(line) : out.print(line) } if out lines end |
#show_help? ⇒ Boolean
Whether user indicated they would like help on supported arguments.
191 192 193 |
# File 'lib/arg-parser/definition.rb', line 191 def show_help? parser.show_help? end |
#show_usage(out = STDERR, width = 80) ⇒ Object
Generates a usage display string
309 310 311 312 313 314 315 316 317 318 319 320 321 322 |
# File 'lib/arg-parser/definition.rb', line 309 def show_usage(out = STDERR, width = 80) lines = [''] pos_args = positional_args opt_args = size - pos_args.size usage_args = pos_args.map(&:to_use) usage_args << (requires_some? ? 'OPTIONS' : '[OPTIONS]') if opt_args > 0 usage_args << rest_args.to_use if rest_args? lines.concat(wrap_text("USAGE: #{RUBY_ENGINE} #{$0} #{usage_args.join(' ')}", width)) lines << '' lines << 'Specify the /? or --help option for more detailed help' lines << '' lines.each{ |line| out.puts line } if out lines end |
#show_usage? ⇒ Boolean
Whether user indicated they would like help on usage.
184 185 186 |
# File 'lib/arg-parser/definition.rb', line 184 def show_usage? parser.show_usage? end |
#size ⇒ Integer
Returns the number of arguments that have been defined.
303 304 305 |
# File 'lib/arg-parser/definition.rb', line 303 def size @arguments.size end |
#validate_requirements(args) ⇒ Array
Validates the supplied args
Hash object, verifying that any argument set requirements have been satisfied. Returns an array of error messages for each set requirement that is not satisfied.
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
# File 'lib/arg-parser/definition.rb', line 204 def validate_requirements(args) errors = [] @require_set.each do |req, sets| sets.each do |set| count = set.count{ |arg| args.has_key?(arg.key) && args[arg.key] } case req when :one if count == 0 errors << "No argument has been specified for one of: #{set.join(', ')}" elsif count > 1 errors << "Only one argument can been specified from: #{set.join(', ')}" end when :any if count == 0 errors << "At least one of the arguments must be specified from: #{set.join(', ')}" end end end end errors end |
#value_args ⇒ Array
Returns all the positional, keyword, and rest arguments that have been defined.
297 298 299 |
# File 'lib/arg-parser/definition.rb', line 297 def value_args @arguments.values.select{ |arg| ValueArgument === arg } end |
#wrap_text(text, width) ⇒ Array
Utility method for wrapping lines of text
at width
characters.
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 |
# File 'lib/arg-parser/definition.rb', line 399 def wrap_text(text, width) if width > 0 && (text.length > width || text.index("\n")) lines = [] start, nl_pos, ws_pos, wb_pos, end_pos = 0, 0, 0, 0, text.rindex(/[^\s]/) while start < end_pos last_start = start nl_pos = text.index("\n", start) ws_pos = text.rindex(/ +/, start + width) wb_pos = text.rindex(/[\-,.;#)}\]\/\\]/, start + width - 1) ### Debug code ### #STDERR.puts self #ind = ' ' * end_pos #ind[start] = '(' #ind[start+width < end_pos ? start+width : end_pos] = ']' #ind[nl_pos] = 'n' if nl_pos #ind[wb_pos] = 'b' if wb_pos #ind[ws_pos] = 's' if ws_pos #STDERR.puts ind ### End debug code ### if nl_pos && nl_pos <= start + width lines << text[start...nl_pos].strip start = nl_pos + 1 elsif end_pos < start + width lines << text[start..end_pos] start = end_pos elsif ws_pos && ws_pos > start && ((wb_pos.nil? || ws_pos > wb_pos) || (wb_pos && wb_pos > 5 && wb_pos - 5 < ws_pos)) lines << text[start...ws_pos] start = text.index(/[^\s]/, ws_pos + 1) elsif wb_pos && wb_pos > start lines << text[start..wb_pos] start = wb_pos + 1 else lines << text[start...(start+width)] start += width end if start <= last_start # Detect an infinite loop, and just return the original text STDERR.puts "Inifinite loop detected at #{__FILE__}:#{__LINE__}" STDERR.puts " width: #{width}, start: #{start}, nl_pos: #{nl_pos}, " + "ws_pos: #{ws_pos}, wb_pos: #{wb_pos}" return [text] end end lines else [text] end end |