hammer_cli 0.0.18 → 0.1.0
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.
- checksums.yaml +4 -4
- data/README.md +3 -314
- data/bin/hammer +45 -6
- data/config/cli.modules.d/module_config_template.yml +4 -0
- data/config/cli_config.template.yml +9 -11
- data/doc/developer_docs.md +1 -0
- data/doc/i18n.md +85 -0
- data/doc/installation.md +321 -0
- data/lib/hammer_cli.rb +3 -0
- data/lib/hammer_cli/abstract.rb +15 -24
- data/lib/hammer_cli/apipie/command.rb +13 -7
- data/lib/hammer_cli/apipie/options.rb +14 -16
- data/lib/hammer_cli/apipie/read_command.rb +6 -1
- data/lib/hammer_cli/apipie/resource.rb +48 -58
- data/lib/hammer_cli/apipie/write_command.rb +5 -1
- data/lib/hammer_cli/completer.rb +77 -21
- data/lib/hammer_cli/connection.rb +44 -0
- data/lib/hammer_cli/exception_handler.rb +15 -4
- data/lib/hammer_cli/exceptions.rb +6 -0
- data/lib/hammer_cli/i18n.rb +95 -0
- data/lib/hammer_cli/logger.rb +3 -3
- data/lib/hammer_cli/main.rb +12 -11
- data/lib/hammer_cli/modules.rb +19 -6
- data/lib/hammer_cli/options/normalizers.rb +42 -7
- data/lib/hammer_cli/options/option_definition.rb +2 -2
- data/lib/hammer_cli/output.rb +1 -0
- data/lib/hammer_cli/output/adapter/abstract.rb +20 -0
- data/lib/hammer_cli/output/adapter/base.rb +49 -78
- data/lib/hammer_cli/output/adapter/csv.rb +5 -5
- data/lib/hammer_cli/output/adapter/table.rb +41 -10
- data/lib/hammer_cli/output/dsl.rb +1 -1
- data/lib/hammer_cli/output/field_filter.rb +21 -0
- data/lib/hammer_cli/output/fields.rb +44 -78
- data/lib/hammer_cli/output/formatters.rb +38 -0
- data/lib/hammer_cli/settings.rb +28 -6
- data/lib/hammer_cli/shell.rb +58 -57
- data/lib/hammer_cli/utils.rb +14 -0
- data/lib/hammer_cli/validator.rb +5 -5
- data/lib/hammer_cli/version.rb +1 -1
- data/locale/Makefile +64 -0
- data/locale/hammer-cli.pot +203 -0
- data/locale/zanata.xml +29 -0
- data/test/unit/apipie/command_test.rb +42 -25
- data/test/unit/apipie/read_command_test.rb +10 -7
- data/test/unit/apipie/write_command_test.rb +9 -8
- data/test/unit/completer_test.rb +206 -21
- data/test/unit/connection_test.rb +68 -0
- data/test/unit/fixtures/apipie/architectures.json +153 -0
- data/test/unit/fixtures/apipie/documented.json +79 -0
- data/test/unit/fixtures/json_input/invalid.json +12 -0
- data/test/unit/fixtures/json_input/valid.json +12 -0
- data/test/unit/history_test.rb +71 -0
- data/test/unit/main_test.rb +9 -0
- data/test/unit/modules_test.rb +22 -6
- data/test/unit/options/field_filter_test.rb +27 -0
- data/test/unit/options/normalizers_test.rb +53 -0
- data/test/unit/output/adapter/base_test.rb +162 -10
- data/test/unit/output/adapter/csv_test.rb +16 -3
- data/test/unit/output/adapter/table_test.rb +97 -13
- data/test/unit/output/dsl_test.rb +74 -6
- data/test/unit/output/fields_test.rb +93 -62
- data/test/unit/output/formatters_test.rb +47 -0
- data/test/unit/settings_test.rb +35 -4
- data/test/unit/utils_test.rb +45 -0
- metadata +85 -4
- data/test/unit/apipie/fake_api.rb +0 -101
@@ -28,7 +28,7 @@ module HammerCLI::Apipie
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def self.desc(desc=nil)
|
31
|
-
super(desc) || resource.
|
31
|
+
super(desc) || resource.action(action).apidoc[:apis][0][:short_description] || " "
|
32
32
|
rescue
|
33
33
|
" "
|
34
34
|
end
|
@@ -65,9 +65,9 @@ module HammerCLI::Apipie
|
|
65
65
|
private
|
66
66
|
|
67
67
|
def self.setup_identifier_options
|
68
|
-
identifier_option(:id, "resource id", declared_identifiers[:id]) if identifier? :id
|
69
|
-
identifier_option(:name, "resource name", declared_identifiers[:name]) if identifier? :name
|
70
|
-
identifier_option(:label, "resource label", declared_identifiers[:label]) if identifier? :label
|
68
|
+
identifier_option(:id, _("resource id"), declared_identifiers[:id]) if identifier? :id
|
69
|
+
identifier_option(:name, _("resource name"), declared_identifiers[:name]) if identifier? :name
|
70
|
+
identifier_option(:label, _("resource label"), declared_identifiers[:label]) if identifier? :label
|
71
71
|
end
|
72
72
|
|
73
73
|
def self.identifier_option(name, desc, attr_name)
|
@@ -83,10 +83,16 @@ module HammerCLI::Apipie
|
|
83
83
|
end
|
84
84
|
|
85
85
|
def name_to_id(name, option_name, resource)
|
86
|
-
results = resource.call(:index, :search => "#{option_name} = #{name}")
|
86
|
+
results = resource.call(:index, :search => "#{option_name} = #{name}")
|
87
87
|
results = HammerCLIForeman.collection_to_common_format(results)
|
88
|
-
|
89
|
-
|
88
|
+
|
89
|
+
msg_opts = {
|
90
|
+
:resource => resource.name,
|
91
|
+
:option => option_name,
|
92
|
+
:value => name
|
93
|
+
}
|
94
|
+
raise _("%{resource} with %{option} '%{value}' not found") % msg_opts if results.empty?
|
95
|
+
raise _("%{resource} with %{option} '%{value}' found more than once") % msg_opts if results.count > 1
|
90
96
|
results[0]['id']
|
91
97
|
end
|
92
98
|
|
@@ -7,20 +7,20 @@ module HammerCLI::Apipie
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def all_method_options
|
10
|
-
method_options_for_params(resource.
|
10
|
+
method_options_for_params(resource.action(action).params, true)
|
11
11
|
end
|
12
12
|
|
13
13
|
def method_options
|
14
|
-
method_options_for_params(resource.
|
14
|
+
method_options_for_params(resource.action(action).params, false)
|
15
15
|
end
|
16
16
|
|
17
17
|
def method_options_for_params(params, include_nil=true)
|
18
18
|
opts = {}
|
19
19
|
params.each do |p|
|
20
|
-
if p
|
21
|
-
opts[p
|
20
|
+
if p.expected_type == :hash
|
21
|
+
opts[p.name] = method_options_for_params(p.params, include_nil)
|
22
22
|
else
|
23
|
-
opts[p
|
23
|
+
opts[p.name] = get_option_value(p.name)
|
24
24
|
end
|
25
25
|
end
|
26
26
|
opts.reject! {|key, value| value.nil? } unless include_nil
|
@@ -44,7 +44,7 @@ module HammerCLI::Apipie
|
|
44
44
|
filter = Array(filter)
|
45
45
|
filter += declared_identifiers.keys
|
46
46
|
|
47
|
-
options_for_params(resource.
|
47
|
+
options_for_params(resource.action(action).params, filter)
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
@@ -52,9 +52,9 @@ module HammerCLI::Apipie
|
|
52
52
|
|
53
53
|
def options_for_params(params, filter)
|
54
54
|
params.each do |p|
|
55
|
-
next if filter.include?
|
56
|
-
if p
|
57
|
-
options_for_params(p
|
55
|
+
next if filter.include?(p.name) || filter.include?(p.name.to_sym)
|
56
|
+
if p.expected_type == :hash
|
57
|
+
options_for_params(p.params, filter)
|
58
58
|
else
|
59
59
|
create_option p
|
60
60
|
end
|
@@ -71,25 +71,23 @@ module HammerCLI::Apipie
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def option_switches(param)
|
74
|
-
'--' + param
|
74
|
+
'--' + param.name.gsub('_', '-')
|
75
75
|
end
|
76
76
|
|
77
77
|
def option_type(param)
|
78
|
-
param
|
78
|
+
param.name.upcase.gsub('-', '_')
|
79
79
|
end
|
80
80
|
|
81
81
|
def option_desc(param)
|
82
|
-
|
83
|
-
return " " if desc.empty?
|
84
|
-
return desc
|
82
|
+
param.description || " "
|
85
83
|
end
|
86
84
|
|
87
85
|
def option_opts(param)
|
88
86
|
opts = {}
|
89
|
-
opts[:required] = true if param
|
87
|
+
opts[:required] = true if param.required?
|
90
88
|
# FIXME: There is a bug in apipie, it does not produce correct expected type for Arrays
|
91
89
|
# When it's fixed, we should test param["expected_type"] == "array"
|
92
|
-
opts[:format] = HammerCLI::Options::Normalizers::List.new if param
|
90
|
+
opts[:format] = HammerCLI::Options::Normalizers::List.new if param.validator.include? "Array"
|
93
91
|
return opts
|
94
92
|
end
|
95
93
|
|
@@ -14,7 +14,12 @@ module HammerCLI::Apipie
|
|
14
14
|
protected
|
15
15
|
def retrieve_data
|
16
16
|
raise "resource or action not defined" unless self.class.resource_defined?
|
17
|
-
|
17
|
+
logger.debug request_params.ai
|
18
|
+
if resource && resource.has_action?(action)
|
19
|
+
resource.call(action, request_params, request_headers)
|
20
|
+
else
|
21
|
+
raise HammerCLI::OperationNotSupportedError, "The server does not support such operation."
|
22
|
+
end
|
18
23
|
end
|
19
24
|
|
20
25
|
def print_data(records)
|
@@ -1,64 +1,36 @@
|
|
1
|
+
require 'apipie_bindings'
|
1
2
|
module HammerCLI::Apipie
|
2
3
|
|
3
|
-
class
|
4
|
+
class AbstractCredentials
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
def initialize(resource_class)
|
8
|
-
@resource_class = resource_class
|
9
|
-
end
|
10
|
-
|
11
|
-
def name
|
12
|
-
resource_class.name.split("::")[-1].downcase
|
6
|
+
def to_params
|
7
|
+
{}
|
13
8
|
end
|
14
9
|
|
15
|
-
|
16
|
-
irregular_names = {
|
17
|
-
"statistics" => "statistics",
|
18
|
-
"home" => "home",
|
19
|
-
"host_class" => "host_classes",
|
20
|
-
"medium" => "media",
|
21
|
-
"puppetclass" => "puppetclasses",
|
22
|
-
"dashboard" => "dashboard",
|
23
|
-
"smart_proxy" => "smart_proxies",
|
24
|
-
"settings" => "settings",
|
25
|
-
"hostgroup_class" => "hostgroup_classes"
|
26
|
-
}
|
27
|
-
irregular_names[name] || "%ss" % name
|
28
|
-
end
|
10
|
+
private
|
29
11
|
|
30
|
-
def
|
31
|
-
|
32
|
-
|
12
|
+
def ask_user(prompt, silent=false)
|
13
|
+
if silent
|
14
|
+
ask(prompt) {|q| q.echo = false}
|
15
|
+
else
|
16
|
+
ask(prompt)
|
33
17
|
end
|
34
|
-
raise "No method documentation found for #{resource_class}##{method_name}"
|
35
18
|
end
|
36
19
|
|
37
20
|
end
|
38
21
|
|
39
22
|
|
40
|
-
class
|
23
|
+
class ApipieConnector < HammerCLI::AbstractConnector
|
41
24
|
|
42
|
-
|
43
|
-
super(resource_class)
|
44
|
-
@instance = resource_class.new(config)
|
45
|
-
end
|
25
|
+
attr_reader :api
|
46
26
|
|
47
|
-
def
|
48
|
-
|
49
|
-
|
27
|
+
def initialize(params)
|
28
|
+
credentials = params.delete(:credentials)
|
29
|
+
params.merge!(credentials.to_params) if credentials
|
50
30
|
|
51
|
-
|
52
|
-
Logging.logger[resource_class.name].debug "Calling '#{method_name}' with params #{params.ai}" if HammerCLI::Settings.get(:log_api_calls)
|
53
|
-
result = instance.send(method_name, params, headers)
|
54
|
-
Logging.logger[resource_class.name].debug "Method '#{method_name}' responded with #{result[0].ai}" if HammerCLI::Settings.get(:log_api_calls)
|
55
|
-
result
|
31
|
+
@api = ApipieBindings::API.new(params)
|
56
32
|
end
|
57
33
|
|
58
|
-
private
|
59
|
-
|
60
|
-
attr_reader :instance
|
61
|
-
|
62
34
|
end
|
63
35
|
|
64
36
|
|
@@ -69,13 +41,7 @@ module HammerCLI::Apipie
|
|
69
41
|
end
|
70
42
|
|
71
43
|
def resource
|
72
|
-
|
73
|
-
# or its superclass try to look it up in parent command's class
|
74
|
-
if self.class.resource
|
75
|
-
return ResourceInstance.from_definition(self.class.resource, resource_config)
|
76
|
-
else
|
77
|
-
return ResourceInstance.from_definition(self.parent_command.class.resource, resource_config)
|
78
|
-
end
|
44
|
+
self.class.resource || self.parent_command.class.resource
|
79
45
|
end
|
80
46
|
|
81
47
|
def action
|
@@ -83,15 +49,29 @@ module HammerCLI::Apipie
|
|
83
49
|
end
|
84
50
|
|
85
51
|
def resource_config
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
52
|
+
self.class.resource_config
|
53
|
+
end
|
54
|
+
|
55
|
+
def connection_options
|
56
|
+
self.class.connection_options
|
91
57
|
end
|
92
58
|
|
93
59
|
module ClassMethods
|
94
60
|
|
61
|
+
def resource_config
|
62
|
+
{}
|
63
|
+
end
|
64
|
+
|
65
|
+
def connection_options
|
66
|
+
{
|
67
|
+
:connector => HammerCLI::Apipie::ApipieConnector
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
def connection_name(resource_class)
|
72
|
+
:apipie
|
73
|
+
end
|
74
|
+
|
95
75
|
def class_resource
|
96
76
|
return @api_resource if @api_resource
|
97
77
|
return superclass.class_resource if superclass.respond_to? :class_resource
|
@@ -106,8 +86,18 @@ module HammerCLI::Apipie
|
|
106
86
|
end
|
107
87
|
end
|
108
88
|
|
109
|
-
def resource(
|
110
|
-
|
89
|
+
def resource(resource=nil, action=nil)
|
90
|
+
unless resource.nil?
|
91
|
+
api = HammerCLI::Connection.create(
|
92
|
+
connection_name(resource),
|
93
|
+
resource_config,
|
94
|
+
connection_options).api
|
95
|
+
if api.has_resource?(resource)
|
96
|
+
@api_resource = api.resource(resource)
|
97
|
+
else
|
98
|
+
logger.warn "Resource '#{resource}' does not exist in the API"
|
99
|
+
end
|
100
|
+
end
|
111
101
|
@api_action = action unless action.nil?
|
112
102
|
|
113
103
|
# if the resource definition is not available in this class
|
@@ -27,7 +27,11 @@ module HammerCLI::Apipie
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def send_request
|
30
|
-
resource.
|
30
|
+
if resource && resource.has_action?(action)
|
31
|
+
resource.call(action, request_params, request_headers)
|
32
|
+
else
|
33
|
+
raise HammerCLI::OperationNotSupportedError, "The server does not support such operation."
|
34
|
+
end
|
31
35
|
end
|
32
36
|
|
33
37
|
def request_headers
|
data/lib/hammer_cli/completer.rb
CHANGED
@@ -1,30 +1,77 @@
|
|
1
1
|
require 'enumerator'
|
2
2
|
|
3
|
+
|
3
4
|
module HammerCLI
|
4
5
|
|
6
|
+
# Single "word" on a command line to complete.
|
7
|
+
# It contains trailing spaces to recognize whether the word is complete or not.
|
8
|
+
# --param[ ]* or -flag[ ]* or ['"]?word['"]?[ ]*
|
9
|
+
class CompleterWord < String
|
10
|
+
|
11
|
+
def initialize(str)
|
12
|
+
@original = str
|
13
|
+
if quoted?
|
14
|
+
str = str.gsub(/^['"]/, '').gsub(/['"]\s*$/, '')
|
15
|
+
else
|
16
|
+
str = str.strip
|
17
|
+
end
|
18
|
+
super(str)
|
19
|
+
end
|
20
|
+
|
21
|
+
def quoted?
|
22
|
+
quote != ""
|
23
|
+
end
|
24
|
+
|
25
|
+
def quote
|
26
|
+
@original.gsub(/^(['"]?)(.*)$/, '\1')
|
27
|
+
end
|
28
|
+
|
29
|
+
def complete?
|
30
|
+
if quoted?
|
31
|
+
@original.strip.gsub(/^['"].*['"][\s]*$/, '') == ""
|
32
|
+
else
|
33
|
+
@original[-1,1] == " "
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# Array of command line words for completion.
|
41
|
+
# Splits string line to "words" with trailing spaces.
|
42
|
+
# --param[=]?[ ]* or -flag[ ]* or ['"]word['"]?[ ]*
|
5
43
|
class CompleterLine < Array
|
6
44
|
|
7
45
|
def initialize(line)
|
8
46
|
@line = line
|
9
|
-
super(
|
47
|
+
super(split_line)
|
48
|
+
end
|
49
|
+
|
50
|
+
def complete?
|
51
|
+
self.empty? || self.last.complete?
|
10
52
|
end
|
11
53
|
|
12
|
-
|
13
|
-
|
54
|
+
protected
|
55
|
+
|
56
|
+
def split_line
|
57
|
+
@line.scan(/-[\w\-]+=?[\s]*|["][^"]*["]?[\s]*|['][^']*[']?[\s]*|[^\s]+[\s]*/).collect do |word|
|
58
|
+
CompleterWord.new(word.gsub(/=$/, ' '))
|
59
|
+
end
|
14
60
|
end
|
15
61
|
|
16
62
|
end
|
17
63
|
|
64
|
+
|
18
65
|
class Completer
|
19
66
|
|
20
67
|
def initialize(cmd_class)
|
21
68
|
@command = cmd_class
|
22
69
|
end
|
23
70
|
|
24
|
-
|
25
71
|
def complete(line)
|
26
72
|
line = CompleterLine.new(line)
|
27
73
|
|
74
|
+
# get the last command on the line
|
28
75
|
cmd, remaining = find_last_cmd(line)
|
29
76
|
|
30
77
|
opt, value = option_to_complete(cmd, remaining)
|
@@ -33,7 +80,7 @@ module HammerCLI
|
|
33
80
|
else
|
34
81
|
param, value = param_to_complete(cmd, remaining)
|
35
82
|
if param
|
36
|
-
if remaining.
|
83
|
+
if remaining.complete?
|
37
84
|
return complete_attribute(param, value) + complete_command(cmd, remaining)
|
38
85
|
else
|
39
86
|
return complete_attribute(param, value)
|
@@ -50,12 +97,25 @@ module HammerCLI
|
|
50
97
|
|
51
98
|
def complete_attribute(attribute, value)
|
52
99
|
if attribute.respond_to?(:complete)
|
53
|
-
|
100
|
+
if value != nil and value.quoted?
|
101
|
+
filter(attribute.complete(value), value).map do |completion|
|
102
|
+
quote_value(completion, value.quote)
|
103
|
+
end
|
104
|
+
else
|
105
|
+
filter(attribute.complete(value), value)
|
106
|
+
end
|
54
107
|
else
|
55
108
|
[]
|
56
109
|
end
|
57
110
|
end
|
58
111
|
|
112
|
+
def quote_value(val, quotes)
|
113
|
+
if val[-1,1] == ' '
|
114
|
+
quotes + val.strip + quotes + ' '
|
115
|
+
else
|
116
|
+
quotes + val
|
117
|
+
end
|
118
|
+
end
|
59
119
|
|
60
120
|
def param_to_complete(cmd, line)
|
61
121
|
params = cmd.parameters.select do |p|
|
@@ -73,7 +133,7 @@ module HammerCLI
|
|
73
133
|
|
74
134
|
param = nil
|
75
135
|
|
76
|
-
if line.
|
136
|
+
if line.complete?
|
77
137
|
# "--option " or "--option xx " or "xx "
|
78
138
|
value = nil
|
79
139
|
param_index = param_candidates.size
|
@@ -94,33 +154,35 @@ module HammerCLI
|
|
94
154
|
return [param, value]
|
95
155
|
end
|
96
156
|
|
97
|
-
|
98
157
|
def option_to_complete(cmd, line)
|
99
158
|
return [nil, nil] if line.empty?
|
100
159
|
|
101
|
-
if line.
|
160
|
+
if line.complete?
|
102
161
|
# last word must be option and can't be flag -> we complete the value
|
103
|
-
# "--option "
|
104
|
-
opt =
|
162
|
+
# "--option " or "--option xx "
|
163
|
+
opt = find_option(cmd, line[-1])
|
105
164
|
return [opt, nil] if opt and not opt.flag?
|
106
165
|
else
|
107
166
|
# we complete the value in the second case
|
108
167
|
# "--opt" or "--option xx" or "xx yy"
|
109
|
-
opt =
|
168
|
+
opt = find_option(cmd, line[-2])
|
110
169
|
return [opt, line[-1]] if opt and not opt.flag?
|
111
170
|
end
|
112
171
|
return [nil, nil]
|
113
172
|
end
|
114
173
|
|
174
|
+
def find_option(cmd, switch)
|
175
|
+
cmd.find_option(switch) unless switch.nil?
|
176
|
+
end
|
115
177
|
|
116
178
|
def find_last_cmd(line)
|
117
179
|
cmd = @command
|
118
180
|
subcommands = sub_command_map(cmd)
|
119
181
|
|
120
|
-
# if the last word is not
|
182
|
+
# if the last word is not complete we have to select it's parent
|
121
183
|
# -> shorten the line
|
122
184
|
words = line.dup
|
123
|
-
words.pop unless line.
|
185
|
+
words.pop unless line.complete?
|
124
186
|
|
125
187
|
cmd_idx = 0
|
126
188
|
words.each_with_index do |word, idx|
|
@@ -139,21 +201,19 @@ module HammerCLI
|
|
139
201
|
return [cmd, remaining]
|
140
202
|
end
|
141
203
|
|
142
|
-
|
143
204
|
def complete_command(command, remaining)
|
144
205
|
completions = []
|
145
206
|
completions += sub_command_names(command)
|
146
207
|
completions += command_options(command)
|
147
208
|
completions = Completer::finalize_completions(completions)
|
148
209
|
|
149
|
-
if remaining.
|
210
|
+
if remaining.complete?
|
150
211
|
return completions
|
151
212
|
else
|
152
213
|
return filter(completions, remaining.last)
|
153
214
|
end
|
154
215
|
end
|
155
216
|
|
156
|
-
|
157
217
|
def filter(completions, last_word)
|
158
218
|
if last_word.to_s != ""
|
159
219
|
completions.select{|name| name.start_with? last_word }
|
@@ -162,12 +222,10 @@ module HammerCLI
|
|
162
222
|
end
|
163
223
|
end
|
164
224
|
|
165
|
-
|
166
225
|
def self.finalize_completions(completions)
|
167
226
|
completions.collect{|name| name+' ' }
|
168
227
|
end
|
169
228
|
|
170
|
-
|
171
229
|
def sub_command_map(cmd_class)
|
172
230
|
cmd_class.recognised_subcommands.inject({}) do |cmd_map, cmd|
|
173
231
|
cmd.names.each do |name|
|
@@ -177,12 +235,10 @@ module HammerCLI
|
|
177
235
|
end
|
178
236
|
end
|
179
237
|
|
180
|
-
|
181
238
|
def sub_command_names(cmd_class)
|
182
239
|
sub_command_map(cmd_class).keys.flatten
|
183
240
|
end
|
184
241
|
|
185
|
-
|
186
242
|
def command_options(cmd_class)
|
187
243
|
cmd_class.recognised_options.inject([]) do |opt_switches, opt|
|
188
244
|
opt_switches += opt.switches
|