Class: ArgParser::Definition
- Inherits:
-
ArgumentScope
- Object
- ArgumentScope
- 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
-
#copyright ⇒ String
A copyright notice, displayed in the usage and help outputs.
-
#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.
Attributes inherited from ArgumentScope
#name, #parent, #predefined_args
Instance Method Summary collapse
-
#collapse(cmd_inst) ⇒ Definition
Collapses an ArgumentScope into this Definition, representing the collapsed argument possibilities once a command has been identitfied for a CommandArgument.
-
#errors ⇒ Object
Return an array of parse errors.
-
#initialize(name = 'ArgParser::Definition') {|_self| ... } ⇒ Definition
constructor
Create a new Definition, which is a collection of valid Arguments to be used when parsing a command-line.
-
#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.
-
#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.
-
#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.
-
#validate_requirements(args) ⇒ Array
Validates the supplied
args
Hash object, verifying that any argument set requirements have been satisfied. -
#wrap_text(text, width) ⇒ Array
Utility method for wrapping lines of
text
atwidth
characters.
Methods inherited from ArgumentScope
#<<, #[], #add_child, #args, #command_arg, #command_args, #command_args?, #flag_arg, #flag_args, #flag_args?, #has_key?, #key_used?, #keys, #keyword_arg, #keyword_args, #keyword_args?, #non_positional_args, #non_positional_args?, #positional_arg, #positional_args, #positional_args?, #rest_arg, #rest_args, #rest_args?, #short_keys, #size, #value_args, #walk_ancestors, #walk_arguments, #walk_children
Constructor Details
#initialize(name = 'ArgParser::Definition') {|_self| ... } ⇒ Definition
Create a new Definition, which is a collection of valid Arguments to be used when parsing a command-line.
358 359 360 361 362 363 |
# File 'lib/arg-parser/definition.rb', line 358 def initialize(name = 'ArgParser::Definition') super(name) @require_set = [] @title = $0.respond_to?(:titleize) ? $0.titleize : $0 yield self if block_given? end |
Instance Attribute Details
#copyright ⇒ String
Returns A copyright notice, displayed in the usage and help outputs.
353 354 355 |
# File 'lib/arg-parser/definition.rb', line 353 def copyright @copyright end |
#purpose ⇒ String
Returns A short description of the purpose of the script, for display when showing the usage help.
350 351 352 |
# File 'lib/arg-parser/definition.rb', line 350 def purpose @purpose end |
#title ⇒ String
Returns A title for the script, displayed at the top of the usage and help outputs.
347 348 349 |
# File 'lib/arg-parser/definition.rb', line 347 def title @title end |
Instance Method Details
#collapse(cmd_inst) ⇒ Definition
Collapses an ArgumentScope into this Definition, representing the collapsed argument possibilities once a command has been identitfied for a CommandArgument. Think of the original Definition as being a superposition of possible argument definitions, with one possible state for each CommandInstance of each commad. Once the actual CommandInstance is known, we are collapsing the superposition of possible definitions to a lower dimensionality; only one possible definition remains once all CommandArgument objects are replaced by CommandInstances.
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 |
# File 'lib/arg-parser/definition.rb', line 381 def collapse(cmd_inst) new_def = self.clone child = cmd_inst.argument_scope new_args = {} new_short_keys = {} @arguments.each do |key, arg| if arg == cmd_inst.command_arg new_args[key] = cmd_inst child.walk_arguments do |key, arg| new_args[key] = arg new_short_keys[arg.short_key] = arg if arg.short_key end else new_args[key] = arg new_short_keys[arg.short_key] = arg if arg.short_key end end new_children = @children.reject{ |c| c == cmd_inst.argument_scope } & child.instance_variable_get(:@children) new_def.instance_variable_set(:@arguments, new_args) new_def.instance_variable_set(:@short_keys, new_short_keys) new_def.instance_variable_set(:@children, new_children) new_def end |
#errors ⇒ Object
Return an array of parse errors.
484 485 486 |
# File 'lib/arg-parser/definition.rb', line 484 def errors parser.errors 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.
477 478 479 |
# File 'lib/arg-parser/definition.rb', line 477 def parse(args = ARGV) parser.parse(args) end |
#parser ⇒ Parser
Returns a Parser instance that can be used to parse this command-line Definition.
463 464 465 |
# File 'lib/arg-parser/definition.rb', line 463 def parser @parser ||= Parser.new(self) end |
#predefined_arg(lookup_key, opts = {}) ⇒ Object
Lookup a pre-defined argument (created earlier via Argument#register), and add it to this arguments definition.
427 428 429 430 431 432 433 434 435 436 437 438 |
# File 'lib/arg-parser/definition.rb', line 427 def predefined_arg(lookup_key, opts = {}) # TODO: walk ancestor chain looking at pre-defined arg scopes arg = (self.predefined_args && self.predefined_args.key_used?(lookup_key)) || Argument.lookup(lookup_key) arg.short_key = opts[:short_key] if opts.has_key?(:short_key) arg.description = opts[:description] if opts.has_key?(:description) arg.usage_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) arg.on_parse = opts[:on_parse] if opts.has_key?(:on_parse) self << arg end |
#require_any_of(*keys) ⇒ Object
Individual arguments are optional, but at least one of keys
arguments is required.
450 451 452 |
# File 'lib/arg-parser/definition.rb', line 450 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.
443 444 445 |
# File 'lib/arg-parser/definition.rb', line 443 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.
456 457 458 |
# File 'lib/arg-parser/definition.rb', line 456 def requires_some? @require_set.size > 0 end |
#show_help(out = STDOUT, width = 80) ⇒ Array
Generates a more detailed help screen.
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 |
# File 'lib/arg-parser/definition.rb', line 554 def show_help(out = STDOUT, width = 80) lines = ['', ''] lines << title lines << title.gsub(/./, '=') lines << '' if purpose lines.concat(wrap_text(purpose, width)) lines << '' end if copyright lines.concat(wrap_text("Copyright (c) #{copyright}", width)) lines << '' end lines << 'USAGE' lines << '-----' pos_args = positional_args opt_args = size - pos_args.size usage_args = [] usage_args.concat(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{ |arg| arg.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 command_args? max = command_args.reduce(0) do |max, cmd_arg| m = cmd_arg.commands.map{ |_, arg| arg.to_s.length }.max m > max ? m : max end command_args.each do |cmd_arg| lines << '' lines << "#{cmd_arg.to_use}S" lines << '--------' cmd_arg.commands.each do |_, arg| if arg.usage_break lines << '' lines << arg.usage_break end desc = arg.description 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 end if non_positional_args? lines << '' lines << 'OPTIONS' lines << '-------' max = non_positional_args.map{ |arg| arg.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.
498 499 500 |
# File 'lib/arg-parser/definition.rb', line 498 def show_help? parser.show_help? end |
#show_usage(out = STDERR, width = 80) ⇒ Object
Generates a usage display string
533 534 535 536 537 538 539 540 541 542 543 544 545 546 |
# File 'lib/arg-parser/definition.rb', line 533 def show_usage(out = STDERR, width = 80) lines = [''] usage_args = [] usage_args.concat(positional_args.map(&:to_use)) opt_args = size - usage_args.size 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.
491 492 493 |
# File 'lib/arg-parser/definition.rb', line 491 def show_usage? parser.show_usage? 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.
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 |
# File 'lib/arg-parser/definition.rb', line 511 def validate_requirements(args) errors = [] @require_set.each do |req, 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 errors end |
#wrap_text(text, width) ⇒ Array
Utility method for wrapping lines of text
at width
characters.
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 |
# File 'lib/arg-parser/definition.rb', line 650 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 |