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