Module: Launchr::Mixlib::CLI
- Included in:
- CLI
- Defined in:
- lib/launchr/mixin/mixlib_cli.rb
Overview
Author:: Adam Jacob (<[email protected]>)
Copyright:: Copyright (c) 2008 Opscode, Inc.
License:: Apache License, Version 2.0
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Defined Under Namespace
Modules: ClassMethods
Instance Attribute Summary collapse
-
#arguments ⇒ Object
Returns the value of attribute arguments.
-
#banner ⇒ Object
Returns the value of attribute banner.
-
#config ⇒ Object
Returns the value of attribute config.
-
#filtered_argv ⇒ Object
Returns the value of attribute filtered_argv.
-
#footer ⇒ Object
Returns the value of attribute footer.
-
#header ⇒ Object
Returns the value of attribute header.
-
#opt_parser ⇒ Object
Returns the value of attribute opt_parser.
-
#options ⇒ Object
Returns the value of attribute options.
-
#options_arguments ⇒ Object
Returns the value of attribute options_arguments.
-
#spaced_summary ⇒ Object
Returns the value of attribute spaced_summary.
-
#summary_indent ⇒ Object
Returns the value of attribute summary_indent.
-
#summary_width ⇒ Object
Returns the value of attribute summary_width.
Instance Method Summary collapse
- #build_option_arguments(opt_setting) ⇒ Object
- #filter_options_summary(options_summary) ⇒ Object
- #guess_and_switchify_arguments(argv) ⇒ Object
-
#initialize(*args) ⇒ Object
Create a new Mixlib::CLI class.
-
#parse_options(argv = ARGV) ⇒ Object
Parses an array, by default ARGV, for command line options (as configured at the class level).
Instance Attribute Details
#arguments ⇒ Object
Returns the value of attribute arguments.
279 280 281 |
# File 'lib/launchr/mixin/mixlib_cli.rb', line 279 def arguments @arguments end |
#banner ⇒ Object
Returns the value of attribute banner.
279 280 281 |
# File 'lib/launchr/mixin/mixlib_cli.rb', line 279 def @banner end |
#config ⇒ Object
Returns the value of attribute config.
279 280 281 |
# File 'lib/launchr/mixin/mixlib_cli.rb', line 279 def config @config end |
#filtered_argv ⇒ Object
Returns the value of attribute filtered_argv.
280 281 282 |
# File 'lib/launchr/mixin/mixlib_cli.rb', line 280 def filtered_argv @filtered_argv end |
#footer ⇒ Object
Returns the value of attribute footer.
279 280 281 |
# File 'lib/launchr/mixin/mixlib_cli.rb', line 279 def @footer end |
#header ⇒ Object
Returns the value of attribute header.
279 280 281 |
# File 'lib/launchr/mixin/mixlib_cli.rb', line 279 def header @header end |
#opt_parser ⇒ Object
Returns the value of attribute opt_parser.
280 281 282 |
# File 'lib/launchr/mixin/mixlib_cli.rb', line 280 def opt_parser @opt_parser end |
#options ⇒ Object
Returns the value of attribute options.
279 280 281 |
# File 'lib/launchr/mixin/mixlib_cli.rb', line 279 def @options end |
#options_arguments ⇒ Object
Returns the value of attribute options_arguments.
279 280 281 |
# File 'lib/launchr/mixin/mixlib_cli.rb', line 279 def @options_arguments end |
#spaced_summary ⇒ Object
Returns the value of attribute spaced_summary.
280 281 282 |
# File 'lib/launchr/mixin/mixlib_cli.rb', line 280 def spaced_summary @spaced_summary end |
#summary_indent ⇒ Object
Returns the value of attribute summary_indent.
280 281 282 |
# File 'lib/launchr/mixin/mixlib_cli.rb', line 280 def summary_indent @summary_indent end |
#summary_width ⇒ Object
Returns the value of attribute summary_width.
280 281 282 |
# File 'lib/launchr/mixin/mixlib_cli.rb', line 280 def summary_width @summary_width end |
Instance Method Details
#build_option_arguments(opt_setting) ⇒ Object
542 543 544 545 546 547 548 549 550 551 552 553 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 |
# File 'lib/launchr/mixin/mixlib_cli.rb', line 542 def build_option_arguments(opt_setting) arguments = Array.new arguments << opt_setting[:short] if opt_setting.has_key?(:short) arguments << opt_setting[:long] if opt_setting.has_key?(:long) if opt_setting.has_key?(:keywords) arguments << opt_setting[:keywords] elsif opt_setting.has_key?(:type) arguments << opt_setting[:type] end case opt_setting[:description] when Array lines = opt_setting[:description].dup # lines.first << " (required)" if opt_setting[:required] lines.map! do |line| if line == lines.first line else line = " " + line if opt_setting[:indent] @spaced_summary ? line : " " + line end end arguments += lines when String description = opt_setting[:description] # description = " " + description if opt_setting[:indent] # description << " (required)" if opt_setting[:required] arguments << description end case opt_setting[:example] when Array lines = opt_setting[:example] example = lines.map do |line| if line == lines.first header = "Examples $ " header = " " + header unless @spaced_summary else header = " $ " header = " " + header unless @spaced_summary end header = " " + header if opt_setting[:indent] line_parts = line.split("#") if line_parts.first.include?("#{File.basename($0)} ") header + line else header + "#{File.basename $0} " + line end end arguments << " " if @spaced_summary arguments += example when /#{File.basename $0}/ line = opt_setting[:example] line_parts = line.split("#") if line_parts.first.include?("#{File.basename($0)} ") line = "Example $ " + line line = " " + line if opt_setting[:indent] else line = "Example $ #{File.basename $0} " + line line = " " + line if opt_setting[:indent] end line = " " + line unless @spaced_summary arguments << line when nil else line = "Example $ #{File.basename $0} " + opt_setting[:example] line = " " + line if opt_setting[:indent] line = " " + line unless @spaced_summary arguments << line end arguments end |
#filter_options_summary(options_summary) ⇒ Object
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 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 |
# File 'lib/launchr/mixin/mixlib_cli.rb', line 619 def os = .split("\n") out = [] short_args = @arguments.values.map do |args| args[:short] ? args[:short].sub(/([A-Z]|=|\s).*$/,"") : args[:short] end long_args = @arguments.values.map do |args| args[:long] ? args[:long].sub(/([A-Z]|=|\s).*$/,"") : args[:long] end os.each do |line| case line when out += [@header].flatten if @header unless line =~ /^\s*$/ # line = " " + line if @spaced_summary out << line end else if @spaced_summary out << "" unless line =~ /^#{@opt_parser.summary_indent}\s{#{@opt_parser.summary_width},}/ end line =~ /^\s+-((\[no-\])?\w+)\,?/ short_opt = $1 || false line =~ /^\s+(-(\[no-\])?\w+\,?)?\s--((\[no-\])?\w+)/ long_opt = $3 || false # line.sub!("-"+short_opt," "+short_opt) if short_opt && short_args.include?("-#{short_opt}") # line.sub!("--"+long_opt," "+long_opt) if long_opt && long_args.include?("--#{long_opt}") opt_value = {} @options_arguments.each do |key,value| if long_opt && value[:long_strip] if long_opt.sub(/^(-+)?\[no-\]/,"") == value[:long_strip].sub(/^-+/,"") # puts long_opt opt_value = value end elsif short_opt && value[:short_strip] if short_opt.sub(/^(-+)?\[no-\]/,"") == value[:short_strip].sub(/^-+/,"") # puts short_opt opt_value = value end end end line = " " + line if opt_value[:indent] if short_opt && short_args.include?("-#{short_opt}") short_opt = @arguments.values[short_args.index("-#{short_opt}")][:short].sub(/^-+/,"") # short_opt = opt_value[:short].sub(/^-+/,"") line.sub!("-"+short_opt,short_opt+" ") end if long_opt && long_args.include?("--#{long_opt}") long_opt = @arguments.values[long_args.index("--#{long_opt}")][:long].sub(/^-+/,"") # long_opt = opt_value[:short].sub(/^-+/,"") line.sub!("--"+long_opt,long_opt+" ") end out << line end end out << " " if @spaced_summary out += [@footer].flatten if @footer out end |
#guess_and_switchify_arguments(argv) ⇒ Object
389 390 391 392 393 394 395 396 397 398 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 |
# File 'lib/launchr/mixin/mixlib_cli.rb', line 389 def guess_and_switchify_arguments argv # collect argument declarations short_args = @arguments.values.map { |args| args[:short_strip] } long_args = @arguments.values.map { |args| args[:long_strip] } short_opts_args = @options_arguments.values.map { |args| args[:short_strip] } long_opts_args = @options_arguments.values.map { |args| args[:long_strip] } short_opts_args_unfiltered = @options_arguments.values.map { |args| args[:short] } long_opts_args_unfiltered = @options_arguments.values.map { |args| args[:long] } i = 0 while i < argv.size # switchify the argv argument if it looks like a recognised argument if short_args.include?("-"+argv[i].sub(/^no-/,"").sub(/(=|\s).*/,"")) argv[i] = "-" + argv[i] end if long_args.include?("--"+argv[i].sub(/^no-/,"").sub(/(=|\s).*/,"")) argv[i] = "--" + argv[i] end # when the argv argument matches a recognised option or argument # without the style =value, the following argument might have to be skipped... # so find the index of the switch declaration j = nil if short_opts_args.include?(argv[i]) j = short_opts_args.index(argv[i]) end if long_opts_args.include?(argv[i]) j = long_opts_args.index(argv[i]) end if j # when the switch declaration has a required argument if short_opts_args_unfiltered[j] =~ /( .+|\<|\=|[A-Z])/ # skip forward one i += 1 end # when the switch declaration has a required argument if long_opts_args_unfiltered[j] =~ /( .+|\<|\=|[A-Z])/ # skip forward one i += 1 end end # next argument i += 1 end argv end |
#initialize(*args) ⇒ Object
Create a new Mixlib::CLI class. If you override this, make sure you call super!
Parameters
- *args<Array>
-
The array of arguments passed to the initializer
Returns
- object<Mixlib::Config>
-
Returns an instance of whatever you wanted :)
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 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 |
# File 'lib/launchr/mixin/mixlib_cli.rb', line 289 def initialize(*args) @options = Launchr::OrderedHash.new @arguments = Launchr::OrderedHash.new @options_arguments = Launchr::OrderedHash.new @config = Hash.new @filtered_argv = [] # Set the banner @banner = self.class. @header = self.class.header @footer = self.class. @summary_indent = self.class.summary_indent @summary_width = self.class.summary_width @spaced_summary = self.class.spaced_summary # Dupe the class options for this instance = self.class. .keys.inject(@options) { |memo, key| memo[key] = [key].dup; memo } # Dupe the class arguments for this instance klass_arguments = self.class.arguments klass_arguments.keys.inject(@arguments) { |memo, key| memo[key] = klass_arguments[key].dup; memo } # Dupe the class arguments for this instance = self.class. .keys.inject(@options_arguments) { |memo, key| memo[key] = [key].dup; memo } # check argument and option :name keys dont conflict name_collision = .keys & klass_arguments.keys raise ArgumentError, "An option cannot have the same name as an argument: #{name_collision.join(', ')}" unless name_collision.empty? koso, kolo = [], [] .each do |name, kargs| koso << (kargs[:short_strip] || "") kolo << (kargs[:long_strip] || "") end kasa, kala = [], [] klass_arguments.each do |name, kargs| kasa << (kargs[:short_strip] || "") kala << (kargs[:long_strip] || "") end # Check that argument an option --long switches dont conflict loa_collision = kolo & kala - [""] opt_name = .keys[kolo.index(loa_collision.first) || 0] arg_name = klass_arguments.keys[kala.index(loa_collision.first) || 0] raise ArgumentError, "Collision: switch '#{loa_collision.first}' for option(#{opt_name.inspect}) and argument(#{arg_name.inspect}) cannot be the same" unless loa_collision.empty? # Check that argument an option -s short switches dont conflict soa_collision = koso & kasa - [""] opt_name = .keys[kolo.index(soa_collision.first) || 0] arg_name = klass_arguments.keys[kala.index(soa_collision.first) || 0] raise ArgumentError, "Collision: switch '#{soa_collision.first}' for option(#{opt_name.inspect}) and argument(#{arg_name.inspect}) cannot be the same" unless soa_collision.empty? # Set the default configuration values for this instance @options.each do |config_key, config_opts| config_opts[:on] ||= :on config_opts[:boolean] ||= false config_opts[:requires] ||= nil config_opts[:proc] ||= nil config_opts[:show_options] ||= false config_opts[:exit] ||= nil if config_opts.has_key?(:default) @config[config_key] = config_opts[:default] end end @arguments.each do |config_key, config_opts| config_opts[:on] ||= :on config_opts[:boolean] ||= false config_opts[:requires] ||= nil config_opts[:proc] ||= nil config_opts[:show_options] ||= false config_opts[:exit] ||= nil if config_opts.has_key?(:default) @config[config_key] = config_opts[:default] end end @options_arguments.each do |config_key, config_opts| config_opts[:on] ||= :on config_opts[:boolean] ||= false config_opts[:requires] ||= nil config_opts[:proc] ||= nil config_opts[:show_options] ||= false config_opts[:exit] ||= nil if config_opts.has_key?(:default) @config[config_key] = config_opts[:default] end end super(*args) end |
#parse_options(argv = ARGV) ⇒ Object
Parses an array, by default ARGV, for command line options (as configured at the class level).
Parameters
- argv<Array>
-
The array of arguments to parse; defaults to ARGV
Returns
- argv<Array>
-
Returns any un-parsed elements.
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 |
# File 'lib/launchr/mixin/mixlib_cli.rb', line 450 def (argv=ARGV) argv = argv.dup argv = guess_and_switchify_arguments(argv) @opt_parser = OptionParser.new do |opts| # Set the banner opts. = # Create new options .each do |opt_key, opt_val| opt_args = build_option_arguments(opt_val) opt_method = case opt_val[:on] when :on :on when :tail :on_tail when :head :on_head else raise ArgumentError, "You must pass :on, :tail, or :head to :on" end parse_block = \ Proc.new() do |*c| if c.empty? || c == [nil] c = true config[opt_key] = (opt_val[:proc] && opt_val[:proc].call(c)) || c else c = c.first config[opt_key] = (opt_val[:proc] && opt_val[:proc].call(c)) || c end puts (opts.to_s) if opt_val[:show_options] exit opt_val[:exit] if opt_val[:exit] end # opts.send(:on, *[opt_method,*opt_args, parse_block]) opt_args.unshift opt_method opt_args << parse_block opts.send(*opt_args) end end @opt_parser.summary_indent = @summary_indent if @summary_indent @opt_parser.summary_width = @summary_width if @summary_width @opt_parser.parse!(argv) @filtered_argv = argv # Deal with any required values fail = nil .each do |opt_key, opt_value| next unless config[opt_key] # next if config[opt_key] == opt_value[:default] reqargs = [] case opt_value[:requires] when nil when Proc begin result = opt_value[:requires].call(config) rescue reqargs << $!. end reqargs << result if result.class == String when Array,Symbol required_opts = [opt_value[:requires]].flatten required_opts.each do |required_opt| reqargs << required_opt.to_sym unless config[required_opt.to_sym] end reqargs.map! do |opt| arg = ([opt][:long_strip] || [opt][:short_strip]).dup arg.gsub!(/^-+/,"") if arguments.keys.include?(opt) arg end end unless reqargs.empty? fail = true opt = (opt_value[:long_strip] || opt_value[:short_strip]).dup opt.gsub!(/^-+/,"") if arguments.keys.include?(opt_key) puts "You must supply #{reqargs.join(", ")} with #{opt}!" end end if fail puts (@opt_parser.to_s) exit 2 end argv end |