hammer_cli 0.15.1 → 0.16.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_modification.md +82 -0
- data/doc/creating_commands.md +78 -38
- data/doc/developer_docs.md +2 -0
- data/doc/help_modification.md +119 -0
- data/doc/i18n.md +2 -2
- data/doc/installation_rpm.md +3 -3
- data/doc/release_notes.md +9 -1
- data/lib/hammer_cli.rb +0 -1
- data/lib/hammer_cli/abstract.rb +44 -13
- data/lib/hammer_cli/exception_handler.rb +1 -1
- data/lib/hammer_cli/help/definition.rb +55 -0
- data/lib/hammer_cli/help/definition/abstract_item.rb +38 -0
- data/lib/hammer_cli/help/definition/list.rb +53 -0
- data/lib/hammer_cli/help/definition/section.rb +36 -0
- data/lib/hammer_cli/help/definition/text.rb +21 -0
- data/lib/hammer_cli/help/text_builder.rb +26 -49
- data/lib/hammer_cli/i18n.rb +0 -1
- data/lib/hammer_cli/options/option_collector.rb +12 -9
- data/lib/hammer_cli/options/option_processor.rb +17 -0
- data/lib/hammer_cli/options/processor_list.rb +37 -0
- data/lib/hammer_cli/options/sources/base.rb +17 -0
- data/lib/hammer_cli/options/sources/command_line.rb +3 -1
- data/lib/hammer_cli/options/sources/saved_defaults.rb +3 -1
- data/lib/hammer_cli/options/validators/base.rb +20 -0
- data/lib/hammer_cli/options/validators/dsl.rb +160 -0
- data/lib/hammer_cli/options/validators/dsl_block_validator.rb +19 -0
- data/lib/hammer_cli/output/adapter/csv.rb +11 -11
- data/lib/hammer_cli/output/adapter/tree_structure.rb +5 -3
- data/lib/hammer_cli/output/definition.rb +42 -4
- data/lib/hammer_cli/output/dsl.rb +4 -2
- data/lib/hammer_cli/output/fields.rb +9 -2
- data/lib/hammer_cli/testing/messages.rb +6 -6
- data/lib/hammer_cli/utils.rb +15 -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 +70 -5
- data/test/unit/exception_handler_test.rb +1 -1
- data/test/unit/help/definition/abstract_item_test.rb +33 -0
- data/test/unit/help/definition/list_test.rb +17 -0
- data/test/unit/help/definition/section_test.rb +25 -0
- data/test/unit/help/definition/text_test.rb +11 -0
- data/test/unit/help/definition_test.rb +236 -0
- data/test/unit/help/text_builder_test.rb +170 -1
- data/test/unit/options/option_collector_test.rb +18 -9
- data/test/unit/options/processor_list_test.rb +70 -0
- data/test/unit/{validator_test.rb → options/validators/dsl_test.rb} +57 -93
- data/test/unit/output/adapter/abstract_test.rb +3 -0
- data/test/unit/output/adapter/base_test.rb +5 -0
- data/test/unit/output/adapter/csv_test.rb +3 -0
- data/test/unit/output/adapter/json_test.rb +12 -0
- data/test/unit/output/adapter/table_test.rb +5 -0
- data/test/unit/output/adapter/yaml_test.rb +11 -0
- data/test/unit/output/definition_test.rb +221 -1
- data/test/unit/utils_test.rb +23 -0
- metadata +31 -5
- data/lib/hammer_cli/validator.rb +0 -172
@@ -0,0 +1,55 @@
|
|
1
|
+
require_relative 'definition/abstract_item'
|
2
|
+
require_relative 'definition/text'
|
3
|
+
require_relative 'definition/list'
|
4
|
+
require_relative 'definition/section'
|
5
|
+
|
6
|
+
module HammerCLI
|
7
|
+
module Help
|
8
|
+
class Definition < Array
|
9
|
+
def build_string
|
10
|
+
@out = StringIO.new
|
11
|
+
each do |item|
|
12
|
+
next unless item.is_a? AbstractItem
|
13
|
+
@out.puts unless first_print?
|
14
|
+
@out.puts item.build_string
|
15
|
+
end
|
16
|
+
@out.string
|
17
|
+
end
|
18
|
+
|
19
|
+
def find_item(item_id)
|
20
|
+
self[item_index(item_id)]
|
21
|
+
end
|
22
|
+
|
23
|
+
def at(path)
|
24
|
+
return super(path) if path.is_a? Integer
|
25
|
+
return self if path.empty?
|
26
|
+
expand_path(path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def insert_definition(mode, item_id, definition)
|
30
|
+
HammerCLI.insert_relative(self, mode, item_index(item_id), *definition)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def expand_path(path)
|
36
|
+
path = [path] unless path.is_a? Array
|
37
|
+
item = find_item(path[0])
|
38
|
+
return item if path[1..-1].empty?
|
39
|
+
item.definition.at(path[1..-1])
|
40
|
+
end
|
41
|
+
|
42
|
+
def first_print?
|
43
|
+
@out.size.zero?
|
44
|
+
end
|
45
|
+
|
46
|
+
def item_index(item_id)
|
47
|
+
index = find_index do |item|
|
48
|
+
item.id == item_id
|
49
|
+
end
|
50
|
+
raise ArgumentError, "Help item '#{item_id}' not found" if index.nil?
|
51
|
+
index
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module HammerCLI
|
2
|
+
module Help
|
3
|
+
class AbstractItem
|
4
|
+
INDENT_STEP = 2
|
5
|
+
|
6
|
+
attr_reader :id
|
7
|
+
attr_accessor :definition
|
8
|
+
|
9
|
+
def initialize(options = {})
|
10
|
+
@id = options[:id]
|
11
|
+
@indentation = options[:indentation]
|
12
|
+
end
|
13
|
+
|
14
|
+
def build_string
|
15
|
+
raise NotImplementedError
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.indent(content, indentation = nil)
|
19
|
+
indentation ||= ' ' * INDENT_STEP
|
20
|
+
content = content.split("\n") unless content.is_a? Array
|
21
|
+
content.map do |line|
|
22
|
+
(indentation + line).rstrip
|
23
|
+
end.join("\n")
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def build_definition(content)
|
29
|
+
raise NotImplementedError
|
30
|
+
end
|
31
|
+
|
32
|
+
def indent(content, indentation = nil)
|
33
|
+
indentation ||= @indentation
|
34
|
+
self.class.indent(content, indentation)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module HammerCLI
|
2
|
+
module Help
|
3
|
+
class List < AbstractItem
|
4
|
+
LIST_INDENT = 20
|
5
|
+
|
6
|
+
def initialize(items, options = {})
|
7
|
+
super(options)
|
8
|
+
@indent_size = options[:indent_size] || indent_size(items)
|
9
|
+
build_definition(items || [])
|
10
|
+
end
|
11
|
+
|
12
|
+
def build_string
|
13
|
+
out = StringIO.new
|
14
|
+
@definition.each do |item|
|
15
|
+
out.puts item.build_string
|
16
|
+
end
|
17
|
+
out.string
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def build_definition(items)
|
23
|
+
@definition = Definition.new
|
24
|
+
items.each do |item|
|
25
|
+
@definition << Text.new(format_item(item))
|
26
|
+
end
|
27
|
+
@definition
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def indent_size(items)
|
33
|
+
items = normalize(items)
|
34
|
+
max_len = items.map { |i| i[0].to_s.length }.max
|
35
|
+
(max_len + INDENT_STEP > LIST_INDENT) ? (max_len + INDENT_STEP) : LIST_INDENT
|
36
|
+
end
|
37
|
+
|
38
|
+
def format_item(item)
|
39
|
+
col1, col2 = item
|
40
|
+
col2 = indent(col2.to_s, ' ' * @indent_size).lstrip
|
41
|
+
line = "%-#{@indent_size}s%s" % [col1, col2]
|
42
|
+
line.strip!
|
43
|
+
line
|
44
|
+
end
|
45
|
+
|
46
|
+
def normalize(items)
|
47
|
+
items.map do |i|
|
48
|
+
i.is_a?(Array) ? i : [i]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module HammerCLI
|
2
|
+
module Help
|
3
|
+
class Section < AbstractItem
|
4
|
+
attr_reader :label
|
5
|
+
|
6
|
+
def initialize(label, definition = nil, options = {})
|
7
|
+
super(options)
|
8
|
+
@label = label
|
9
|
+
@richtext = options[:richtext] || false
|
10
|
+
@id ||= label
|
11
|
+
build_definition(definition)
|
12
|
+
end
|
13
|
+
|
14
|
+
def build_string
|
15
|
+
out = StringIO.new
|
16
|
+
out.puts heading
|
17
|
+
out.puts indent(@definition.build_string)
|
18
|
+
out.string
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def build_definition(content)
|
24
|
+
@definition = content || Definition.new
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def heading
|
30
|
+
label = "#{@label}:"
|
31
|
+
label = HighLine.color(label, :bold) if @richtext
|
32
|
+
label
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module HammerCLI
|
2
|
+
module Help
|
3
|
+
class Text < AbstractItem
|
4
|
+
def initialize(text = nil, options = {})
|
5
|
+
super(options)
|
6
|
+
build_definition(text)
|
7
|
+
end
|
8
|
+
|
9
|
+
def build_string
|
10
|
+
@text
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def build_definition(content)
|
16
|
+
@text = content || ''
|
17
|
+
@definition = Definition.new([self])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,78 +1,55 @@
|
|
1
|
+
require 'hammer_cli/help/definition'
|
2
|
+
|
1
3
|
module HammerCLI
|
2
4
|
module Help
|
3
5
|
class TextBuilder
|
4
|
-
|
5
|
-
LIST_INDENT = 20
|
6
|
+
attr_accessor :definition
|
6
7
|
|
7
8
|
def initialize(richtext = false)
|
8
|
-
@out = StringIO.new
|
9
9
|
@richtext = richtext
|
10
|
+
@definition = HammerCLI::Help::Definition.new
|
10
11
|
end
|
11
12
|
|
12
13
|
def string
|
13
|
-
@
|
14
|
+
@definition.build_string
|
14
15
|
end
|
15
16
|
|
16
|
-
def text(content)
|
17
|
-
|
18
|
-
puts content
|
17
|
+
def text(content, options = {})
|
18
|
+
@definition << HammerCLI::Help::Text.new(content, options)
|
19
19
|
end
|
20
20
|
|
21
|
-
def list(items)
|
21
|
+
def list(items, options = {})
|
22
22
|
return if items.empty?
|
23
|
-
|
24
|
-
items = normalize_list(items)
|
25
|
-
max_len = items.map { |i| i[0].to_s.length }.max
|
26
|
-
indent_size = (max_len + INDENT_STEP > LIST_INDENT) ? (max_len + INDENT_STEP) : LIST_INDENT
|
27
|
-
|
28
|
-
puts unless first_print?
|
29
|
-
items.each do |col1, col2|
|
30
|
-
# handle multiple lines in the second column
|
31
|
-
col2 = indent(col2.to_s, ' ' * indent_size).lstrip
|
32
|
-
|
33
|
-
line = "%-#{indent_size}s%s" % [col1, col2]
|
34
|
-
line.strip!
|
35
|
-
puts line
|
36
|
-
end
|
23
|
+
@definition << HammerCLI::Help::List.new(items, options)
|
37
24
|
end
|
38
25
|
|
39
|
-
def section(label, &block)
|
40
|
-
puts unless first_print?
|
41
|
-
heading(label)
|
42
|
-
|
26
|
+
def section(label, options = {}, &block)
|
43
27
|
sub_builder = TextBuilder.new(@richtext)
|
44
28
|
yield(sub_builder) if block_given?
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
def indent(content, indentation = nil)
|
49
|
-
indentation ||= " " * INDENT_STEP
|
50
|
-
content = content.split("\n") unless content.is_a? Array
|
51
|
-
content.map do |line|
|
52
|
-
(indentation + line).rstrip
|
53
|
-
end.join("\n")
|
29
|
+
options[:richtext] ||= @richtext
|
30
|
+
@definition << HammerCLI::Help::Section.new(label, sub_builder.definition, options)
|
54
31
|
end
|
55
32
|
|
56
|
-
|
57
|
-
|
58
|
-
def heading(label)
|
59
|
-
label = "#{label}:"
|
60
|
-
label = HighLine.color(label, :bold) if @richtext
|
61
|
-
puts label
|
33
|
+
def find_item(item_id)
|
34
|
+
@definition.find_item(item_id)
|
62
35
|
end
|
63
36
|
|
64
|
-
def
|
65
|
-
@
|
37
|
+
def at(path = [])
|
38
|
+
item = path.empty? ? self : @definition.at(path)
|
39
|
+
sub_builder = TextBuilder.new(@richtext)
|
40
|
+
sub_builder.definition = item.definition
|
41
|
+
yield(sub_builder)
|
42
|
+
item.definition = sub_builder.definition
|
66
43
|
end
|
67
44
|
|
68
|
-
def
|
69
|
-
|
45
|
+
def insert(mode, item_id)
|
46
|
+
sub_builder = TextBuilder.new(@richtext)
|
47
|
+
yield(sub_builder)
|
48
|
+
@definition.insert_definition(mode, item_id, sub_builder.definition)
|
70
49
|
end
|
71
50
|
|
72
|
-
def
|
73
|
-
|
74
|
-
i.is_a?(Array) ? i : [i]
|
75
|
-
end
|
51
|
+
def indent(content, indentation = nil)
|
52
|
+
HammerCLI::Help::AbstractItem.indent(content, indentation)
|
76
53
|
end
|
77
54
|
end
|
78
55
|
end
|
data/lib/hammer_cli/i18n.rb
CHANGED
@@ -1,17 +1,20 @@
|
|
1
1
|
module HammerCLI
|
2
2
|
module Options
|
3
3
|
class OptionCollector
|
4
|
-
attr_accessor :
|
4
|
+
attr_accessor :option_processor
|
5
5
|
|
6
|
-
def initialize(recognised_options,
|
6
|
+
def initialize(recognised_options, option_processor)
|
7
7
|
@recognised_options = recognised_options
|
8
|
-
|
8
|
+
|
9
|
+
if !option_processor.is_a?(HammerCLI::Options::ProcessorList)
|
10
|
+
@option_processor = HammerCLI::Options::ProcessorList.new(option_processor)
|
11
|
+
else
|
12
|
+
@option_processor = option_processor
|
13
|
+
end
|
9
14
|
end
|
10
15
|
|
11
16
|
def all_options_raw
|
12
|
-
@all_options_raw ||= @
|
13
|
-
source.get_options(@recognised_options, all_options)
|
14
|
-
end
|
17
|
+
@all_options_raw ||= @option_processor.process(@recognised_options, {})
|
15
18
|
end
|
16
19
|
|
17
20
|
def all_options
|
@@ -21,13 +24,13 @@ module HammerCLI
|
|
21
24
|
def options
|
22
25
|
@options ||= all_options.reject { |key, value| value.nil? && all_options_raw[key].nil? }
|
23
26
|
end
|
24
|
-
|
27
|
+
|
25
28
|
private
|
26
|
-
|
29
|
+
|
27
30
|
def translate_nils(opts)
|
28
31
|
Hash[ opts.map { |k,v| [k, translate_nil(v)] } ]
|
29
32
|
end
|
30
|
-
|
33
|
+
|
31
34
|
def translate_nil(value)
|
32
35
|
value == HammerCLI::NilValue ? nil : value
|
33
36
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module HammerCLI
|
2
|
+
module Options
|
3
|
+
class OptionProcessor
|
4
|
+
def initialize(name: nil)
|
5
|
+
@name = name
|
6
|
+
end
|
7
|
+
|
8
|
+
def name
|
9
|
+
@name || self.class.name.split('::')[-1]
|
10
|
+
end
|
11
|
+
|
12
|
+
def process(defined_options, result)
|
13
|
+
result
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module HammerCLI
|
2
|
+
module Options
|
3
|
+
class ProcessorList < Array
|
4
|
+
attr_reader :name
|
5
|
+
|
6
|
+
def initialize(sources = [], name: nil)
|
7
|
+
@name = name
|
8
|
+
self.push(*sources)
|
9
|
+
end
|
10
|
+
|
11
|
+
def insert_relative(mode, target_name, processor)
|
12
|
+
index = target_name.nil? ? nil : item_index(target_name)
|
13
|
+
HammerCLI.insert_relative(self, mode, index, processor)
|
14
|
+
end
|
15
|
+
|
16
|
+
def find_by_name(name)
|
17
|
+
self[item_index(name)]
|
18
|
+
end
|
19
|
+
|
20
|
+
def process(defined_options, result)
|
21
|
+
self.inject(result) do |all_options, processor|
|
22
|
+
processor.process(defined_options, all_options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def item_index(target_name)
|
29
|
+
idx = find_index do |item|
|
30
|
+
item.respond_to?(:name) && (item.name == target_name)
|
31
|
+
end
|
32
|
+
raise ArgumentError, "Option processor '#{target_name}' not found" if idx.nil?
|
33
|
+
idx
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative '../option_processor'
|
2
|
+
|
3
|
+
module HammerCLI
|
4
|
+
module Options
|
5
|
+
module Sources
|
6
|
+
class Base < HammerCLI::Options::OptionProcessor
|
7
|
+
def process(defined_options, result)
|
8
|
+
get_options(defined_options, result)
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_options(defined_options, result)
|
12
|
+
result
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|