hammer_cli 0.15.1 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/doc/commands_modification.md +82 -0
  3. data/doc/creating_commands.md +78 -38
  4. data/doc/developer_docs.md +2 -0
  5. data/doc/help_modification.md +119 -0
  6. data/doc/i18n.md +2 -2
  7. data/doc/installation_rpm.md +3 -3
  8. data/doc/release_notes.md +9 -1
  9. data/lib/hammer_cli.rb +0 -1
  10. data/lib/hammer_cli/abstract.rb +44 -13
  11. data/lib/hammer_cli/exception_handler.rb +1 -1
  12. data/lib/hammer_cli/help/definition.rb +55 -0
  13. data/lib/hammer_cli/help/definition/abstract_item.rb +38 -0
  14. data/lib/hammer_cli/help/definition/list.rb +53 -0
  15. data/lib/hammer_cli/help/definition/section.rb +36 -0
  16. data/lib/hammer_cli/help/definition/text.rb +21 -0
  17. data/lib/hammer_cli/help/text_builder.rb +26 -49
  18. data/lib/hammer_cli/i18n.rb +0 -1
  19. data/lib/hammer_cli/options/option_collector.rb +12 -9
  20. data/lib/hammer_cli/options/option_processor.rb +17 -0
  21. data/lib/hammer_cli/options/processor_list.rb +37 -0
  22. data/lib/hammer_cli/options/sources/base.rb +17 -0
  23. data/lib/hammer_cli/options/sources/command_line.rb +3 -1
  24. data/lib/hammer_cli/options/sources/saved_defaults.rb +3 -1
  25. data/lib/hammer_cli/options/validators/base.rb +20 -0
  26. data/lib/hammer_cli/options/validators/dsl.rb +160 -0
  27. data/lib/hammer_cli/options/validators/dsl_block_validator.rb +19 -0
  28. data/lib/hammer_cli/output/adapter/csv.rb +11 -11
  29. data/lib/hammer_cli/output/adapter/tree_structure.rb +5 -3
  30. data/lib/hammer_cli/output/definition.rb +42 -4
  31. data/lib/hammer_cli/output/dsl.rb +4 -2
  32. data/lib/hammer_cli/output/fields.rb +9 -2
  33. data/lib/hammer_cli/testing/messages.rb +6 -6
  34. data/lib/hammer_cli/utils.rb +15 -0
  35. data/lib/hammer_cli/version.rb +1 -1
  36. data/locale/ca/LC_MESSAGES/hammer-cli.mo +0 -0
  37. data/locale/de/LC_MESSAGES/hammer-cli.mo +0 -0
  38. data/locale/en/LC_MESSAGES/hammer-cli.mo +0 -0
  39. data/locale/en_GB/LC_MESSAGES/hammer-cli.mo +0 -0
  40. data/locale/es/LC_MESSAGES/hammer-cli.mo +0 -0
  41. data/locale/fr/LC_MESSAGES/hammer-cli.mo +0 -0
  42. data/locale/it/LC_MESSAGES/hammer-cli.mo +0 -0
  43. data/locale/ja/LC_MESSAGES/hammer-cli.mo +0 -0
  44. data/locale/ko/LC_MESSAGES/hammer-cli.mo +0 -0
  45. data/locale/pt_BR/LC_MESSAGES/hammer-cli.mo +0 -0
  46. data/locale/ru/LC_MESSAGES/hammer-cli.mo +0 -0
  47. data/locale/zh_CN/LC_MESSAGES/hammer-cli.mo +0 -0
  48. data/locale/zh_TW/LC_MESSAGES/hammer-cli.mo +0 -0
  49. data/test/unit/abstract_test.rb +70 -5
  50. data/test/unit/exception_handler_test.rb +1 -1
  51. data/test/unit/help/definition/abstract_item_test.rb +33 -0
  52. data/test/unit/help/definition/list_test.rb +17 -0
  53. data/test/unit/help/definition/section_test.rb +25 -0
  54. data/test/unit/help/definition/text_test.rb +11 -0
  55. data/test/unit/help/definition_test.rb +236 -0
  56. data/test/unit/help/text_builder_test.rb +170 -1
  57. data/test/unit/options/option_collector_test.rb +18 -9
  58. data/test/unit/options/processor_list_test.rb +70 -0
  59. data/test/unit/{validator_test.rb → options/validators/dsl_test.rb} +57 -93
  60. data/test/unit/output/adapter/abstract_test.rb +3 -0
  61. data/test/unit/output/adapter/base_test.rb +5 -0
  62. data/test/unit/output/adapter/csv_test.rb +3 -0
  63. data/test/unit/output/adapter/json_test.rb +12 -0
  64. data/test/unit/output/adapter/table_test.rb +5 -0
  65. data/test/unit/output/adapter/yaml_test.rb +11 -0
  66. data/test/unit/output/definition_test.rb +221 -1
  67. data/test/unit/utils_test.rb +23 -0
  68. metadata +31 -5
  69. data/lib/hammer_cli/validator.rb +0 -172
@@ -50,7 +50,7 @@ module HammerCLI
50
50
  end
51
51
 
52
52
  def print_message(msg, options = {})
53
- output.print_message(msg, nil, options)
53
+ output.print_message(msg, {}, options)
54
54
  end
55
55
 
56
56
  def log_full_error(e, message = e.message)
@@ -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
- INDENT_STEP = 2
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
- @out.string
14
+ @definition.build_string
14
15
  end
15
16
 
16
- def text(content)
17
- puts unless first_print?
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
- puts indent(sub_builder.string)
46
- end
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
- protected
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 puts(*args)
65
- @out.puts(*args)
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 first_print?
69
- @out.size == 0
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 normalize_list(items)
73
- items.map do |i|
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
@@ -146,4 +146,3 @@ include FastGettext::Translation
146
146
 
147
147
  domain = [HammerCLI::I18n::LocaleDomain.new, HammerCLI::I18n::SystemLocaleDomain.new].find { |d| d.available? }
148
148
  HammerCLI::I18n.add_domain(domain) if domain
149
-
@@ -1,17 +1,20 @@
1
1
  module HammerCLI
2
2
  module Options
3
3
  class OptionCollector
4
- attr_accessor :option_sources
4
+ attr_accessor :option_processor
5
5
 
6
- def initialize(recognised_options, option_sources)
6
+ def initialize(recognised_options, option_processor)
7
7
  @recognised_options = recognised_options
8
- @option_sources = option_sources
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 ||= @option_sources.inject({}) do |all_options, source|
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