commander-openflighthpc 1.0.0.pre.alpha1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +44 -0
  5. data/.rubocop_todo.yml +77 -0
  6. data/.travis.yml +14 -0
  7. data/CHANGELOG.md +5 -0
  8. data/Gemfile +3 -0
  9. data/LICENSE +51 -0
  10. data/Manifest +38 -0
  11. data/README.md +492 -0
  12. data/Rakefile +13 -0
  13. data/bin/commander +104 -0
  14. data/commander-openflighthpc.gemspec +32 -0
  15. data/lib/commander.rb +36 -0
  16. data/lib/commander/blank.rb +7 -0
  17. data/lib/commander/command.rb +263 -0
  18. data/lib/commander/configure.rb +14 -0
  19. data/lib/commander/core_ext.rb +2 -0
  20. data/lib/commander/core_ext/array.rb +24 -0
  21. data/lib/commander/core_ext/object.rb +8 -0
  22. data/lib/commander/delegates.rb +27 -0
  23. data/lib/commander/help_formatters.rb +52 -0
  24. data/lib/commander/help_formatters/base.rb +24 -0
  25. data/lib/commander/help_formatters/terminal.rb +24 -0
  26. data/lib/commander/help_formatters/terminal/command_help.erb +35 -0
  27. data/lib/commander/help_formatters/terminal/help.erb +36 -0
  28. data/lib/commander/help_formatters/terminal/subcommand_help.erb +23 -0
  29. data/lib/commander/help_formatters/terminal_compact.rb +11 -0
  30. data/lib/commander/help_formatters/terminal_compact/command_help.erb +26 -0
  31. data/lib/commander/help_formatters/terminal_compact/help.erb +29 -0
  32. data/lib/commander/help_formatters/terminal_compact/subcommand_help.erb +15 -0
  33. data/lib/commander/import.rb +5 -0
  34. data/lib/commander/methods.rb +11 -0
  35. data/lib/commander/patches/decimal-integer.rb +17 -0
  36. data/lib/commander/patches/help_formatter_binding.rb +15 -0
  37. data/lib/commander/patches/implicit-short-tags.rb +75 -0
  38. data/lib/commander/patches/option_defaults.rb +23 -0
  39. data/lib/commander/patches/validate_inputs.rb +76 -0
  40. data/lib/commander/platform.rb +7 -0
  41. data/lib/commander/runner.rb +493 -0
  42. data/lib/commander/user_interaction.rb +551 -0
  43. data/lib/commander/version.rb +3 -0
  44. data/spec/command_spec.rb +157 -0
  45. data/spec/configure_spec.rb +37 -0
  46. data/spec/core_ext/array_spec.rb +18 -0
  47. data/spec/core_ext/object_spec.rb +19 -0
  48. data/spec/help_formatters/terminal_compact_spec.rb +69 -0
  49. data/spec/help_formatters/terminal_spec.rb +67 -0
  50. data/spec/methods_spec.rb +61 -0
  51. data/spec/patches/validate_inputs_spec.rb +84 -0
  52. data/spec/runner_spec.rb +672 -0
  53. data/spec/spec_helper.rb +79 -0
  54. data/spec/ui_spec.rb +30 -0
  55. metadata +183 -0
@@ -0,0 +1,14 @@
1
+ module Commander
2
+ def configure(*configuration_opts, &configuration_block)
3
+ configuration_module = Module.new
4
+ configuration_module.extend Commander::Methods
5
+
6
+ configuration_module.class_exec(*configuration_opts, &configuration_block)
7
+
8
+ configuration_module.class_exec do
9
+ run!
10
+ end
11
+ end
12
+
13
+ module_function :configure
14
+ end
@@ -0,0 +1,2 @@
1
+ require 'commander/core_ext/array'
2
+ require 'commander/core_ext/object'
@@ -0,0 +1,24 @@
1
+ class Array
2
+ ##
3
+ # Split _string_ into an array. Used in
4
+ # conjunction with Highline's #ask, or #ask_for_array
5
+ # methods, which must respond to #parse.
6
+ #
7
+ # This method allows escaping of whitespace. For example
8
+ # the arguments foo bar\ baz will become ['foo', 'bar baz']
9
+ #
10
+ # === Example
11
+ #
12
+ # # ask invokes Array#parse
13
+ # list = ask 'Favorite cookies:', Array
14
+ #
15
+ # # or use ask_for_CLASS
16
+ # list = ask_for_array 'Favorite cookies: '
17
+ #
18
+
19
+ def self.parse(string)
20
+ # Using reverse + lookahead to work around Ruby 1.8's lack of lookbehind
21
+ # TODO: simplify now that we don't support Ruby 1.8
22
+ string.reverse.split(/\s(?!\\)/).reverse.map { |s| s.reverse.gsub('\\ ', ' ') }
23
+ end
24
+ end
@@ -0,0 +1,8 @@
1
+ class Object
2
+ ##
3
+ # Return the current binding.
4
+
5
+ def get_binding
6
+ binding
7
+ end
8
+ end
@@ -0,0 +1,27 @@
1
+ module Commander
2
+ module Delegates
3
+ %w(
4
+ add_command
5
+ command
6
+ program
7
+ error_handler
8
+ run!
9
+ global_option
10
+ alias_command
11
+ default_command
12
+ always_trace!
13
+ never_trace!
14
+ silent_trace!
15
+ ).each do |meth|
16
+ eval <<-END, binding, __FILE__, __LINE__
17
+ def #{meth}(*args, &block)
18
+ ::Commander::Runner.instance.#{meth}(*args, &block)
19
+ end
20
+ END
21
+ end
22
+
23
+ def defined_commands(*args, &block)
24
+ ::Commander::Runner.instance.commands(*args, &block)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,52 @@
1
+ module Commander
2
+ module HelpFormatter
3
+ autoload :Base, 'commander/help_formatters/base'
4
+ autoload :Terminal, 'commander/help_formatters/terminal'
5
+ autoload :TerminalCompact, 'commander/help_formatters/terminal_compact'
6
+
7
+ class Context
8
+ def initialize(target)
9
+ @target = target
10
+ end
11
+
12
+ # NOTE: `get_binding` has been stubbed! This version will be ignored
13
+ # See patch for actual version
14
+ prepend Patches::HelpFormatterBinding
15
+ def get_binding
16
+ @target.instance_eval { binding }.tap do |bind|
17
+ decorate_binding(bind)
18
+ end
19
+ end
20
+
21
+ # No-op, override in subclasses.
22
+ def decorate_binding(_bind)
23
+ end
24
+ end
25
+
26
+ class ProgramContext < Context
27
+ def decorate_binding(bind)
28
+ bind.eval("max_command_length = #{max_command_length(bind)}")
29
+ bind.eval("max_aliases_length = #{max_aliases_length(bind)}")
30
+ end
31
+
32
+ def max_command_length(bind)
33
+ max_key_length(bind.eval('@commands'))
34
+ end
35
+
36
+ def max_aliases_length(bind)
37
+ max_key_length(bind.eval('@aliases'))
38
+ end
39
+
40
+ def max_key_length(hash, default = 20)
41
+ longest = hash.keys.max_by(&:size)
42
+ longest ? longest.size : default
43
+ end
44
+ end
45
+
46
+ module_function
47
+
48
+ def indent(amount, text)
49
+ text.to_s.gsub("\n", "\n" + (' ' * amount))
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,24 @@
1
+ module Commander
2
+ ##
3
+ # = Help Formatter
4
+ #
5
+ # Commander's help formatters control the output when
6
+ # either the help command, or --help switch are called.
7
+ # The default formatter is Commander::HelpFormatter::Terminal.
8
+
9
+ module HelpFormatter
10
+ class Base
11
+ def initialize(runner)
12
+ @runner = runner
13
+ end
14
+
15
+ def render
16
+ 'Implement global help here'
17
+ end
18
+
19
+ def render_command(command)
20
+ "Implement help for #{command.name} here"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ require 'erb'
2
+
3
+ module Commander
4
+ module HelpFormatter
5
+ class Terminal < Base
6
+ def render
7
+ template(:help).result(ProgramContext.new(@runner).get_binding)
8
+ end
9
+
10
+ def render_command(command)
11
+ template(:command_help).result(Context.new(command).get_binding)
12
+ end
13
+
14
+ def render_subcommand(command)
15
+ bind = ProgramContext.new(@runner).get_binding({cmd: command})
16
+ template(:subcommand_help).result(bind)
17
+ end
18
+
19
+ def template(name)
20
+ ERB.new(File.read(File.join(File.dirname(__FILE__), 'terminal', "#{name}.erb")), nil, '-')
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,35 @@
1
+ <% if !@syntax -%>
2
+ <%= $terminal.color "NAME", :bold %>:
3
+
4
+ <%= @name %>
5
+ <% else -%>
6
+ <%= $terminal.color "SYNOPSIS", :bold %>:
7
+
8
+ <%= @syntax -%>
9
+
10
+ <% end -%>
11
+
12
+ <%= $terminal.color "DESCRIPTION", :bold %>:
13
+
14
+ <%= Commander::HelpFormatter.indent 4, (@description || @summary || 'No description.') -%>
15
+
16
+ <% unless @examples.empty? -%>
17
+
18
+ <%= $terminal.color "EXAMPLES", :bold %>:
19
+ <% for description, command in @examples -%>
20
+
21
+ # <%= description %>
22
+ <%= command %>
23
+ <% end -%>
24
+ <% end -%>
25
+ <% unless @options.empty? -%>
26
+
27
+ <%= $terminal.color "OPTIONS", :bold %>:
28
+ <% for option in @options -%>
29
+
30
+ <%= option[:switches].join ', ' %>
31
+ <%= Commander::HelpFormatter.indent 8, option[:description] %><% if option[:default] %>
32
+ <%= $terminal.color "Default", :bold %>: <%= option[:default] %><% end %>
33
+ <% end -%>
34
+ <% end -%>
35
+
@@ -0,0 +1,36 @@
1
+ <%= $terminal.color "NAME", :bold %>:
2
+
3
+ <%= program :name %>
4
+
5
+ <%= $terminal.color "DESCRIPTION", :bold %>:
6
+
7
+ <%= Commander::HelpFormatter.indent 4, program(:description) %>
8
+
9
+ <%= $terminal.color "COMMANDS", :bold %>:
10
+ <% for name, command in @help_commands.sort -%>
11
+ <% unless alias? name %>
12
+ <%= "%-#{max_command_length}s %s" % [command.name, command.summary || command.description] -%>
13
+ <% end -%>
14
+ <% end %>
15
+ <% unless @aliases.empty? %>
16
+ <%= $terminal.color "ALIASES", :bold %>:
17
+ <% for alias_name, args in @aliases.sort %>
18
+ <%= "%-#{max_aliases_length}s %s %s" % [alias_name, command(alias_name).name, args.join(' ')] -%>
19
+ <% end %>
20
+ <% end %>
21
+ <% unless @help_options.empty? -%>
22
+ <%= $terminal.color "GLOBAL OPTIONS", :bold %>:
23
+ <% for option in @help_options -%>
24
+
25
+ <%= option[:switches].join ', ' %>
26
+ <%= option[:description] %>
27
+ <% end -%>
28
+ <% end -%>
29
+ <% if program :help -%>
30
+ <% for title, body in program(:help) %>
31
+ <%= $terminal.color title.to_s.upcase, :bold %>:
32
+
33
+ <%= body %>
34
+ <% end -%>
35
+ <% end -%>
36
+
@@ -0,0 +1,23 @@
1
+ <% if !cmd.syntax %>
2
+ <%= $terminal.color "NAME", :bold %>:
3
+
4
+ <%= cmd.name %>
5
+ <% else -%>
6
+ <%= $terminal.color "SYNOPSIS", :bold %>:
7
+
8
+ <%= cmd.syntax -%>
9
+
10
+ <% end -%>
11
+
12
+ <%= $terminal.color "DESCRIPTION", :bold %>:
13
+
14
+ <%= Commander::HelpFormatter.indent 4, (cmd.description || cmd.summary || 'No description.') -%>
15
+
16
+
17
+ <%= $terminal.color "SUBCOMMANDS", :bold %>:
18
+ <% for name, command in @commands.sort -%>
19
+ <% unless alias? name %>
20
+ <%= "%-#{max_command_length}s %s" % [command.name, command.summary || command.description] -%>
21
+ <% end -%>
22
+ <% end %>
23
+
@@ -0,0 +1,11 @@
1
+ require 'erb'
2
+
3
+ module Commander
4
+ module HelpFormatter
5
+ class TerminalCompact < Terminal
6
+ def template(name)
7
+ ERB.new(File.read(File.join(File.dirname(__FILE__), 'terminal_compact', "#{name}.erb")), nil, '-')
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ <%= @name %>
2
+ <% if @syntax -%>
3
+
4
+ Usage: <%= @syntax %>
5
+ <% end -%>
6
+ <% if @description || @summary -%>
7
+
8
+ <%= @description || @summary %>
9
+ <% end -%>
10
+ <% unless @examples.empty? -%>
11
+
12
+ Examples:
13
+ <% for description, command in @examples -%>
14
+
15
+ # <%= description %>
16
+ <%= command %>
17
+ <% end -%>
18
+ <% end -%>
19
+ <% unless @options.empty? -%>
20
+
21
+ Options:
22
+ <% for option in @options -%>
23
+ <%= "%-20s %s" % [option[:switches].join(', '), option[:description]] %><% if option[:default] %> <%= option[:default] %><% end %>
24
+ <% end -%>
25
+ <% end -%>
26
+
@@ -0,0 +1,29 @@
1
+ <%= program :name %>
2
+
3
+ <%= program :description %>
4
+
5
+ Commands:
6
+ <% for name, command in @help_commands.sort -%>
7
+ <% unless alias? name -%>
8
+ <%= "%-#{max_command_length}s %s" % [command.name, command.summary || command.description] %>
9
+ <% end -%>
10
+ <% end -%>
11
+ <% unless @aliases.empty? %>
12
+ Aliases:
13
+ <% for alias_name, args in @aliases.sort -%>
14
+ <%= "%-#{max_aliases_length}s %s %s" % [alias_name, command(alias_name).name, args.join(' ')] %>
15
+ <% end -%>
16
+ <% end %>
17
+ <% unless @help_options.empty? -%>
18
+ Global Options:
19
+ <% for option in @help_options -%>
20
+ <%= "%-20s %s" % [option[:switches].join(', '), option[:description]] -%>
21
+ <% end -%>
22
+ <% end -%>
23
+ <% if program :help -%>
24
+ <% for title, body in program(:help) %>
25
+ <%= title %>:
26
+ <%= body %>
27
+ <% end %>
28
+ <% end -%>
29
+
@@ -0,0 +1,15 @@
1
+ <%= cmd.name %>
2
+ <% if cmd.syntax -%>
3
+
4
+ Usage: <%= cmd.syntax %>
5
+ <% end -%>
6
+ <% if cmd.description || cmd.summary -%>
7
+
8
+ <%= cmd.description || cmd.summary %>
9
+ <% end -%>
10
+
11
+ <% for name, command in @commands.sort -%>
12
+ <% unless alias? name -%>
13
+ <%= "%-#{max_command_length}s %s" % [command.name, command.summary || command.description] %>
14
+ <% end -%>
15
+ <% end -%>
@@ -0,0 +1,5 @@
1
+ require 'commander'
2
+
3
+ include Commander::Methods
4
+
5
+ at_exit { run! }
@@ -0,0 +1,11 @@
1
+ module Commander
2
+ module Methods
3
+ include Commander::UI
4
+ include Commander::UI::AskForClass
5
+ include Commander::Delegates
6
+
7
+ if $stdin.tty? && (cols = $terminal.output_cols) >= 40
8
+ $terminal.wrap_at = cols - 5
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ # Patches the underling OptionParser DecimalInteger type so that it doesn't
2
+ # convert numbers starting with a '0' as if they are an Octal number
3
+ module Commander
4
+ module Patches
5
+ module DecimalInteger
6
+ decimal = '\d+(?:_\d+)*'
7
+ DecimalInteger = /\A[-+]?#{decimal}\z/io
8
+ ::OptionParser::accept(DecimalInteger, DecimalInteger) {|s,|
9
+ begin
10
+ Integer(s, 10)
11
+ rescue ArgumentError
12
+ raise ::OptionParser::InvalidArgument, s
13
+ end if s
14
+ }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ module Commander
2
+ module Patches
3
+ module HelpFormatterBinding
4
+ def get_binding(additional = {})
5
+ bnd = @target.instance_eval { binding }.tap do |bind|
6
+ decorate_binding(bind)
7
+ end
8
+ additional.each do |k, v|
9
+ bnd.local_variable_set(k, v)
10
+ end
11
+ bnd
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,75 @@
1
+ # Patches the underling ruby OptionParser to prevent it from automatically
2
+ # generating short tags for options
3
+ module Commander
4
+ module Patches
5
+ module ImplicitShortTags
6
+ def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc:
7
+ opt, arg, val, rest = nil
8
+ nonopt ||= proc {|a| throw :terminate, a}
9
+ argv.unshift(arg) if arg = catch(:terminate) {
10
+ while arg = argv.shift
11
+ case arg
12
+ # long option
13
+ when /\A--([^=]*)(?:=(.*))?/m
14
+ opt, rest = $1, $2
15
+ opt.tr!('_', '-')
16
+ begin
17
+ sw, = complete(:long, opt, true)
18
+ rescue ::OptionParser::ParseError
19
+ raise $!.set_option(arg, true)
20
+ end
21
+ begin
22
+ opt, cb, val = sw.parse(rest, argv) {|*exc| raise(*exc)}
23
+ val = cb.call(val) if cb
24
+ setter.call(sw.switch_name, val) if setter
25
+ rescue ::OptionParser::ParseError
26
+ raise $!.set_option(arg, rest)
27
+ end
28
+
29
+ # short option
30
+ when /\A-(.)((=).*|.+)?/m
31
+ eq, rest, opt = $3, $2, $1
32
+ has_arg, val = eq, rest
33
+ begin
34
+ sw, = search(:short, opt)
35
+ unless sw
36
+ sw, = complete(:short, opt)
37
+ # short option matched.
38
+ val = arg.sub(/\A-/, '')
39
+ has_arg = true
40
+ end
41
+ rescue ::OptionParser::ParseError
42
+ raise $!.set_option(arg, true)
43
+ end
44
+ begin
45
+ opt, cb, val = sw.parse(val, argv) {|*exc| raise(*exc) if eq}
46
+ raise InvalidOption, arg if has_arg and !eq and arg == "-#{opt}"
47
+ argv.unshift(opt) if opt and (!rest or (opt = opt.sub(/\A-*/, '-')) != '-')
48
+ val = cb.call(val) if cb
49
+ setter.call(sw.switch_name, val) if setter
50
+ rescue ::OptionParser::ParseError
51
+ raise $!.set_option(arg, arg.length > 2)
52
+ end
53
+
54
+ # non-option argument
55
+ else
56
+ catch(:prune) do
57
+ visit(:each_option) do |sw0|
58
+ sw = sw0
59
+ sw.block.call(arg) if ::OptionParser::Switch === sw and sw.match_nonswitch?(arg)
60
+ end
61
+ nonopt.call(arg)
62
+ end
63
+ end
64
+ end
65
+
66
+ nil
67
+ }
68
+
69
+ visit(:search, :short, nil) {|sw| sw.block.call(*argv) if !sw.pattern}
70
+
71
+ argv
72
+ end
73
+ end
74
+ end
75
+ end