hammer_cli 0.19.0 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (213) hide show
  1. checksums.yaml +4 -4
  2. data/bin/hammer-complete +28 -0
  3. data/config/cli_config.template.yml +2 -0
  4. data/config/hammer.completion +5 -0
  5. data/doc/commands_extension.md +12 -0
  6. data/doc/creating_commands.md +100 -0
  7. data/doc/installation.md +47 -4
  8. data/doc/release_notes.md +32 -5
  9. data/lib/hammer_cli.rb +1 -0
  10. data/lib/hammer_cli/abstract.rb +61 -4
  11. data/lib/hammer_cli/apipie/api_connection.rb +5 -1
  12. data/lib/hammer_cli/apipie/command.rb +3 -2
  13. data/lib/hammer_cli/apipie/option_builder.rb +15 -13
  14. data/lib/hammer_cli/apipie/option_definition.rb +9 -7
  15. data/lib/hammer_cli/bash.rb +2 -0
  16. data/lib/hammer_cli/bash/completion.rb +159 -0
  17. data/lib/hammer_cli/bash/prebuild_command.rb +21 -0
  18. data/lib/hammer_cli/command_extensions.rb +21 -1
  19. data/lib/hammer_cli/connection.rb +4 -0
  20. data/lib/hammer_cli/exception_handler.rb +11 -2
  21. data/lib/hammer_cli/full_help.rb +8 -1
  22. data/lib/hammer_cli/help/builder.rb +29 -3
  23. data/lib/hammer_cli/logger_watch.rb +1 -1
  24. data/lib/hammer_cli/main.rb +5 -3
  25. data/lib/hammer_cli/options/normalizers.rb +7 -3
  26. data/lib/hammer_cli/options/option_definition.rb +26 -6
  27. data/lib/hammer_cli/options/option_family.rb +114 -0
  28. data/lib/hammer_cli/options/predefined.rb +1 -1
  29. data/lib/hammer_cli/output.rb +1 -1
  30. data/lib/hammer_cli/output/adapter/abstract.rb +1 -5
  31. data/lib/hammer_cli/output/adapter/base.rb +1 -1
  32. data/lib/hammer_cli/output/adapter/csv.rb +3 -2
  33. data/lib/hammer_cli/output/adapter/json.rb +14 -3
  34. data/lib/hammer_cli/output/adapter/silent.rb +1 -1
  35. data/lib/hammer_cli/output/adapter/table.rb +30 -80
  36. data/lib/hammer_cli/output/adapter/yaml.rb +6 -3
  37. data/lib/hammer_cli/output/definition.rb +11 -56
  38. data/lib/hammer_cli/output/generators.rb +1 -0
  39. data/lib/hammer_cli/output/generators/table.rb +121 -0
  40. data/lib/hammer_cli/output/output.rb +2 -4
  41. data/lib/hammer_cli/settings.rb +2 -1
  42. data/lib/hammer_cli/subcommand.rb +25 -1
  43. data/lib/hammer_cli/testing/command_assertions.rb +2 -2
  44. data/lib/hammer_cli/utils.rb +22 -0
  45. data/lib/hammer_cli/version.rb +1 -1
  46. data/locale/ca/LC_MESSAGES/hammer-cli.mo +0 -0
  47. data/locale/de/LC_MESSAGES/hammer-cli.mo +0 -0
  48. data/locale/en/LC_MESSAGES/hammer-cli.mo +0 -0
  49. data/locale/en_GB/LC_MESSAGES/hammer-cli.mo +0 -0
  50. data/locale/es/LC_MESSAGES/hammer-cli.mo +0 -0
  51. data/locale/fr/LC_MESSAGES/hammer-cli.mo +0 -0
  52. data/locale/it/LC_MESSAGES/hammer-cli.mo +0 -0
  53. data/locale/ja/LC_MESSAGES/hammer-cli.mo +0 -0
  54. data/locale/ko/LC_MESSAGES/hammer-cli.mo +0 -0
  55. data/locale/pt_BR/LC_MESSAGES/hammer-cli.mo +0 -0
  56. data/locale/ru/LC_MESSAGES/hammer-cli.mo +0 -0
  57. data/locale/zh_CN/LC_MESSAGES/hammer-cli.mo +0 -0
  58. data/locale/zh_TW/LC_MESSAGES/hammer-cli.mo +0 -0
  59. data/man/hammer.1.gz +0 -0
  60. data/test/unit/abstract_test.rb +23 -2
  61. data/test/unit/apipie/api_connection_test.rb +1 -0
  62. data/test/unit/apipie/option_builder_test.rb +8 -0
  63. data/test/unit/bash_test.rb +138 -0
  64. data/test/unit/command_extensions_test.rb +67 -49
  65. data/test/unit/exception_handler_test.rb +44 -0
  66. data/test/unit/help/builder_test.rb +22 -0
  67. data/test/unit/options/option_family_test.rb +48 -0
  68. data/test/unit/output/adapter/base_test.rb +58 -0
  69. data/test/unit/output/adapter/csv_test.rb +63 -1
  70. data/test/unit/output/adapter/json_test.rb +61 -0
  71. data/test/unit/output/adapter/table_test.rb +70 -1
  72. data/test/unit/output/adapter/yaml_test.rb +59 -0
  73. data/test/unit/output/definition_test.rb +7 -7
  74. data/test/unit/output/output_test.rb +3 -3
  75. metadata +83 -345
  76. data/hammer_cli_complete +0 -13
  77. data/test/reports/TEST-Fields-ContainerField-display-.xml +0 -7
  78. data/test/reports/TEST-Fields-ContainerField-display-blank-is-allowed.xml +0 -15
  79. data/test/reports/TEST-Fields-ContainerField-display-blank-is-not-allowed.xml +0 -15
  80. data/test/reports/TEST-Fields-ContainerField.xml +0 -7
  81. data/test/reports/TEST-Fields-Field-display-.xml +0 -7
  82. data/test/reports/TEST-Fields-Field-display-blank-is-allowed.xml +0 -11
  83. data/test/reports/TEST-Fields-Field-display-blank-is-not-allowed.xml +0 -11
  84. data/test/reports/TEST-Fields-Field-hide-blank-.xml +0 -11
  85. data/test/reports/TEST-Fields-Field-parameters.xml +0 -9
  86. data/test/reports/TEST-Fields-Field.xml +0 -13
  87. data/test/reports/TEST-HammerCLI-AbstractCommand-build-options.xml +0 -15
  88. data/test/reports/TEST-HammerCLI-AbstractCommand-exception-handler.xml +0 -13
  89. data/test/reports/TEST-HammerCLI-AbstractCommand-logging.xml +0 -21
  90. data/test/reports/TEST-HammerCLI-AbstractCommand-option-builder.xml +0 -11
  91. data/test/reports/TEST-HammerCLI-AbstractCommand-options.xml +0 -11
  92. data/test/reports/TEST-HammerCLI-AbstractCommand-output.xml +0 -19
  93. data/test/reports/TEST-HammerCLI-AbstractCommand-subcommand-behavior-remove-subcommand.xml +0 -11
  94. data/test/reports/TEST-HammerCLI-AbstractCommand-subcommand-behavior-subcommand-.xml +0 -13
  95. data/test/reports/TEST-HammerCLI-AbstractCommand-subcommand-behavior-subcommand.xml +0 -11
  96. data/test/reports/TEST-HammerCLI-AbstractCommand-subcommand-behavior.xml +0 -7
  97. data/test/reports/TEST-HammerCLI-AbstractCommand.xml +0 -11
  98. data/test/reports/TEST-HammerCLI-Apipie-Command-options.xml +0 -11
  99. data/test/reports/TEST-HammerCLI-Apipie-Command-resource-defined.xml +0 -9
  100. data/test/reports/TEST-HammerCLI-Apipie-Command-setting-resources.xml +0 -19
  101. data/test/reports/TEST-HammerCLI-Apipie-Command.xml +0 -9
  102. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-aliasing-resources.xml +0 -13
  103. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-filtering-options.xml +0 -15
  104. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-required-options.xml +0 -11
  105. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-setting-correct-normalizers.xml +0 -9
  106. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-with-hash-params.xml +0 -11
  107. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-with-one-simple-param.xml +0 -15
  108. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder.xml +0 -7
  109. data/test/reports/TEST-HammerCLI-Completer-command-completion.xml +0 -29
  110. data/test/reports/TEST-HammerCLI-Completer-option-value-completion.xml +0 -17
  111. data/test/reports/TEST-HammerCLI-Completer-subcommand-completion.xml +0 -19
  112. data/test/reports/TEST-HammerCLI-Completer.xml +0 -7
  113. data/test/reports/TEST-HammerCLI-CompleterLine-line-complete.xml +0 -25
  114. data/test/reports/TEST-HammerCLI-CompleterLine-splitting-words.xml +0 -29
  115. data/test/reports/TEST-HammerCLI-CompleterLine.xml +0 -7
  116. data/test/reports/TEST-HammerCLI-CompleterWord-complete-.xml +0 -23
  117. data/test/reports/TEST-HammerCLI-CompleterWord-quote.xml +0 -15
  118. data/test/reports/TEST-HammerCLI-CompleterWord-quoted-.xml +0 -13
  119. data/test/reports/TEST-HammerCLI-CompleterWord.xml +0 -7
  120. data/test/reports/TEST-HammerCLI-Connection.xml +0 -21
  121. data/test/reports/TEST-HammerCLI-ExceptionHandler.xml +0 -21
  122. data/test/reports/TEST-HammerCLI-I18n.xml +0 -11
  123. data/test/reports/TEST-HammerCLI-MainCommand-loading-context-password.xml +0 -11
  124. data/test/reports/TEST-HammerCLI-MainCommand-loading-context-username.xml +0 -11
  125. data/test/reports/TEST-HammerCLI-MainCommand-loading-context-verbose.xml +0 -9
  126. data/test/reports/TEST-HammerCLI-MainCommand-loading-context.xml +0 -7
  127. data/test/reports/TEST-HammerCLI-MainCommand.xml +0 -7
  128. data/test/reports/TEST-HammerCLI-Modules-find-by-name.xml +0 -13
  129. data/test/reports/TEST-HammerCLI-Modules-load-a-module-module-not-found.xml +0 -13
  130. data/test/reports/TEST-HammerCLI-Modules-load-a-module-module-runtime-exception.xml +0 -13
  131. data/test/reports/TEST-HammerCLI-Modules-load-a-module-success.xml +0 -15
  132. data/test/reports/TEST-HammerCLI-Modules-load-a-module.xml +0 -7
  133. data/test/reports/TEST-HammerCLI-Modules-load-all-modules.xml +0 -9
  134. data/test/reports/TEST-HammerCLI-Modules-names.xml +0 -13
  135. data/test/reports/TEST-HammerCLI-Modules.xml +0 -7
  136. data/test/reports/TEST-HammerCLI-OptionBuilderContainer.0.xml +0 -7
  137. data/test/reports/TEST-HammerCLI-OptionBuilderContainer.xml +0 -11
  138. data/test/reports/TEST-HammerCLI-Options-Normalizers-abstract.xml +0 -9
  139. data/test/reports/TEST-HammerCLI-Options-Normalizers-bool.xml +0 -31
  140. data/test/reports/TEST-HammerCLI-Options-Normalizers-datetime.xml +0 -17
  141. data/test/reports/TEST-HammerCLI-Options-Normalizers-enum.xml +0 -15
  142. data/test/reports/TEST-HammerCLI-Options-Normalizers-enumlist.xml +0 -21
  143. data/test/reports/TEST-HammerCLI-Options-Normalizers-json-input.xml +0 -15
  144. data/test/reports/TEST-HammerCLI-Options-Normalizers-key-value-list.xml +0 -17
  145. data/test/reports/TEST-HammerCLI-Options-Normalizers-list.xml +0 -15
  146. data/test/reports/TEST-HammerCLI-Options-Normalizers.xml +0 -7
  147. data/test/reports/TEST-HammerCLI-Options-OptionDefinition-context.xml +0 -9
  148. data/test/reports/TEST-HammerCLI-Options-OptionDefinition-formatters.xml +0 -11
  149. data/test/reports/TEST-HammerCLI-Options-OptionDefinition.xml +0 -7
  150. data/test/reports/TEST-HammerCLI-Output-Adapter-Abstract-error-messages.xml +0 -15
  151. data/test/reports/TEST-HammerCLI-Output-Adapter-Abstract-messages.xml +0 -11
  152. data/test/reports/TEST-HammerCLI-Output-Adapter-Abstract-test-data-for-field.xml +0 -15
  153. data/test/reports/TEST-HammerCLI-Output-Adapter-Abstract.xml +0 -17
  154. data/test/reports/TEST-HammerCLI-Output-Adapter-Base-print-collection-show-ids.xml +0 -9
  155. data/test/reports/TEST-HammerCLI-Output-Adapter-Base-print-collection.xml +0 -27
  156. data/test/reports/TEST-HammerCLI-Output-Adapter-Base.xml +0 -7
  157. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-collection-formatters.xml +0 -11
  158. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-collection-handle-fields-with-collections.xml +0 -13
  159. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-collection-handle-fields-with-containers.xml +0 -11
  160. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-collection-handle-ids.xml +0 -11
  161. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-collection.xml +0 -11
  162. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-message.xml +0 -11
  163. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues.xml +0 -7
  164. data/test/reports/TEST-HammerCLI-Output-Adapter-Table-print-collection-column-width.xml +0 -15
  165. data/test/reports/TEST-HammerCLI-Output-Adapter-Table-print-collection-formatters.xml +0 -11
  166. data/test/reports/TEST-HammerCLI-Output-Adapter-Table-print-collection-handle-ids.xml +0 -11
  167. data/test/reports/TEST-HammerCLI-Output-Adapter-Table-print-collection-sort-columns.xml +0 -9
  168. data/test/reports/TEST-HammerCLI-Output-Adapter-Table-print-collection.xml +0 -11
  169. data/test/reports/TEST-HammerCLI-Output-Adapter-Table.xml +0 -7
  170. data/test/reports/TEST-HammerCLI-Output-Definition-empty-.xml +0 -11
  171. data/test/reports/TEST-HammerCLI-Output-Definition.xml +0 -11
  172. data/test/reports/TEST-HammerCLI-Output-Dsl-collection.xml +0 -13
  173. data/test/reports/TEST-HammerCLI-Output-Dsl-custom-fields.xml +0 -11
  174. data/test/reports/TEST-HammerCLI-Output-Dsl-fields.xml +0 -15
  175. data/test/reports/TEST-HammerCLI-Output-Dsl-label.xml +0 -13
  176. data/test/reports/TEST-HammerCLI-Output-Dsl-path-definition.xml +0 -13
  177. data/test/reports/TEST-HammerCLI-Output-Dsl.xml +0 -9
  178. data/test/reports/TEST-HammerCLI-Output-FieldFilter.xml +0 -13
  179. data/test/reports/TEST-HammerCLI-Output-Formatters-BooleanFormatter.xml +0 -11
  180. data/test/reports/TEST-HammerCLI-Output-Formatters-ColorFormatter.xml +0 -9
  181. data/test/reports/TEST-HammerCLI-Output-Formatters-DateFormatter.xml +0 -11
  182. data/test/reports/TEST-HammerCLI-Output-Formatters-FieldFormatter.xml +0 -13
  183. data/test/reports/TEST-HammerCLI-Output-Formatters-FormatterContainer.xml +0 -13
  184. data/test/reports/TEST-HammerCLI-Output-Formatters-FormatterLibrary.xml +0 -11
  185. data/test/reports/TEST-HammerCLI-Output-Formatters-KeyValueFormatter.xml +0 -13
  186. data/test/reports/TEST-HammerCLI-Output-Formatters-ListFormatter.xml +0 -13
  187. data/test/reports/TEST-HammerCLI-Output-Formatters-LongTextFormatter.xml +0 -13
  188. data/test/reports/TEST-HammerCLI-Output-Output-adapters.xml +0 -17
  189. data/test/reports/TEST-HammerCLI-Output-Output-data.xml +0 -15
  190. data/test/reports/TEST-HammerCLI-Output-Output-formatters.xml +0 -9
  191. data/test/reports/TEST-HammerCLI-Output-Output-messages.xml +0 -19
  192. data/test/reports/TEST-HammerCLI-Output-Output.xml +0 -7
  193. data/test/reports/TEST-HammerCLI-Output-RecordCollection.xml +0 -13
  194. data/test/reports/TEST-HammerCLI-Settings-load-from-paths.xml +0 -15
  195. data/test/reports/TEST-HammerCLI-Settings.xml +0 -25
  196. data/test/reports/TEST-HammerCLI-ShellHistory-loading-old-history.xml +0 -11
  197. data/test/reports/TEST-HammerCLI-ShellHistory-saving-history.xml +0 -15
  198. data/test/reports/TEST-HammerCLI-ShellHistory.xml +0 -7
  199. data/test/reports/TEST-MiniTest-Spec.xml +0 -7
  200. data/test/reports/TEST-String-camelize.xml +0 -11
  201. data/test/reports/TEST-String-formatting.xml +0 -17
  202. data/test/reports/TEST-String-indent.xml +0 -11
  203. data/test/reports/TEST-String-interactive-.xml +0 -13
  204. data/test/reports/TEST-String.xml +0 -7
  205. data/test/reports/TEST-constraints-HammerCLI-Validator-AllConstraint-exist-.xml +0 -13
  206. data/test/reports/TEST-constraints-HammerCLI-Validator-AllConstraint.xml +0 -7
  207. data/test/reports/TEST-constraints-HammerCLI-Validator-AnyConstraint-exist-.xml +0 -13
  208. data/test/reports/TEST-constraints-HammerCLI-Validator-AnyConstraint.xml +0 -7
  209. data/test/reports/TEST-constraints-HammerCLI-Validator-BaseConstraint-exist-.xml +0 -9
  210. data/test/reports/TEST-constraints-HammerCLI-Validator-BaseConstraint-rejected.xml +0 -13
  211. data/test/reports/TEST-constraints-HammerCLI-Validator-BaseConstraint-required.xml +0 -13
  212. data/test/reports/TEST-constraints-HammerCLI-Validator-BaseConstraint.xml +0 -7
  213. data/test/reports/TEST-constraints.xml +0 -7
@@ -6,9 +6,12 @@ module HammerCLI::Output::Adapter
6
6
  output_stream.puts YAML.dump(result.first)
7
7
  end
8
8
 
9
- def print_collection(fields, collection)
10
- result = prepare_collection(fields, collection)
11
- output_stream.puts YAML.dump(result)
9
+ def print_collection(fields, collection, options = {})
10
+ current_chunk = options[:current_chunk] || :single
11
+ prepared = prepare_collection(fields, collection)
12
+ result = YAML.dump(prepared)
13
+ result = result[4..-1] unless %i[first single].include?(current_chunk)
14
+ output_stream.puts result
12
15
  end
13
16
 
14
17
  def print_message(msg, msg_params={})
@@ -59,68 +59,23 @@ module HammerCLI::Output
59
59
  end
60
60
 
61
61
  def sets_table
62
- fields_col_size = max_label_length || _('Fields').size
63
- fields_col = normalize_column(fields_col_size, _('Fields'), centralize: true)
64
- fields_col += ' ' unless (fields_col_size - fields_col.size).zero?
65
- header_bits = [fields_col]
66
- hline_bits = ['-' * fields_col_size]
67
- field_sets.map do |set|
68
- header_bits << normalize_column(set.size, set)
69
- hline_bits << '-' * set.size
70
- end
71
- rows_bits = fields_row(@fields, field_sets, fields_col_size)
72
- line = "+-#{hline_bits.join('-+-')}-+\n"
73
- table = line
74
- table += "| #{header_bits.join(' | ')} |\n"
75
- table += line
76
- table += "#{rows_bits.join("\n")}\n"
77
- table += line
78
- table
62
+ columns = field_sets.unshift(_('Fields'))
63
+ data = fields_data(@fields, columns).flatten
64
+ table_gen = HammerCLI::Output::Generators::Table.new(columns, data)
65
+ table_gen.result
79
66
  end
80
67
 
81
68
  private
82
69
 
83
- def max_label_length
84
- field_labels(@fields, full_labels: true).map(&:size).max
85
- end
70
+ def fields_data(fields, sets)
71
+ fields.each_with_object([]) do |field, data|
72
+ next data << fields_data(field.fields, sets) if field.respond_to?(:fields)
86
73
 
87
- def normalize_column(width, col, centralize: false)
88
- padding = width - HammerCLI::Output::Utils.real_length(col)
89
- if padding >= 0
90
- if centralize
91
- padding /= 2
92
- col.prepend(' ' * padding)
74
+ data << sets.each_with_object({}) do |set, res|
75
+ mark = field.sets.include?(set) ? 'x' : ''
76
+ value = set == sets.first ? field.full_label : mark
77
+ res.update(set => value)
93
78
  end
94
- col += (' ' * padding)
95
- else
96
- col, real_len = HammerCLI::Output::Utils.real_truncate(col, width - 3)
97
- col += '...'
98
- col += ' ' if real_len < (width - 3)
99
- end
100
- col
101
- end
102
-
103
- def fields_row(fields, sets, fields_col_size)
104
- fields.each_with_object([]) do |field, rows|
105
- next rows << fields_row(field.fields, sets, fields_col_size) if field.respond_to?(:fields)
106
-
107
- row = [normalize_column(fields_col_size, field.full_label)]
108
- sets.each do |set|
109
- mark = field.sets.include?(set) ? 'x' : ' '
110
- column = normalize_column(set.size, mark, centralize: true)
111
- column += ' ' unless (set.size - column.size).zero?
112
- row << column
113
- end
114
- rows << "| #{row.join(' | ')} |"
115
- end
116
- end
117
-
118
- def field_labels(fields, full_labels: false)
119
- fields.each_with_object([]) do |field, labels|
120
- label = full_labels ? field.full_label : field.label
121
- next labels << label unless field.respond_to?(:fields)
122
-
123
- labels.concat(field_labels(field.fields, full_labels: full_labels))
124
79
  end
125
80
  end
126
81
 
@@ -0,0 +1 @@
1
+ require 'hammer_cli/output/generators/table'
@@ -0,0 +1,121 @@
1
+ require 'hammer_cli/output/utils'
2
+
3
+ module HammerCLI
4
+ module Output
5
+ module Generators
6
+ class Table
7
+ class Column
8
+ attr_reader :label, :params
9
+
10
+ def initialize(label, params = nil)
11
+ @label = label.to_s
12
+ @params = params || {}
13
+ end
14
+ end
15
+
16
+ MAX_COLUMN_WIDTH = 80
17
+ MIN_COLUMN_WIDTH = 5
18
+
19
+ HLINE = '-'
20
+ LINE_SEPARATOR = '-|-'
21
+ COLUMN_SEPARATOR = ' | '
22
+
23
+ attr_reader :header, :body, :footer, :result
24
+
25
+ def initialize(columns, data, options = {})
26
+ @columns = columns.map { |label, params| Column.new(label, params) }
27
+ @data = data
28
+ @options = options
29
+ create_table
30
+ end
31
+
32
+ private
33
+
34
+ def create_header(header_bits, line)
35
+ result = StringIO.new
36
+ unless @options[:no_headers]
37
+ result.puts(line)
38
+ result.puts(header_bits.join(COLUMN_SEPARATOR))
39
+ result.puts(line)
40
+ end
41
+ result.string
42
+ end
43
+
44
+ def create_body(widths)
45
+ result = StringIO.new
46
+ @data.collect do |row|
47
+ row_bits = @columns.map do |col|
48
+ normalize_column(widths[col.label], row[col.label] || '')
49
+ end
50
+ result.puts(row_bits.join(COLUMN_SEPARATOR))
51
+ end
52
+ result.string
53
+ end
54
+
55
+ def create_footer(line)
56
+ result = StringIO.new
57
+ result.puts(line) unless @data.empty? || @options[:no_headers]
58
+ result.string
59
+ end
60
+
61
+ def create_result
62
+ result = StringIO.new
63
+ result.print(@header, @body, @footer)
64
+ result.string
65
+ end
66
+
67
+ def create_table
68
+ widths = calculate_widths(@columns, @data)
69
+ header_bits = []
70
+ hline_bits = []
71
+ @columns.map do |col|
72
+ header_bits << normalize_column(widths[col.label], col.label.upcase)
73
+ hline_bits << HLINE * widths[col.label]
74
+ end
75
+ line = hline_bits.join(LINE_SEPARATOR)
76
+ @header = create_header(header_bits, line)
77
+ @body = create_body(widths)
78
+ @footer = create_footer(line)
79
+ @result = create_result
80
+ end
81
+
82
+ def normalize_column(width, value)
83
+ value = value.to_s
84
+ padding = width - HammerCLI::Output::Utils.real_length(value)
85
+ if padding >= 0
86
+ value += (' ' * padding)
87
+ else
88
+ value, real_length = HammerCLI::Output::Utils.real_truncate(value, width - 3)
89
+ value += '...'
90
+ value += ' ' if real_length < (width - 3)
91
+ end
92
+ value
93
+ end
94
+
95
+ def calculate_widths(columns, data)
96
+ Hash[columns.map { |c| [c.label, calculate_column_width(c, data)] }]
97
+ end
98
+
99
+ def calculate_column_width(column, data)
100
+ if column.params[:width]
101
+ return [column.params[:width], MIN_COLUMN_WIDTH].max
102
+ end
103
+
104
+ width = HammerCLI::Output::Utils.real_length(column.label)
105
+ max_width = max_width_for(column)
106
+ data.each do |item|
107
+ width = [HammerCLI::Output::Utils.real_length(item[column.label]), width].max
108
+ return max_width if width >= max_width
109
+ end
110
+ width
111
+ end
112
+
113
+ def max_width_for(column)
114
+ return MAX_COLUMN_WIDTH unless column.params[:max_width]
115
+
116
+ column.params[:max_width]
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -25,15 +25,13 @@ module HammerCLI::Output
25
25
 
26
26
  def print_record(definition, record)
27
27
  adapter.print_record(definition.fields, record) if appropriate_verbosity?(:record)
28
- adapter.reset_context
29
28
  end
30
29
 
31
- def print_collection(definition, collection)
30
+ def print_collection(definition, collection, options = {})
32
31
  unless collection.class <= HammerCLI::Output::RecordCollection
33
32
  collection = HammerCLI::Output::RecordCollection.new([collection].flatten(1))
34
33
  end
35
- adapter.print_collection(definition.fields, collection) if appropriate_verbosity?(:collection)
36
- adapter.reset_context
34
+ adapter.print_collection(definition.fields, collection, options) if appropriate_verbosity?(:collection)
37
35
  end
38
36
 
39
37
  def adapter
@@ -66,7 +66,8 @@ module HammerCLI
66
66
 
67
67
  def self.default_settings
68
68
  {
69
- :use_defaults => true
69
+ :use_defaults => true,
70
+ :completion_cache_file => '~/.cache/hammer_completion.yml'
70
71
  }
71
72
  end
72
73
 
@@ -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
@@ -60,6 +60,11 @@ module HammerCLI
60
60
  STDOUT.tty?
61
61
  end
62
62
 
63
+ def self.clear_cache
64
+ cache_file = File.expand_path(HammerCLI::Settings.get(:completion_cache_file))
65
+ File.delete(cache_file) if File.exist?(cache_file)
66
+ end
67
+
63
68
  def self.interactive?
64
69
  return HammerCLI::Settings.get(:_params, :interactive) unless HammerCLI::Settings.get(:_params, :interactive).nil?
65
70
  HammerCLI::Settings.get(:ui, :interactive) != false
@@ -111,4 +116,21 @@ module HammerCLI
111
116
 
112
117
  array.insert(idx, *new_items)
113
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
114
136
  end
@@ -1,5 +1,5 @@
1
1
  module HammerCLI
2
2
  def self.version
3
- @version ||= Gem::Version.new "0.19.0"
3
+ @version ||= Gem::Version.new "2.1.1"
4
4
  end
5
5
  end
Binary file
@@ -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
@@ -30,6 +30,7 @@ describe HammerCLI::Apipie::ApiConnection do
30
30
  it "logs message when logger is available" do
31
31
  logger = stub()
32
32
  logger.expects(:debug).with('Apipie cache was cleared')
33
+ logger.expects(:debug).with('Completion cache was cleared')
33
34
 
34
35
  api_stub.expects(:clean_cache)
35
36
  HammerCLI::Apipie::ApiConnection.new(empty_params, :reload_cache => true, :logger => logger)
@@ -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