commander-openflighthpc 1.0.0.pre.alpha1

Sign up to get free protection for your applications and to get access to all the features.
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