hammer_cli 2.0.0 → 2.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/doc/commands_extension.md +12 -0
- data/doc/creating_commands.md +73 -0
- data/doc/release_notes.md +7 -0
- data/lib/hammer_cli/abstract.rb +29 -2
- data/lib/hammer_cli/apipie/option_builder.rb +15 -13
- data/lib/hammer_cli/apipie/option_definition.rb +9 -7
- data/lib/hammer_cli/command_extensions.rb +21 -1
- data/lib/hammer_cli/exception_handler.rb +1 -1
- data/lib/hammer_cli/full_help.rb +8 -1
- data/lib/hammer_cli/help/builder.rb +29 -3
- data/lib/hammer_cli/options/option_definition.rb +4 -6
- data/lib/hammer_cli/options/option_family.rb +114 -0
- data/lib/hammer_cli/subcommand.rb +25 -1
- data/lib/hammer_cli/testing/command_assertions.rb +2 -2
- data/lib/hammer_cli/utils.rb +17 -0
- data/lib/hammer_cli/version.rb +1 -1
- data/locale/ca/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/de/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/en/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/en_GB/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/es/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/fr/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/it/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/ja/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/ko/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/pt_BR/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/ru/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/zh_CN/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/zh_TW/LC_MESSAGES/hammer-cli.mo +0 -0
- data/test/unit/abstract_test.rb +23 -2
- data/test/unit/apipie/option_builder_test.rb +8 -0
- data/test/unit/command_extensions_test.rb +67 -49
- data/test/unit/help/builder_test.rb +22 -0
- data/test/unit/options/option_family_test.rb +48 -0
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f5401e68d37a678eb6193e892c4d148c165260a0e90f3a11c9dc2e2d49d464ae
|
4
|
+
data.tar.gz: 21d2f0466c0c433033e2bdbaf8aad4d8f3ea6a51261f4f695a135cb1e9f5b5c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c50b60e009c0f48736b540a4d7dcf39db860a8b128542aa15495ac5ae6bdc2c0c3eccf92e098b7c81ac55e90dbe295c5310fa1fd5e39d084e790c379171eeba2
|
7
|
+
data.tar.gz: 2482f77220d681fba21493cf80473132379127ef580c45dfe8293f2e5fb5ff420ba75c4276e4dfbad410f30d3ab0c880135a77b26d5a67d9ffbfb0e5914bd03d
|
data/doc/commands_extension.md
CHANGED
@@ -10,6 +10,11 @@ Each command can be easily extended with one ore more `HammerCLI::CommandExtensi
|
|
10
10
|
inheritable true
|
11
11
|
# Simply add a new option to a command is being extended
|
12
12
|
option(option_params)
|
13
|
+
# Add option family to a command
|
14
|
+
option_family(common_options = {}) do
|
15
|
+
parent option_params
|
16
|
+
child option_params
|
17
|
+
end
|
13
18
|
# Extend hash with data returned from server before it is printed
|
14
19
|
before_print do |data|
|
15
20
|
# data modifications
|
@@ -65,6 +70,13 @@ class MyCommandExtensions < HammerCLI::CommandExtensions
|
|
65
70
|
|
66
71
|
option ['--new-option'], 'TYPE', _('Option description')
|
67
72
|
|
73
|
+
option_family(
|
74
|
+
description: _('Common description')
|
75
|
+
) do
|
76
|
+
parent ['--new-option'], 'TYPE', _('Option description')
|
77
|
+
child ['--new-option-ver2'], 'TYPE', _('Option description')
|
78
|
+
end
|
79
|
+
|
68
80
|
before_print do |data|
|
69
81
|
data['results'].each do |result|
|
70
82
|
result['status'] = process_errors(result['errors'])
|
data/doc/creating_commands.md
CHANGED
@@ -173,6 +173,54 @@ Here is the list of predefined options:
|
|
173
173
|
* `:fields` Expects a list with fields to show in output, see [example](creating_commands.md#printing-hash-records).
|
174
174
|
|
175
175
|
|
176
|
+
### Option family
|
177
|
+
Option family is the way to unify options which have the same meaning or purpose,
|
178
|
+
but contain some differences in their definitions (e.g. the name/switch of an option).
|
179
|
+
Mainly serves as a container for options, which purpose is to show less repetitive
|
180
|
+
output in commands' help. Option builders use it by default.
|
181
|
+
|
182
|
+
To define an option family, use the following DSL:
|
183
|
+
```ruby
|
184
|
+
# options is a Hash with options for family/each defined option within it
|
185
|
+
option_family(options = {}) do
|
186
|
+
# parent is the main option. Must be single, option family can have only one parent.
|
187
|
+
parent switches, type, description, options
|
188
|
+
# child is an additional option. Could be none or more than one. Aren't shown in the help output.
|
189
|
+
child switches, type, description, options
|
190
|
+
end
|
191
|
+
```
|
192
|
+
|
193
|
+
##### Example
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
option_family(
|
197
|
+
aliased_resource: 'environment',
|
198
|
+
description: _('Puppet environment'),
|
199
|
+
deprecation: _("Use %s instead") % '--puppet-environment[-id]'
|
200
|
+
deprecated: { '--environment' => _("Use %s instead") % '--puppet-environment[-id]',
|
201
|
+
'--environment-id' => _("Use %s instead") % '--puppet-environment[-id]'}
|
202
|
+
) do
|
203
|
+
parent '--environment-id', 'ENVIRONMENT_ID', _(''),
|
204
|
+
format: HammerCLI::Options::Normalizers::Number.new,
|
205
|
+
attribute_name: :option_environment_id
|
206
|
+
child '--environment', 'ENVIRONMENT_NAME', _('Environment name'),
|
207
|
+
attribute_name: :option_environment_name
|
208
|
+
end
|
209
|
+
|
210
|
+
# $ hammer command --help:
|
211
|
+
# ...
|
212
|
+
# Options:
|
213
|
+
# --environment[-id] Puppet environment (Deprecated: Use --puppet-environment[-id] instead)
|
214
|
+
# ...
|
215
|
+
|
216
|
+
# $ hammer full-help:
|
217
|
+
# ...
|
218
|
+
# Options:
|
219
|
+
# --environment ENVIRONMENT_NAME Environment name (--environment is deprecated: Use --puppet-environment[-id] instead)
|
220
|
+
# --environment-id ENVIRONMENT_ID (--environment-id is deprecated: Use --puppet-environment[-id] instead)
|
221
|
+
# ...
|
222
|
+
```
|
223
|
+
|
176
224
|
### Option builders
|
177
225
|
Hammer commands offer option builders that can be used for automatic option generation.
|
178
226
|
See [documentation page](option_builders.md#option-builders) dedicated to this topic for more details.
|
@@ -406,6 +454,31 @@ Options:
|
|
406
454
|
-h, --help print help
|
407
455
|
```
|
408
456
|
|
457
|
+
#### Aliasing subcommands
|
458
|
+
|
459
|
+
Commands can have two or more names, e.g. aliases. To support such functionality
|
460
|
+
simple name addition could be used via `command_name` or `command_names` method:
|
461
|
+
```ruby
|
462
|
+
module HammerCLIHello
|
463
|
+
|
464
|
+
class SayCommand < HammerCLI::AbstractCommand
|
465
|
+
|
466
|
+
class GreetingsCommand < HammerCLI::AbstractCommand
|
467
|
+
command_name 'hello'
|
468
|
+
command_name 'hi'
|
469
|
+
# or use can use other method:
|
470
|
+
command_names 'hello', 'hi'
|
471
|
+
|
472
|
+
desc 'Say Hello World!'
|
473
|
+
# ...
|
474
|
+
end
|
475
|
+
|
476
|
+
autoload_subcommands
|
477
|
+
end
|
478
|
+
|
479
|
+
HammerCLI::MainCommand.subcommand 'say', "Say something", HammerCLIHello::SayCommand
|
480
|
+
end
|
481
|
+
```
|
409
482
|
|
410
483
|
### Conflicting subcommands
|
411
484
|
It can happen that two different plugins define subcommands with the same name by accident.
|
data/doc/release_notes.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
Release notes
|
2
2
|
=============
|
3
|
+
### 2.1.0 (2020-05-14)
|
4
|
+
* Hammer full-help returns correct output, [#29697](http://projects.theforeman.org/issues/29697)
|
5
|
+
* Add fuzzy subcommand matching, [#29413](http://projects.theforeman.org/issues/29413)
|
6
|
+
* Help contains squeezed options, [#28440](http://projects.theforeman.org/issues/28440)
|
7
|
+
* Keep referenced resource in option options, [#29015](http://projects.theforeman.org/issues/29015)
|
8
|
+
* Bump to 2.1.0-develop
|
9
|
+
|
3
10
|
### 2.0.0 (2020-02-12)
|
4
11
|
* Bump version to 2.0.0
|
5
12
|
* Bump version to 2.0 ([PR #324](https://github.com/theforeman/hammer-cli/pull/324))
|
data/lib/hammer_cli/abstract.rb
CHANGED
@@ -13,6 +13,7 @@ require 'hammer_cli/options/predefined'
|
|
13
13
|
require 'hammer_cli/help/builder'
|
14
14
|
require 'hammer_cli/help/text_builder'
|
15
15
|
require 'hammer_cli/command_extensions'
|
16
|
+
require 'hammer_cli/options/option_family'
|
16
17
|
require 'logging'
|
17
18
|
|
18
19
|
module HammerCLI
|
@@ -191,6 +192,16 @@ module HammerCLI
|
|
191
192
|
# skip switches that are already defined
|
192
193
|
next if option.nil? or option.switches.any? {|s| find_option(s) }
|
193
194
|
|
195
|
+
if option.respond_to?(:referenced_resource)
|
196
|
+
# Collect options that don't have family, but related to this parent.
|
197
|
+
children = find_options(
|
198
|
+
referenced_resource: option.referenced_resource.to_s,
|
199
|
+
aliased_resource: option.aliased_resource.to_s
|
200
|
+
).select { |o| o.family.nil? || o.family.head.nil? }
|
201
|
+
children.each do |child|
|
202
|
+
option.family.adopt(child) if option.family
|
203
|
+
end
|
204
|
+
end
|
194
205
|
declared_options << option
|
195
206
|
block ||= option.default_conversion_block
|
196
207
|
define_accessors_for(option, &block)
|
@@ -207,6 +218,7 @@ module HammerCLI
|
|
207
218
|
extension.delegatee(self)
|
208
219
|
extension.extend_predefined_options(self)
|
209
220
|
extension.extend_options(self)
|
221
|
+
extension.extend_option_family(self)
|
210
222
|
extension.extend_output(self)
|
211
223
|
extension.extend_help(self)
|
212
224
|
logger('Extensions').info "Applied #{extension.details} on #{self}."
|
@@ -222,6 +234,12 @@ module HammerCLI
|
|
222
234
|
|
223
235
|
protected
|
224
236
|
|
237
|
+
def self.option_family(options = {}, &block)
|
238
|
+
options[:creator] ||= self
|
239
|
+
family = HammerCLI::Options::OptionFamily.new(options)
|
240
|
+
family.instance_eval(&block)
|
241
|
+
end
|
242
|
+
|
225
243
|
def self.find_options(switch_filter, other_filters={})
|
226
244
|
filters = other_filters
|
227
245
|
if switch_filter.is_a? Hash
|
@@ -285,8 +303,17 @@ module HammerCLI
|
|
285
303
|
end
|
286
304
|
|
287
305
|
def self.command_name(name=nil)
|
288
|
-
@
|
289
|
-
|
306
|
+
if @names && name
|
307
|
+
@names << name if !@names.include?(name)
|
308
|
+
else
|
309
|
+
@names = [name] if name
|
310
|
+
end
|
311
|
+
@names || (superclass.respond_to?(:command_names) ? superclass.command_names : nil)
|
312
|
+
end
|
313
|
+
|
314
|
+
def self.command_names(*names)
|
315
|
+
@names = names unless names.empty?
|
316
|
+
@names || (superclass.respond_to?(:command_names) ? superclass.command_names : nil)
|
290
317
|
end
|
291
318
|
|
292
319
|
def self.warning(message = nil)
|
@@ -41,12 +41,11 @@ module HammerCLI::Apipie
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def create_option(param, resource_name_map)
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
)
|
44
|
+
family = HammerCLI::Options::OptionFamily.new
|
45
|
+
family.parent(option_switch(param, resource_name_map),
|
46
|
+
option_type(param, resource_name_map),
|
47
|
+
option_desc(param),
|
48
|
+
option_opts(param, resource_name_map))
|
50
49
|
end
|
51
50
|
|
52
51
|
def option_switch(param, resource_name_map)
|
@@ -61,7 +60,7 @@ module HammerCLI::Apipie
|
|
61
60
|
param.description || " "
|
62
61
|
end
|
63
62
|
|
64
|
-
def option_opts(param)
|
63
|
+
def option_opts(param, resource_name_map)
|
65
64
|
opts = {}
|
66
65
|
opts[:required] = true if (param.required? and require_options?)
|
67
66
|
if param.expected_type.to_s == 'array'
|
@@ -80,19 +79,22 @@ module HammerCLI::Apipie
|
|
80
79
|
end
|
81
80
|
opts[:attribute_name] = HammerCLI.option_accessor_name(param.name)
|
82
81
|
opts[:referenced_resource] = resource_name(param)
|
82
|
+
opts[:aliased_resource] = aliased_name(resource_name(param), resource_name_map)
|
83
83
|
|
84
84
|
return opts
|
85
85
|
end
|
86
86
|
|
87
|
+
def aliased_name(name, resource_name_map)
|
88
|
+
return if name.nil?
|
89
|
+
|
90
|
+
resource_name_map[name.to_s] || resource_name_map[name.to_sym] || name
|
91
|
+
end
|
92
|
+
|
87
93
|
def aliased(param, resource_name_map)
|
88
94
|
resource_name = resource_name(param)
|
95
|
+
return param.name if resource_name.nil?
|
89
96
|
|
90
|
-
|
91
|
-
return param.name
|
92
|
-
else
|
93
|
-
aliased_name = resource_name_map[resource_name.to_s] || resource_name_map[resource_name.to_sym] || resource_name
|
94
|
-
return param.name.gsub(resource_name, aliased_name.to_s)
|
95
|
-
end
|
97
|
+
param.name.gsub(resource_name, aliased_name(resource_name, resource_name_map).to_s)
|
96
98
|
end
|
97
99
|
|
98
100
|
def resource_name(param)
|
@@ -1,21 +1,23 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'options')
|
2
2
|
|
3
3
|
module HammerCLI::Apipie
|
4
|
-
|
5
4
|
class OptionDefinition < HammerCLI::Options::OptionDefinition
|
6
|
-
|
7
|
-
attr_accessor :referenced_resource
|
5
|
+
attr_accessor :referenced_resource, :aliased_resource, :family
|
8
6
|
|
9
7
|
def initialize(switches, type, description, options = {})
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
@referenced_resource = options[:referenced_resource].to_s if options[:referenced_resource]
|
9
|
+
@aliased_resource = options[:aliased_resource].to_s if options[:aliased_resource]
|
10
|
+
@family = options[:family]
|
13
11
|
super
|
14
12
|
# Apipie currently sends descriptions as escaped HTML once this is changed this should be removed.
|
15
13
|
# See #15198 on Redmine.
|
16
14
|
@description = CGI::unescapeHTML(description)
|
17
15
|
end
|
18
16
|
|
19
|
-
|
17
|
+
def child?
|
18
|
+
return unless @family
|
20
19
|
|
20
|
+
@family.children.include?(self)
|
21
|
+
end
|
22
|
+
end
|
21
23
|
end
|
@@ -15,7 +15,7 @@ module HammerCLI
|
|
15
15
|
ALLOWED_EXTENSIONS = %i[
|
16
16
|
option command_options before_print data output help request
|
17
17
|
request_headers headers request_options options request_params params
|
18
|
-
option_sources predefined_options use_option
|
18
|
+
option_sources predefined_options use_option option_family
|
19
19
|
].freeze
|
20
20
|
|
21
21
|
def initialize(options = {})
|
@@ -86,6 +86,11 @@ module HammerCLI
|
|
86
86
|
@option_sources_block = block
|
87
87
|
end
|
88
88
|
|
89
|
+
def self.option_family(options = {}, &block)
|
90
|
+
@option_family_opts = options
|
91
|
+
@option_family_block = block
|
92
|
+
end
|
93
|
+
|
89
94
|
# Object
|
90
95
|
|
91
96
|
def extend_options(command_class)
|
@@ -151,6 +156,13 @@ module HammerCLI
|
|
151
156
|
self.class.extend_option_sources(sources, command)
|
152
157
|
end
|
153
158
|
|
159
|
+
def extend_option_family(command_class)
|
160
|
+
allowed = @only & %i[option_family]
|
161
|
+
return if allowed.empty? || (allowed & @except).any?
|
162
|
+
|
163
|
+
self.class.extend_option_family(command_class)
|
164
|
+
end
|
165
|
+
|
154
166
|
def delegatee(command_class)
|
155
167
|
self.class.delegatee = command_class
|
156
168
|
end
|
@@ -234,5 +246,13 @@ module HammerCLI
|
|
234
246
|
@option_sources_block.call(sources, command)
|
235
247
|
logger.debug("Called block for #{@delegatee} option sources:\n\t#{@option_sources_block}")
|
236
248
|
end
|
249
|
+
|
250
|
+
def self.extend_option_family(command_class)
|
251
|
+
return if @option_family_block.nil?
|
252
|
+
|
253
|
+
@option_family_opts[:creator] = command_class
|
254
|
+
command_class.send(:option_family, @option_family_opts, &@option_family_block)
|
255
|
+
logger.debug("Called option family block for #{command_class}:\n\t#{@option_family_block}")
|
256
|
+
end
|
237
257
|
end
|
238
258
|
end
|
@@ -69,7 +69,7 @@ module HammerCLI
|
|
69
69
|
|
70
70
|
def handle_usage_exception(e)
|
71
71
|
print_error (_("Error: %{message}") + "\n\n" +
|
72
|
-
_("See: '%{path} --help'.")) % {:
|
72
|
+
_("See: '%{path} --help'.")) % { message: e.message, path: HammerCLI.expand_invocation_path(e.command.invocation_path) }
|
73
73
|
log_full_error e
|
74
74
|
HammerCLI::EX_USAGE
|
75
75
|
end
|
data/lib/hammer_cli/full_help.rb
CHANGED
@@ -6,8 +6,11 @@ module HammerCLI
|
|
6
6
|
|
7
7
|
def execute
|
8
8
|
@adapter = option_md? ? MDAdapter.new : TxtAdapter.new
|
9
|
+
HammerCLI.context[:full_help] = true
|
10
|
+
@invocation_paths = {}
|
9
11
|
print_heading
|
10
12
|
print_help
|
13
|
+
HammerCLI.context[:full_help] = false
|
11
14
|
HammerCLI::EX_OK
|
12
15
|
end
|
13
16
|
|
@@ -19,9 +22,13 @@ module HammerCLI
|
|
19
22
|
end
|
20
23
|
|
21
24
|
def print_help(name='hammer', command=HammerCLI::MainCommand, desc='')
|
22
|
-
@
|
25
|
+
@invocation_paths[name] ||= []
|
26
|
+
@adapter.print_command(name, desc, command.new(name, path: @invocation_paths[name]).help)
|
23
27
|
|
24
28
|
command.recognised_subcommands.each do |sub_cmd|
|
29
|
+
path = "#{name} #{sub_cmd.names.first}"
|
30
|
+
@invocation_paths[path] ||= []
|
31
|
+
@invocation_paths[path] += @invocation_paths[name]
|
25
32
|
print_help(@adapter.command_name(name, sub_cmd.names.first), sub_cmd.subcommand_class, sub_cmd.description)
|
26
33
|
end
|
27
34
|
end
|
@@ -14,7 +14,7 @@ module HammerCLI
|
|
14
14
|
def add_usage(invocation_path, usage_descriptions)
|
15
15
|
heading(Clamp.message(:usage_heading))
|
16
16
|
usage_descriptions.each do |usage|
|
17
|
-
puts " #{invocation_path} #{usage}".rstrip
|
17
|
+
puts " #{HammerCLI.expand_invocation_path(invocation_path)} #{usage}".rstrip
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
@@ -29,12 +29,19 @@ module HammerCLI
|
|
29
29
|
|
30
30
|
label_width = DEFAULT_LABEL_INDENT
|
31
31
|
items.each do |item|
|
32
|
-
label
|
32
|
+
label = item.help.first
|
33
33
|
label_width = label.size if label.size > label_width
|
34
34
|
end
|
35
35
|
|
36
36
|
items.each do |item|
|
37
|
-
|
37
|
+
if item.respond_to?(:child?) && item.child?
|
38
|
+
next unless HammerCLI.context[:full_help]
|
39
|
+
end
|
40
|
+
label, description = if !HammerCLI.context[:full_help] && item.respond_to?(:family) && item.family
|
41
|
+
[item.family.switch, item.family.description || item.help[1]]
|
42
|
+
else
|
43
|
+
item.help
|
44
|
+
end
|
38
45
|
description.gsub(/^(.)/) { Unicode::capitalize($1) }.each_line do |line|
|
39
46
|
puts " %-#{label_width}s %s" % [label, line]
|
40
47
|
label = ''
|
@@ -54,6 +61,25 @@ module HammerCLI
|
|
54
61
|
label = HighLine.color(label, :bold) if @richtext
|
55
62
|
puts label
|
56
63
|
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def expand_invocation_path(path)
|
68
|
+
bits = path.split(' ')
|
69
|
+
parent_command = HammerCLI::MainCommand
|
70
|
+
new_path = (bits[1..-1] || []).each_with_object([]) do |bit, names|
|
71
|
+
subcommand = parent_command.find_subcommand(bit)
|
72
|
+
next if subcommand.nil?
|
73
|
+
|
74
|
+
names << if subcommand.names.size > 1
|
75
|
+
"<#{subcommand.names.join('|')}>"
|
76
|
+
else
|
77
|
+
subcommand.names.first
|
78
|
+
end
|
79
|
+
parent_command = subcommand.subcommand_class
|
80
|
+
end
|
81
|
+
new_path.unshift(bits.first).join(' ')
|
82
|
+
end
|
57
83
|
end
|
58
84
|
end
|
59
85
|
end
|
@@ -22,14 +22,12 @@ module HammerCLI
|
|
22
22
|
|
23
23
|
class OptionDefinition < Clamp::Option::Definition
|
24
24
|
|
25
|
-
attr_accessor :value_formatter
|
26
|
-
attr_accessor :context_target
|
27
|
-
attr_accessor :deprecated_switches
|
25
|
+
attr_accessor :value_formatter, :context_target, :deprecated_switches
|
28
26
|
|
29
27
|
def initialize(switches, type, description, options = {})
|
30
|
-
|
31
|
-
|
32
|
-
|
28
|
+
@value_formatter = options[:format] || HammerCLI::Options::Normalizers::Default.new
|
29
|
+
@context_target = options[:context_target]
|
30
|
+
@deprecated_switches = options[:deprecated]
|
33
31
|
super
|
34
32
|
end
|
35
33
|
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HammerCLI
|
4
|
+
module Options
|
5
|
+
class OptionFamily
|
6
|
+
attr_reader :children
|
7
|
+
|
8
|
+
IDS_REGEX = /\s?([Ii][Dd][s]?)\W|([Ii][Dd][s]?\Z)/
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@all = []
|
12
|
+
@children = []
|
13
|
+
@options = options
|
14
|
+
@creator = options[:creator] || Class.new(HammerCLI::Apipie::Command)
|
15
|
+
@prefix = options[:prefix]
|
16
|
+
@description = options[:description]
|
17
|
+
@root = options[:root] || options[:aliased_resource] || options[:referenced_resource]
|
18
|
+
end
|
19
|
+
|
20
|
+
def description
|
21
|
+
types = all.map(&:type).map { |s| s.split('_').last.to_s }
|
22
|
+
.map(&:capitalize).join('/')
|
23
|
+
@description ||= @parent.help[1].gsub(IDS_REGEX) { |w| w.gsub(/\w+/, types) }
|
24
|
+
if @options[:deprecation].class <= String
|
25
|
+
format_deprecation_msg(@description, _('Deprecated: %{deprecated_msg}') % { deprecated_msg: @options[:deprecation] })
|
26
|
+
elsif @options[:deprecation].class <= Hash
|
27
|
+
full_msg = @options[:deprecation].map do |flag, msg|
|
28
|
+
_('%{flag} is deprecated: %{deprecated_msg}') % { flag: flag, deprecated_msg: msg }
|
29
|
+
end.join(', ')
|
30
|
+
format_deprecation_msg(@description, full_msg)
|
31
|
+
else
|
32
|
+
@description
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def switch
|
37
|
+
return if @parent.nil? && @children.empty?
|
38
|
+
return @parent.help_lhs.strip if @children.empty?
|
39
|
+
|
40
|
+
switch_start = main_switch.each_char
|
41
|
+
.zip(*all.map(&:switches).flatten.map(&:each_char))
|
42
|
+
.select { |a, b| a == b }.transpose.first.join
|
43
|
+
suffixes = all.map do |m|
|
44
|
+
m.switches.map { |s| s.gsub(switch_start, '') }
|
45
|
+
end.flatten.reject(&:empty?).sort { |x, y| x.size <=> y.size }
|
46
|
+
"#{switch_start}[#{suffixes.join('|')}]"
|
47
|
+
end
|
48
|
+
|
49
|
+
def head
|
50
|
+
@parent
|
51
|
+
end
|
52
|
+
|
53
|
+
def all
|
54
|
+
@children + [@parent].compact
|
55
|
+
end
|
56
|
+
|
57
|
+
def parent(switches, type, description, opts = {}, &block)
|
58
|
+
raise StandardError, 'Option family can have only one parent' if @parent
|
59
|
+
|
60
|
+
@parent = new_member(switches, type, description, opts, &block)
|
61
|
+
end
|
62
|
+
|
63
|
+
def child(switches, type, description, opts = {}, &block)
|
64
|
+
child = new_member(switches, type, description, opts, &block)
|
65
|
+
@children << child
|
66
|
+
child
|
67
|
+
end
|
68
|
+
|
69
|
+
def adopt(child)
|
70
|
+
child.family = self
|
71
|
+
@children << child
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def format_deprecation_msg(option_desc, deprecation_msg)
|
77
|
+
"#{option_desc} (#{deprecation_msg})"
|
78
|
+
end
|
79
|
+
|
80
|
+
def new_member(switches, type, description, opts = {}, &block)
|
81
|
+
opts = opts.merge(@options)
|
82
|
+
opts[:family] = self
|
83
|
+
if opts[:deprecated]
|
84
|
+
handles = [switches].flatten
|
85
|
+
opts[:deprecated] = opts[:deprecated].select do |switch, _msg|
|
86
|
+
handles.include?(switch)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
@creator.instance_eval do
|
90
|
+
option(switches, type, description, opts, &block)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def main_switch
|
95
|
+
root = @root || @parent.aliased_resource || @parent.referenced_resource || common_root
|
96
|
+
"--#{@prefix}#{root}".tr('_', '-')
|
97
|
+
end
|
98
|
+
|
99
|
+
def common_root
|
100
|
+
switches = all.map(&:switches).flatten
|
101
|
+
shortest = switches.min_by(&:length)
|
102
|
+
max_len = shortest.length
|
103
|
+
max_len.downto(0) do |curr_len|
|
104
|
+
0.upto(max_len - curr_len) do |start|
|
105
|
+
root = shortest[start, curr_len]
|
106
|
+
if switches.all? { |switch| switch.include?(root) }
|
107
|
+
return root[2..-1].chomp('-')
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -23,6 +23,11 @@ module HammerCLI
|
|
23
23
|
@subcommand_class
|
24
24
|
end
|
25
25
|
|
26
|
+
def help
|
27
|
+
names = HammerCLI.context[:full_help] ? @names.join(", ") : @names.first
|
28
|
+
[names, description]
|
29
|
+
end
|
30
|
+
|
26
31
|
attr_reader :warning
|
27
32
|
end
|
28
33
|
|
@@ -90,8 +95,27 @@ module HammerCLI
|
|
90
95
|
logger.info "subcommand #{name} (#{subcommand_class_name}) was created."
|
91
96
|
end
|
92
97
|
|
98
|
+
def find_subcommand(name, fuzzy: true)
|
99
|
+
subcommand = super(name)
|
100
|
+
if subcommand.nil? && fuzzy
|
101
|
+
find_subcommand_starting_with(name)
|
102
|
+
else
|
103
|
+
subcommand
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def find_subcommand_starting_with(name)
|
108
|
+
subcommands = recognised_subcommands.select { |sc| sc.names.any? { |n| n.start_with?(name) } }
|
109
|
+
if subcommands.size > 1
|
110
|
+
raise HammerCLI::CommandConflict, _('Found more than one command.') + "\n\n" +
|
111
|
+
_('Did you mean one of these?') + "\n\t" +
|
112
|
+
subcommands.collect(&:names).flatten.select { |n| n.start_with?(name) }.join("\n\t")
|
113
|
+
end
|
114
|
+
subcommands.first
|
115
|
+
end
|
116
|
+
|
93
117
|
def define_subcommand(name, subcommand_class, definition, &block)
|
94
|
-
existing = find_subcommand(name)
|
118
|
+
existing = find_subcommand(name, fuzzy: false)
|
95
119
|
if existing
|
96
120
|
raise HammerCLI::CommandConflict, _("Can't replace subcommand %<name>s (%<existing_class>s) with %<name>s (%<new_class>s).") % {
|
97
121
|
:name => name,
|
@@ -71,13 +71,13 @@ module HammerCLI
|
|
71
71
|
if heading.nil?
|
72
72
|
["Error: #{message}",
|
73
73
|
"",
|
74
|
-
"See: '#{command} --help'.",
|
74
|
+
"See: '#{HammerCLI.expand_invocation_path(command)} --help'.",
|
75
75
|
""].join("\n")
|
76
76
|
else
|
77
77
|
["#{heading}:",
|
78
78
|
" Error: #{message}",
|
79
79
|
" ",
|
80
|
-
" See: '#{command} --help'.",
|
80
|
+
" See: '#{HammerCLI.expand_invocation_path(command)} --help'.",
|
81
81
|
""].join("\n")
|
82
82
|
end
|
83
83
|
end
|
data/lib/hammer_cli/utils.rb
CHANGED
@@ -116,4 +116,21 @@ module HammerCLI
|
|
116
116
|
|
117
117
|
array.insert(idx, *new_items)
|
118
118
|
end
|
119
|
+
|
120
|
+
def self.expand_invocation_path(path)
|
121
|
+
bits = path.split(' ')
|
122
|
+
parent_command = HammerCLI::MainCommand
|
123
|
+
new_path = (bits[1..-1] || []).each_with_object([]) do |bit, names|
|
124
|
+
subcommand = parent_command.find_subcommand(bit)
|
125
|
+
next if subcommand.nil?
|
126
|
+
|
127
|
+
names << if subcommand.names.size > 1
|
128
|
+
"<#{subcommand.names.join('|')}>"
|
129
|
+
else
|
130
|
+
subcommand.names.first
|
131
|
+
end
|
132
|
+
parent_command = subcommand.subcommand_class
|
133
|
+
end
|
134
|
+
new_path.unshift(bits.first).join(' ')
|
135
|
+
end
|
119
136
|
end
|
data/lib/hammer_cli/version.rb
CHANGED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/test/unit/abstract_test.rb
CHANGED
@@ -262,6 +262,27 @@ describe HammerCLI::AbstractCommand do
|
|
262
262
|
end
|
263
263
|
|
264
264
|
end
|
265
|
+
|
266
|
+
describe 'find_subcommand' do
|
267
|
+
it 'should find by full name' do
|
268
|
+
main_cmd.find_subcommand('some_command').wont_be_nil
|
269
|
+
end
|
270
|
+
|
271
|
+
it 'should find by partial name' do
|
272
|
+
main_cmd.find_subcommand('some_').wont_be_nil
|
273
|
+
end
|
274
|
+
|
275
|
+
it 'should not find by wrong name' do
|
276
|
+
main_cmd.find_subcommand('not_existing').must_be_nil
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'should raise if more than one were found' do
|
280
|
+
main_cmd.subcommand('pong', 'description', Subcommand2)
|
281
|
+
proc do
|
282
|
+
main_cmd.find_subcommand('p')
|
283
|
+
end.must_raise HammerCLI::CommandConflict
|
284
|
+
end
|
285
|
+
end
|
265
286
|
end
|
266
287
|
|
267
288
|
describe "options" do
|
@@ -413,7 +434,7 @@ describe HammerCLI::AbstractCommand do
|
|
413
434
|
class CmdName2 < CmdName1
|
414
435
|
end
|
415
436
|
|
416
|
-
CmdName2.command_name.must_equal 'cmd'
|
437
|
+
CmdName2.command_name.must_equal ['cmd']
|
417
438
|
end
|
418
439
|
|
419
440
|
it "should inherit output definition" do
|
@@ -525,7 +546,7 @@ describe HammerCLI::AbstractCommand do
|
|
525
546
|
opt = cmd.find_option('--flag')
|
526
547
|
opt.is_a?(HammerCLI::Options::OptionDefinition).must_equal true
|
527
548
|
cmd.output_definition.empty?.must_equal false
|
528
|
-
cmd.new({}).help.must_match(/.*text.*/)
|
549
|
+
cmd.new('', {}).help.must_match(/.*text.*/)
|
529
550
|
end
|
530
551
|
|
531
552
|
it 'should store more than one extension' do
|
@@ -37,6 +37,14 @@ describe HammerCLI::Apipie::OptionBuilder do
|
|
37
37
|
it "should set description with html tags stripped" do
|
38
38
|
options[0].description.must_equal 'filter results'
|
39
39
|
end
|
40
|
+
|
41
|
+
it "should build option with default family" do
|
42
|
+
options[0].family.wont_be_nil
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should build parent option within default family" do
|
46
|
+
options[0].child?.must_equal false
|
47
|
+
end
|
40
48
|
end
|
41
49
|
|
42
50
|
|
@@ -23,6 +23,12 @@ describe HammerCLI::CommandExtensions do
|
|
23
23
|
|
24
24
|
class CmdExtensions < HammerCLI::CommandExtensions
|
25
25
|
option '--ext', 'EXT', 'ext'
|
26
|
+
option_family(
|
27
|
+
description: 'Test',
|
28
|
+
) do
|
29
|
+
parent '--test-one', '', ''
|
30
|
+
child '--test-two', '', ''
|
31
|
+
end
|
26
32
|
before_print do |data|
|
27
33
|
data['key'] = 'value'
|
28
34
|
end
|
@@ -64,49 +70,55 @@ describe HammerCLI::CommandExtensions do
|
|
64
70
|
|
65
71
|
it 'should extend help only' do
|
66
72
|
cmd.extend_with(CmdExtensions.new(only: :help))
|
67
|
-
cmd.new({}).help.must_match(/.*Section.*/)
|
68
|
-
cmd.new({}).help.must_match(/.*text.*/)
|
73
|
+
cmd.new('', {}).help.must_match(/.*Section.*/)
|
74
|
+
cmd.new('', {}).help.must_match(/.*text.*/)
|
69
75
|
end
|
70
76
|
|
71
77
|
it 'should extend params only' do
|
72
78
|
cmd.extend_with(CmdExtensions.new(only: :request_params))
|
73
|
-
cmd.new({}).extended_request[0].must_equal(thin: true)
|
74
|
-
cmd.new({}).extended_request[1].must_equal({})
|
75
|
-
cmd.new({}).extended_request[2].must_equal({})
|
79
|
+
cmd.new('', {}).extended_request[0].must_equal(thin: true)
|
80
|
+
cmd.new('', {}).extended_request[1].must_equal({})
|
81
|
+
cmd.new('', {}).extended_request[2].must_equal({})
|
76
82
|
end
|
77
83
|
|
78
84
|
it 'should extend headers only' do
|
79
85
|
cmd.extend_with(CmdExtensions.new(only: :request_headers))
|
80
|
-
cmd.new({}).extended_request[0].must_equal({})
|
81
|
-
cmd.new({}).extended_request[1].must_equal(ssl: true)
|
82
|
-
cmd.new({}).extended_request[2].must_equal({})
|
86
|
+
cmd.new('', {}).extended_request[0].must_equal({})
|
87
|
+
cmd.new('', {}).extended_request[1].must_equal(ssl: true)
|
88
|
+
cmd.new('', {}).extended_request[2].must_equal({})
|
83
89
|
end
|
84
90
|
|
85
91
|
it 'should extend options only' do
|
86
92
|
cmd.extend_with(CmdExtensions.new(only: :request_options))
|
87
|
-
cmd.new({}).extended_request[0].must_equal({})
|
88
|
-
cmd.new({}).extended_request[1].must_equal({})
|
89
|
-
cmd.new({}).extended_request[2].must_equal(with_authentication: true)
|
93
|
+
cmd.new('', {}).extended_request[0].must_equal({})
|
94
|
+
cmd.new('', {}).extended_request[1].must_equal({})
|
95
|
+
cmd.new('', {}).extended_request[2].must_equal(with_authentication: true)
|
90
96
|
end
|
91
97
|
|
92
98
|
it 'should extend params and options and headers' do
|
93
99
|
cmd.extend_with(CmdExtensions.new(only: :request))
|
94
|
-
cmd.new({}).extended_request[0].must_equal(thin: true)
|
95
|
-
cmd.new({}).extended_request[1].must_equal(ssl: true)
|
96
|
-
cmd.new({}).extended_request[2].must_equal(with_authentication: true)
|
100
|
+
cmd.new('', {}).extended_request[0].must_equal(thin: true)
|
101
|
+
cmd.new('', {}).extended_request[1].must_equal(ssl: true)
|
102
|
+
cmd.new('', {}).extended_request[2].must_equal(with_authentication: true)
|
97
103
|
end
|
98
104
|
|
99
105
|
it 'should extend data only' do
|
100
106
|
cmd.extend_with(CmdExtensions.new(only: :data))
|
101
|
-
cmd.new({}).help.wont_match(/.*Section.*/)
|
102
|
-
cmd.new({}).help.wont_match(/.*text.*/)
|
107
|
+
cmd.new('', {}).help.wont_match(/.*Section.*/)
|
108
|
+
cmd.new('', {}).help.wont_match(/.*text.*/)
|
103
109
|
cmd.output_definition.empty?.must_equal true
|
104
110
|
opt = cmd.find_option('--ext')
|
105
111
|
opt.is_a?(HammerCLI::Options::OptionDefinition).must_equal false
|
106
|
-
cmd.new({}).extended_request[0].must_equal({})
|
107
|
-
cmd.new({}).extended_request[1].must_equal({})
|
108
|
-
cmd.new({}).extended_request[2].must_equal({})
|
109
|
-
cmd.new({}).extended_data({}).must_equal('key' => 'value')
|
112
|
+
cmd.new('', {}).extended_request[0].must_equal({})
|
113
|
+
cmd.new('', {}).extended_request[1].must_equal({})
|
114
|
+
cmd.new('', {}).extended_request[2].must_equal({})
|
115
|
+
cmd.new('', {}).extended_data({}).must_equal('key' => 'value')
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should extend option family only' do
|
119
|
+
cmd.extend_with(CmdExtensions.new(only: :option_family))
|
120
|
+
cmd.output_definition.empty?.must_equal true
|
121
|
+
cmd.recognised_options.map(&:switches).flatten.must_equal ['--test-one', '--test-two', '-h', '--help']
|
110
122
|
end
|
111
123
|
end
|
112
124
|
|
@@ -116,9 +128,9 @@ describe HammerCLI::CommandExtensions do
|
|
116
128
|
opt = cmd.find_option('--ext')
|
117
129
|
opt.is_a?(HammerCLI::Options::OptionDefinition).must_equal false
|
118
130
|
cmd.output_definition.empty?.must_equal false
|
119
|
-
cmd.new({}).extended_request[0].must_equal(thin: true)
|
120
|
-
cmd.new({}).extended_request[1].must_equal(ssl: true)
|
121
|
-
cmd.new({}).extended_request[2].must_equal(with_authentication: true)
|
131
|
+
cmd.new('', {}).extended_request[0].must_equal(thin: true)
|
132
|
+
cmd.new('', {}).extended_request[1].must_equal(ssl: true)
|
133
|
+
cmd.new('', {}).extended_request[2].must_equal(with_authentication: true)
|
122
134
|
end
|
123
135
|
|
124
136
|
it 'should extend all except output' do
|
@@ -126,62 +138,68 @@ describe HammerCLI::CommandExtensions do
|
|
126
138
|
cmd.output_definition.empty?.must_equal true
|
127
139
|
opt = cmd.find_option('--ext')
|
128
140
|
opt.is_a?(HammerCLI::Options::OptionDefinition).must_equal true
|
129
|
-
cmd.new({}).extended_request[0].must_equal(thin: true)
|
130
|
-
cmd.new({}).extended_request[1].must_equal(ssl: true)
|
131
|
-
cmd.new({}).extended_request[2].must_equal(with_authentication: true)
|
141
|
+
cmd.new('', {}).extended_request[0].must_equal(thin: true)
|
142
|
+
cmd.new('', {}).extended_request[1].must_equal(ssl: true)
|
143
|
+
cmd.new('', {}).extended_request[2].must_equal(with_authentication: true)
|
132
144
|
end
|
133
145
|
|
134
146
|
it 'should extend all except help' do
|
135
147
|
cmd.extend_with(CmdExtensions.new(except: :help))
|
136
|
-
cmd.new({}).help.wont_match(/.*Section.*/)
|
137
|
-
cmd.new({}).help.wont_match(/.*text.*/)
|
148
|
+
cmd.new('', {}).help.wont_match(/.*Section.*/)
|
149
|
+
cmd.new('', {}).help.wont_match(/.*text.*/)
|
138
150
|
cmd.output_definition.empty?.must_equal false
|
139
151
|
opt = cmd.find_option('--ext')
|
140
152
|
opt.is_a?(HammerCLI::Options::OptionDefinition).must_equal true
|
141
|
-
cmd.new({}).extended_request[0].must_equal(thin: true)
|
142
|
-
cmd.new({}).extended_request[1].must_equal(ssl: true)
|
143
|
-
cmd.new({}).extended_request[2].must_equal(with_authentication: true)
|
153
|
+
cmd.new('', {}).extended_request[0].must_equal(thin: true)
|
154
|
+
cmd.new('', {}).extended_request[1].must_equal(ssl: true)
|
155
|
+
cmd.new('', {}).extended_request[2].must_equal(with_authentication: true)
|
144
156
|
end
|
145
157
|
|
146
158
|
it 'should extend all except params' do
|
147
159
|
cmd.extend_with(CmdExtensions.new(except: :request_params))
|
148
|
-
cmd.new({}).extended_request[0].must_equal({})
|
149
|
-
cmd.new({}).extended_request[1].must_equal(ssl: true)
|
150
|
-
cmd.new({}).extended_request[2].must_equal(with_authentication: true)
|
160
|
+
cmd.new('', {}).extended_request[0].must_equal({})
|
161
|
+
cmd.new('', {}).extended_request[1].must_equal(ssl: true)
|
162
|
+
cmd.new('', {}).extended_request[2].must_equal(with_authentication: true)
|
151
163
|
end
|
152
164
|
|
153
165
|
it 'should extend all except headers' do
|
154
166
|
cmd.extend_with(CmdExtensions.new(except: :request_headers))
|
155
|
-
cmd.new({}).extended_request[0].must_equal(thin: true)
|
156
|
-
cmd.new({}).extended_request[1].must_equal({})
|
157
|
-
cmd.new({}).extended_request[2].must_equal(with_authentication: true)
|
167
|
+
cmd.new('', {}).extended_request[0].must_equal(thin: true)
|
168
|
+
cmd.new('', {}).extended_request[1].must_equal({})
|
169
|
+
cmd.new('', {}).extended_request[2].must_equal(with_authentication: true)
|
158
170
|
end
|
159
171
|
|
160
172
|
it 'should extend all except options' do
|
161
173
|
cmd.extend_with(CmdExtensions.new(except: :request_options))
|
162
|
-
cmd.new({}).extended_request[0].must_equal(thin: true)
|
163
|
-
cmd.new({}).extended_request[1].must_equal(ssl: true)
|
164
|
-
cmd.new({}).extended_request[2].must_equal({})
|
174
|
+
cmd.new('', {}).extended_request[0].must_equal(thin: true)
|
175
|
+
cmd.new('', {}).extended_request[1].must_equal(ssl: true)
|
176
|
+
cmd.new('', {}).extended_request[2].must_equal({})
|
165
177
|
end
|
166
178
|
|
167
179
|
it 'should extend all except params and options and headers' do
|
168
180
|
cmd.extend_with(CmdExtensions.new(except: :request))
|
169
|
-
cmd.new({}).extended_request[0].must_equal({})
|
170
|
-
cmd.new({}).extended_request[1].must_equal({})
|
171
|
-
cmd.new({}).extended_request[2].must_equal({})
|
181
|
+
cmd.new('', {}).extended_request[0].must_equal({})
|
182
|
+
cmd.new('', {}).extended_request[1].must_equal({})
|
183
|
+
cmd.new('', {}).extended_request[2].must_equal({})
|
172
184
|
end
|
173
185
|
|
174
186
|
it 'should extend all except data' do
|
175
187
|
cmd.extend_with(CmdExtensions.new(except: :data))
|
176
|
-
cmd.new({}).help.must_match(/.*Section.*/)
|
177
|
-
cmd.new({}).help.must_match(/.*text.*/)
|
188
|
+
cmd.new('', {}).help.must_match(/.*Section.*/)
|
189
|
+
cmd.new('', {}).help.must_match(/.*text.*/)
|
178
190
|
cmd.output_definition.empty?.must_equal false
|
179
191
|
opt = cmd.find_option('--ext')
|
180
192
|
opt.is_a?(HammerCLI::Options::OptionDefinition).must_equal true
|
181
|
-
cmd.new({}).extended_request[0].must_equal(thin: true)
|
182
|
-
cmd.new({}).extended_request[1].must_equal(ssl: true)
|
183
|
-
cmd.new({}).extended_request[2].must_equal(with_authentication: true)
|
184
|
-
cmd.new({}).extended_data({}).must_equal({})
|
193
|
+
cmd.new('', {}).extended_request[0].must_equal(thin: true)
|
194
|
+
cmd.new('', {}).extended_request[1].must_equal(ssl: true)
|
195
|
+
cmd.new('', {}).extended_request[2].must_equal(with_authentication: true)
|
196
|
+
cmd.new('', {}).extended_data({}).must_equal({})
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'should extend all except option family' do
|
200
|
+
cmd.extend_with(CmdExtensions.new(except: :option_family))
|
201
|
+
cmd.output_definition.empty?.must_equal false
|
202
|
+
cmd.recognised_options.map(&:switches).flatten.must_equal ['--ext', '-h', '--help']
|
185
203
|
end
|
186
204
|
end
|
187
205
|
|
@@ -69,4 +69,26 @@ describe HammerCLI::Help::Builder do
|
|
69
69
|
help.string.strip.must_equal expected_output
|
70
70
|
end
|
71
71
|
end
|
72
|
+
|
73
|
+
describe 'option family' do
|
74
|
+
let(:family) { Class.new(HammerCLI::Options::OptionFamily) }
|
75
|
+
|
76
|
+
it 'prints option families' do
|
77
|
+
fm1 = family.new
|
78
|
+
fm1.parent(['--option-zzz'], 'OPT', 'Some description')
|
79
|
+
fm1.child(['--option-aaa'], 'OPT', 'Some description')
|
80
|
+
fm2 = family.new
|
81
|
+
fm2.parent(['--option-bbb'], 'OPT', 'Some description')
|
82
|
+
fm2.child(['--option-yyy'], 'OPT', 'Some description')
|
83
|
+
|
84
|
+
options = fm1.all + fm2.all
|
85
|
+
help.add_list('Options', options)
|
86
|
+
|
87
|
+
help.string.strip.must_equal [
|
88
|
+
'Options:',
|
89
|
+
' --option[-yyy|-bbb] Some description',
|
90
|
+
' --option[-aaa|-zzz] Some description',
|
91
|
+
].join("\n")
|
92
|
+
end
|
93
|
+
end
|
72
94
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
describe HammerCLI::Options::OptionFamily do
|
4
|
+
let(:family) do
|
5
|
+
HammerCLI::Options::OptionFamily.new(
|
6
|
+
deprecated: { '--test-one' => 'Use --test-two instead' }
|
7
|
+
)
|
8
|
+
end
|
9
|
+
let(:first_option) { HammerCLI::Apipie::OptionDefinition.new("--test-one", '', '') }
|
10
|
+
let(:second_option) { HammerCLI::Apipie::OptionDefinition.new("--test-two", '', '') }
|
11
|
+
let(:third_option) { HammerCLI::Apipie::OptionDefinition.new("--test-three", '', '') }
|
12
|
+
let(:full_family) do
|
13
|
+
family.parent('--test-one', '', 'Test').family.child('--test-two', '', '').family
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'switch' do
|
17
|
+
it 'returns nil if family is empty' do
|
18
|
+
family.switch.must_be_nil
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'returns parent switch if family has no children' do
|
22
|
+
family.parent('--test-one', '', '')
|
23
|
+
family.switch.must_equal '--test-one'
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'returns switch based on members' do
|
27
|
+
full_family.switch.must_equal '--test[-two|-one]'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'description' do
|
32
|
+
it 'returns parent description if nothing passed to initializer' do
|
33
|
+
full_family.description.must_equal full_family.head.help[1]
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'returns description with deprecation message' do
|
37
|
+
full_family.description.must_equal 'Test (--test-one is deprecated: Use --test-two instead)'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'adopt' do
|
42
|
+
it 'appends an option to children' do
|
43
|
+
full_family.adopt(third_option)
|
44
|
+
full_family.children.size.must_equal 2
|
45
|
+
third_option.family.must_equal full_family
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hammer_cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Bačovský
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-
|
12
|
+
date: 2020-05-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: clamp
|
@@ -145,7 +145,7 @@ dependencies:
|
|
145
145
|
version: 0.2.0
|
146
146
|
description: 'Hammer cli provides universal extendable CLI interface for ruby apps
|
147
147
|
|
148
|
-
'
|
148
|
+
'
|
149
149
|
email: mbacovsk@redhat.com
|
150
150
|
executables:
|
151
151
|
- hammer
|
@@ -252,6 +252,7 @@ files:
|
|
252
252
|
- lib/hammer_cli/options/normalizers.rb
|
253
253
|
- lib/hammer_cli/options/option_collector.rb
|
254
254
|
- lib/hammer_cli/options/option_definition.rb
|
255
|
+
- lib/hammer_cli/options/option_family.rb
|
255
256
|
- lib/hammer_cli/options/option_processor.rb
|
256
257
|
- lib/hammer_cli/options/predefined.rb
|
257
258
|
- lib/hammer_cli/options/processor_list.rb
|
@@ -353,6 +354,7 @@ files:
|
|
353
354
|
- test/unit/options/normalizers_test.rb
|
354
355
|
- test/unit/options/option_collector_test.rb
|
355
356
|
- test/unit/options/option_definition_test.rb
|
357
|
+
- test/unit/options/option_family_test.rb
|
356
358
|
- test/unit/options/processor_list_test.rb
|
357
359
|
- test/unit/options/sources/command_line_test.rb
|
358
360
|
- test/unit/options/sources/saved_defaults_test.rb
|
@@ -392,7 +394,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
392
394
|
- !ruby/object:Gem::Version
|
393
395
|
version: '0'
|
394
396
|
requirements: []
|
395
|
-
rubygems_version: 3.0.
|
397
|
+
rubygems_version: 3.0.8
|
396
398
|
signing_key:
|
397
399
|
specification_version: 4
|
398
400
|
summary: Universal command-line interface
|
@@ -414,6 +416,7 @@ test_files:
|
|
414
416
|
- test/unit/command_extensions_test.rb
|
415
417
|
- test/unit/main_test.rb
|
416
418
|
- test/unit/options/processor_list_test.rb
|
419
|
+
- test/unit/options/option_family_test.rb
|
417
420
|
- test/unit/options/validators/dsl_test.rb
|
418
421
|
- test/unit/options/sources/command_line_test.rb
|
419
422
|
- test/unit/options/sources/saved_defaults_test.rb
|