hammer_cli 0.19.0 → 2.1.1

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.
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