hammer_cli 2.5.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/bin/hammer +1 -1
  3. data/doc/commands_extension.md +8 -6
  4. data/doc/creating_commands.md +17 -0
  5. data/doc/release_notes.md +23 -0
  6. data/lib/hammer_cli/abstract.rb +75 -60
  7. data/lib/hammer_cli/apipie/command.rb +1 -1
  8. data/lib/hammer_cli/apipie/option_builder.rb +16 -11
  9. data/lib/hammer_cli/apipie/option_definition.rb +1 -8
  10. data/lib/hammer_cli/command_extensions.rb +47 -34
  11. data/lib/hammer_cli/help/builder.rb +10 -6
  12. data/lib/hammer_cli/options/normalizers.rb +126 -18
  13. data/lib/hammer_cli/options/option_definition.rb +17 -22
  14. data/lib/hammer_cli/options/option_family.rb +44 -8
  15. data/lib/hammer_cli/output/adapter/abstract.rb +6 -0
  16. data/lib/hammer_cli/output/adapter/base.rb +1 -1
  17. data/lib/hammer_cli/output/adapter/tree_structure.rb +1 -1
  18. data/lib/hammer_cli/output/definition.rb +1 -1
  19. data/lib/hammer_cli/output/field_filter.rb +2 -2
  20. data/lib/hammer_cli/utils.rb +6 -0
  21. data/lib/hammer_cli/version.rb +1 -1
  22. data/locale/ca/LC_MESSAGES/hammer-cli.mo +0 -0
  23. data/locale/de/LC_MESSAGES/hammer-cli.mo +0 -0
  24. data/locale/en/LC_MESSAGES/hammer-cli.mo +0 -0
  25. data/locale/en_GB/LC_MESSAGES/hammer-cli.mo +0 -0
  26. data/locale/es/LC_MESSAGES/hammer-cli.mo +0 -0
  27. data/locale/fr/LC_MESSAGES/hammer-cli.mo +0 -0
  28. data/locale/it/LC_MESSAGES/hammer-cli.mo +0 -0
  29. data/locale/ja/LC_MESSAGES/hammer-cli.mo +0 -0
  30. data/locale/ko/LC_MESSAGES/hammer-cli.mo +0 -0
  31. data/locale/pt_BR/LC_MESSAGES/hammer-cli.mo +0 -0
  32. data/locale/ru/LC_MESSAGES/hammer-cli.mo +0 -0
  33. data/locale/zh_CN/LC_MESSAGES/hammer-cli.mo +0 -0
  34. data/locale/zh_TW/LC_MESSAGES/hammer-cli.mo +0 -0
  35. data/man/hammer.1.gz +0 -0
  36. data/test/unit/abstract_test.rb +7 -0
  37. data/test/unit/apipie/option_builder_test.rb +8 -3
  38. data/test/unit/command_extensions_test.rb +10 -2
  39. data/test/unit/help/builder_test.rb +20 -2
  40. data/test/unit/options/option_definition_test.rb +12 -1
  41. data/test/unit/output/definition_test.rb +3 -3
  42. metadata +22 -22
@@ -29,7 +29,11 @@ module HammerCLI
29
29
 
30
30
  label_width = DEFAULT_LABEL_INDENT
31
31
  items.each do |item|
32
- label = item.help.first
32
+ label = if !HammerCLI.context[:full_help] && item.respond_to?(:family) && item.family && !item.child?
33
+ item.family.help.first
34
+ else
35
+ item.help.first
36
+ end
33
37
  label_width = label.size if label.size > label_width
34
38
  end
35
39
 
@@ -38,11 +42,11 @@ module HammerCLI
38
42
  next unless HammerCLI.context[:full_help]
39
43
  end
40
44
  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
45
- description.gsub(/^(.)/) { Unicode::capitalize($1) }.each_line do |line|
45
+ item.family.help
46
+ else
47
+ item.help
48
+ end
49
+ description.gsub(/^(.)/) { Unicode.capitalize(Regexp.last_match(1)) }.wrap.each_line do |line|
46
50
  puts " %-#{label_width}s %s" % [label, line]
47
51
  label = ''
48
52
  end
@@ -4,8 +4,28 @@ require 'hammer_cli/csv_parser'
4
4
  module HammerCLI
5
5
  module Options
6
6
  module Normalizers
7
+ def self.available
8
+ AbstractNormalizer.available
9
+ end
7
10
 
8
11
  class AbstractNormalizer
12
+ class << self
13
+ attr_reader :available
14
+
15
+ def inherited(subclass)
16
+ @available ||= []
17
+ @available << subclass
18
+ end
19
+
20
+ def completion_type
21
+ :value
22
+ end
23
+
24
+ def common_description
25
+ _("Value described in the option's description. Mostly simple string")
26
+ end
27
+ end
28
+
9
29
  def description
10
30
  ""
11
31
  end
@@ -17,6 +37,10 @@ module HammerCLI
17
37
  def complete(val)
18
38
  []
19
39
  end
40
+
41
+ def completion_type
42
+ { type: self.class.completion_type }
43
+ end
20
44
  end
21
45
 
22
46
  class Default < AbstractNormalizer
@@ -30,9 +54,15 @@ module HammerCLI
30
54
  PAIR_RE = '([^,=]+)=([^,\{\[]+|[\{\[][^\{\}\[\]]*[\}\]])'
31
55
  FULL_RE = "^((%s)[,]?)+$" % PAIR_RE
32
56
 
33
- def description
34
- _("Comma-separated list of key=value.") + "\n" +
35
- _("JSON is acceptable and preferred way for complex parameters")
57
+ class << self
58
+ def completion_type
59
+ :key_value_list
60
+ end
61
+
62
+ def common_description
63
+ _('Comma-separated list of key=value.') + "\n" +
64
+ _('JSON is acceptable and preferred way for such parameters')
65
+ end
36
66
  end
37
67
 
38
68
  def format(val)
@@ -94,9 +124,16 @@ module HammerCLI
94
124
 
95
125
 
96
126
  class List < AbstractNormalizer
97
- def description
98
- _("Comma separated list of values. Values containing comma should be quoted or escaped with backslash.") + "\n" +
99
- _("JSON is acceptable and preferred way for complex parameters")
127
+ class << self
128
+ def completion_type
129
+ :list
130
+ end
131
+
132
+ def common_description
133
+ _('Comma separated list of values. Values containing comma should be quoted or escaped with backslash.') +
134
+ "\n" +
135
+ _('JSON is acceptable and preferred way for such parameters')
136
+ end
100
137
  end
101
138
 
102
139
  def format(val)
@@ -110,6 +147,18 @@ module HammerCLI
110
147
  end
111
148
 
112
149
  class ListNested < AbstractNormalizer
150
+ class << self
151
+ def completion_type
152
+ :schema
153
+ end
154
+
155
+ def common_description
156
+ _('Comma separated list of values defined by a schema.') +
157
+ "\n" +
158
+ _('JSON is acceptable and preferred way for such parameters')
159
+ end
160
+ end
161
+
113
162
  class Schema < Array
114
163
  def description(richtext: true)
115
164
  '"' + reduce([]) do |schema, nested_param|
@@ -135,11 +184,6 @@ module HammerCLI
135
184
  @schema = Schema.new(schema)
136
185
  end
137
186
 
138
- def description
139
- _("Comma separated list of values defined by a schema. See Option details section below.") + "\n" +
140
- _("JSON is acceptable and preferred way for complex parameters")
141
- end
142
-
143
187
  def format(val)
144
188
  return [] unless val.is_a?(String) && !val.empty?
145
189
  begin
@@ -152,9 +196,22 @@ module HammerCLI
152
196
  end
153
197
  end
154
198
  end
199
+
200
+ def completion_type
201
+ super.merge({ schema: schema.description(richtext: false) })
202
+ end
155
203
  end
156
204
 
157
205
  class Number < AbstractNormalizer
206
+ class << self
207
+ def completion_type
208
+ :number
209
+ end
210
+
211
+ def common_description
212
+ _('Numeric value. Integer')
213
+ end
214
+ end
158
215
 
159
216
  def format(val)
160
217
  if numeric?(val)
@@ -167,17 +224,22 @@ module HammerCLI
167
224
  def numeric?(val)
168
225
  Integer(val) != nil rescue false
169
226
  end
170
-
171
227
  end
172
228
 
173
229
 
174
230
  class Bool < AbstractNormalizer
175
- def allowed_values
176
- ['yes', 'no', 'true', 'false', '1', '0']
231
+ class << self
232
+ def completion_type
233
+ :boolean
234
+ end
235
+
236
+ def common_description
237
+ _('One of %s') % ['true/false', 'yes/no', '1/0'].join(', ')
238
+ end
177
239
  end
178
240
 
179
- def description
180
- _('One of %s.') % ['true/false', 'yes/no', '1/0'].join(', ')
241
+ def allowed_values
242
+ ['yes', 'no', 'true', 'false', '1', '0']
181
243
  end
182
244
 
183
245
  def format(bool)
@@ -194,10 +256,23 @@ module HammerCLI
194
256
  def complete(value)
195
257
  allowed_values.map { |v| v + ' ' }
196
258
  end
259
+
260
+ def completion_type
261
+ super.merge({ values: allowed_values })
262
+ end
197
263
  end
198
264
 
199
265
 
200
266
  class File < AbstractNormalizer
267
+ class << self
268
+ def completion_type
269
+ :file
270
+ end
271
+
272
+ def common_description
273
+ _('Path to a file')
274
+ end
275
+ end
201
276
 
202
277
  def format(path)
203
278
  ::File.read(::File.expand_path(path))
@@ -233,6 +308,16 @@ module HammerCLI
233
308
 
234
309
 
235
310
  class Enum < AbstractNormalizer
311
+ class << self
312
+ def completion_type
313
+ :enum
314
+ end
315
+
316
+ def common_description
317
+ _("Possible values are described in the option's description")
318
+ end
319
+ end
320
+
236
321
  attr_reader :allowed_values
237
322
 
238
323
  def initialize(allowed_values)
@@ -260,6 +345,10 @@ module HammerCLI
260
345
  Completer::finalize_completions(@allowed_values)
261
346
  end
262
347
 
348
+ def completion_type
349
+ super.merge({ values: allowed_values })
350
+ end
351
+
263
352
  private
264
353
 
265
354
  def quoted_values
@@ -269,9 +358,14 @@ module HammerCLI
269
358
 
270
359
 
271
360
  class DateTime < AbstractNormalizer
361
+ class << self
362
+ def completion_type
363
+ :datetime
364
+ end
272
365
 
273
- def description
274
- _("Date and time in YYYY-MM-DD HH:MM:SS or ISO 8601 format")
366
+ def common_description
367
+ _('Date and time in YYYY-MM-DD HH:MM:SS or ISO 8601 format')
368
+ end
275
369
  end
276
370
 
277
371
  def format(date)
@@ -283,6 +377,16 @@ module HammerCLI
283
377
  end
284
378
 
285
379
  class EnumList < AbstractNormalizer
380
+ class << self
381
+ def completion_type
382
+ :multienum
383
+ end
384
+
385
+ def common_description
386
+ _("Any combination of possible values described in the option's description")
387
+ end
388
+ end
389
+
286
390
  attr_reader :allowed_values
287
391
 
288
392
  def initialize(allowed_values)
@@ -301,6 +405,10 @@ module HammerCLI
301
405
  Completer::finalize_completions(@allowed_values)
302
406
  end
303
407
 
408
+ def completion_type
409
+ super.merge({ values: allowed_values })
410
+ end
411
+
304
412
  private
305
413
 
306
414
  def quoted_values
@@ -22,12 +22,14 @@ module HammerCLI
22
22
 
23
23
  class OptionDefinition < Clamp::Option::Definition
24
24
 
25
- attr_accessor :value_formatter, :context_target, :deprecated_switches
25
+ attr_accessor :value_formatter, :context_target, :deprecated_switches,
26
+ :family
26
27
 
27
28
  def initialize(switches, type, description, options = {})
28
29
  @value_formatter = options[:format] || HammerCLI::Options::Normalizers::Default.new
29
30
  @context_target = options[:context_target]
30
31
  @deprecated_switches = options[:deprecated]
32
+ @family = options[:family]
31
33
  super
32
34
  end
33
35
 
@@ -36,7 +38,9 @@ module HammerCLI
36
38
  end
37
39
 
38
40
  def help_lhs
39
- super
41
+ lhs = switches.join(', ')
42
+ lhs += " #{completion_type[:type]}".upcase unless flag?
43
+ lhs
40
44
  end
41
45
 
42
46
  def help_rhs
@@ -50,14 +54,14 @@ module HammerCLI
50
54
  rhs.empty? ? " " : rhs
51
55
  end
52
56
 
53
- def handles?(switch)
57
+ def extract_value(switch, arguments)
54
58
  message = _("Warning: Option %{option} is deprecated. %{message}")
55
59
  if deprecated_switches.class <= String && switches.include?(switch)
56
- warn(message % { :option => switch, :message => deprecated_switches })
60
+ warn(message % { option: switch, message: deprecated_switches })
57
61
  elsif deprecated_switches.class <= Hash && deprecated_switches.keys.include?(switch)
58
- warn(message % { :option => switch, :message => deprecated_switches[switch] })
62
+ warn(message % { option: switch, message: deprecated_switches[switch] })
59
63
  end
60
- super(switch)
64
+ super(switch, arguments)
61
65
  end
62
66
 
63
67
  def deprecation_message(switch)
@@ -140,22 +144,13 @@ module HammerCLI
140
144
  return { type: :flag } if @type == :flag
141
145
 
142
146
  formatter ||= value_formatter
143
- completion_type = case formatter
144
- when HammerCLI::Options::Normalizers::Bool,
145
- HammerCLI::Options::Normalizers::Enum
146
- { type: :enum, values: value_formatter.allowed_values }
147
- when HammerCLI::Options::Normalizers::EnumList
148
- { type: :multienum, values: value_formatter.allowed_values }
149
- when HammerCLI::Options::Normalizers::ListNested
150
- { type: :schema, schema: value_formatter.schema.description(richtext: false) }
151
- when HammerCLI::Options::Normalizers::List
152
- { type: :list }
153
- when HammerCLI::Options::Normalizers::KeyValueList
154
- { type: :key_value_list }
155
- when HammerCLI::Options::Normalizers::File
156
- { type: :file }
157
- end
158
- completion_type || { type: :value }
147
+ formatter.completion_type
148
+ end
149
+
150
+ def child?
151
+ return unless @family
152
+
153
+ @family.children.include?(self)
159
154
  end
160
155
 
161
156
  private
@@ -2,25 +2,33 @@
2
2
 
3
3
  module HammerCLI
4
4
  module Options
5
+ class OptionFamilyRegistry < Array
6
+ # rubocop:disable Style/Alias
7
+ alias_method :register, :push
8
+ alias_method :unregister, :delete
9
+ # rubocop:enable Style/Alias
10
+ end
11
+
5
12
  class OptionFamily
6
13
  attr_reader :children
7
14
 
8
- IDS_REGEX = /(\A[Ii][Dd][s]?)|\s([Ii][Dd][s]?)\W|([Ii][Dd][s]?\Z)/
15
+ IDS_REGEX = /(\A[Ii][Dd][s]?)|\s([Ii][Dd][s]?)\W|([Ii][Dd][s]?\Z)|(numeric identifier|identifier)/.freeze
9
16
 
10
17
  def initialize(options = {})
11
18
  @all = []
12
19
  @children = []
13
20
  @options = options
14
- @creator = options[:creator] || Class.new(HammerCLI::Apipie::Command)
21
+ @creator = options[:creator] || self
15
22
  @prefix = options[:prefix]
16
23
  @root = options[:root] || options[:aliased_resource] || options[:referenced_resource]
24
+ @creator.family_registry.register(self) if @creator != self
17
25
  end
18
26
 
19
27
  def description
20
28
  types = all.map(&:type).map { |s| s.split('_').last.to_s }
21
29
  .map(&:downcase).join('/')
22
- parent_desc = @parent.help[1].gsub(IDS_REGEX) { |w| w.gsub(/\w+/, types) }
23
- desc = parent_desc.strip.empty? ? @options[:description] : parent_desc
30
+ parent_desc = @parent.help[1].gsub(IDS_REGEX) { |w| w.gsub(/\b.+\b/, types) }
31
+ desc = @options[:description] || parent_desc.strip.empty? ? @options[:description] : parent_desc
24
32
  if @options[:deprecation].class <= String
25
33
  format_deprecation_msg(desc, _('Deprecated: %{deprecated_msg}') % { deprecated_msg: @options[:deprecation] })
26
34
  elsif @options[:deprecation].class <= Hash
@@ -33,6 +41,21 @@ module HammerCLI
33
41
  end
34
42
  end
35
43
 
44
+ def help
45
+ [help_lhs, help_rhs]
46
+ end
47
+
48
+ def help_lhs
49
+ return @parent&.help_lhs if @children.empty?
50
+
51
+ types = all.map(&:value_formatter).map { |f| f.completion_type[:type].to_s.upcase }
52
+ switch + ' ' + types.uniq.join('/')
53
+ end
54
+
55
+ def help_rhs
56
+ description || @parent.help[1]
57
+ end
58
+
36
59
  def formats
37
60
  return [@options[:format].class] if @options[:format]
38
61
 
@@ -41,7 +64,7 @@ module HammerCLI
41
64
 
42
65
  def switch
43
66
  return if @parent.nil? && @children.empty?
44
- return @parent.help_lhs.strip if @children.empty?
67
+ return @parent.switches.join(', ').strip if @children.empty?
45
68
 
46
69
  switch_start = main_switch.each_char
47
70
  .zip(*all.map(&:switches).flatten.map(&:each_char))
@@ -68,6 +91,8 @@ module HammerCLI
68
91
 
69
92
  def child(switches, type, description, opts = {}, &block)
70
93
  child = new_member(switches, type, description, opts, &block)
94
+ return unless child
95
+
71
96
  @children << child
72
97
  child
73
98
  end
@@ -80,6 +105,18 @@ module HammerCLI
80
105
  @children << child
81
106
  end
82
107
 
108
+ def root
109
+ @root || @parent&.aliased_resource || @parent&.referenced_resource || common_root
110
+ end
111
+
112
+ def option(*args)
113
+ HammerCLI::Apipie::OptionDefinition.new(*args)
114
+ end
115
+
116
+ def find_option(switch)
117
+ all.find { |m| m.handles?(switch) }
118
+ end
119
+
83
120
  private
84
121
 
85
122
  def format_deprecation_msg(option_desc, deprecation_msg)
@@ -90,18 +127,17 @@ module HammerCLI
90
127
  opts = opts.merge(@options)
91
128
  opts[:family] = self
92
129
  if opts[:deprecated]
93
- handles = [switches].flatten
130
+ handles = Array(switches)
94
131
  opts[:deprecated] = opts[:deprecated].select do |switch, _msg|
95
132
  handles.include?(switch)
96
133
  end
97
134
  end
98
135
  @creator.instance_eval do
99
- option(switches, type, description, opts, &block)
136
+ option(switches, type, description, opts, &block) unless Array(switches).any? { |s| find_option(s) }
100
137
  end
101
138
  end
102
139
 
103
140
  def main_switch
104
- root = @root || @parent.aliased_resource || @parent.referenced_resource || common_root
105
141
  "--#{@prefix}#{root}".tr('_', '-')
106
142
  end
107
143
 
@@ -97,6 +97,12 @@ module HammerCLI::Output::Adapter
97
97
  @context[:fields] || ['DEFAULT']
98
98
  end
99
99
 
100
+ def context_for_fields
101
+ {
102
+ show_ids: @context[:show_ids]
103
+ }
104
+ end
105
+
100
106
  private
101
107
 
102
108
  def filter_formatters(formatters_map)
@@ -76,7 +76,7 @@ module HammerCLI::Output::Adapter
76
76
  def render_value(field, data)
77
77
  formatter = @formatters.formatter_for_type(field.class)
78
78
  parameters = field.parameters
79
- parameters[:context] = @context
79
+ parameters[:context] = context_for_fields
80
80
  data = formatter.format(data, field.parameters) if formatter
81
81
  data.to_s
82
82
  end
@@ -55,7 +55,7 @@ module HammerCLI::Output::Adapter
55
55
  else
56
56
  formatter = @formatters.formatter_for_type(field.class)
57
57
  parameters = field.parameters
58
- parameters[:context] = @context
58
+ parameters[:context] = context_for_fields
59
59
  if formatter
60
60
  data = formatter.format(data, field.parameters)
61
61
  end
@@ -73,7 +73,7 @@ module HammerCLI::Output
73
73
 
74
74
  data << sets.each_with_object({}) do |set, res|
75
75
  mark = field.sets.include?(set) ? 'x' : ''
76
- value = set == sets.first ? field.full_label : mark
76
+ value = set == sets.first ? field.full_label.capitalize : mark
77
77
  res.update(set => value)
78
78
  end
79
79
  end
@@ -11,7 +11,7 @@ module HammerCLI::Output
11
11
 
12
12
  def fields=(fields)
13
13
  @fields = fields || []
14
- @filtered_fields = @fields.dup
14
+ @filtered_fields = Marshal.load(Marshal.dump(@fields))
15
15
  end
16
16
 
17
17
  def filter_by_classes(classes = nil)
@@ -66,7 +66,7 @@ module HammerCLI::Output
66
66
 
67
67
  def include_by_label?(labels, label)
68
68
  labels.any? do |l|
69
- l.start_with?("#{label}/") || label.match(%r{^#{l.gsub(/\*/, '.*')}(|\/.*)$})
69
+ l.start_with?("#{label}/") || label.match(%r{^#{l.gsub(/\*/, '.*')}(|\/.*)$}) || l == label
70
70
  end
71
71
  end
72
72
 
@@ -40,6 +40,12 @@ class String
40
40
  HammerCLI.constant_path(self)[-1]
41
41
  end
42
42
 
43
+ # Rails implementation: https://github.com/rails/rails/blob/main/actionview/lib/action_view/helpers/text_helper.rb#L260
44
+ def wrap(line_width: 80, break_sequence: "\n")
45
+ split("\n").collect! do |line|
46
+ line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1#{break_sequence}").strip : line
47
+ end * break_sequence
48
+ end
43
49
  end
44
50
 
45
51
  class Hash
@@ -1,5 +1,5 @@
1
1
  module HammerCLI
2
2
  def self.version
3
- @version ||= Gem::Version.new "2.5.0"
3
+ @version ||= Gem::Version.new "3.1.0"
4
4
  end
5
5
  end
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/man/hammer.1.gz CHANGED
Binary file
@@ -308,6 +308,13 @@ describe HammerCLI::AbstractCommand do
308
308
  opt = TestOptionCmd.find_option('--fields')
309
309
  opt.is_a?(HammerCLI::Options::OptionDefinition).must_equal true
310
310
  end
311
+
312
+ it 'should add option type and accepted value' do
313
+ help_str = TestOptionCmd.help('')
314
+ help_str.must_match(
315
+ /LIST Comma separated list of values. Values containing comma should be quoted or escaped with backslash./
316
+ )
317
+ end
311
318
  end
312
319
 
313
320
  describe "#options" do
@@ -17,7 +17,7 @@ describe HammerCLI::Apipie::OptionBuilder do
17
17
  let(:resource) {api.resource(:documented)}
18
18
  let(:action) {resource.action(:index)}
19
19
  let(:builder) { HammerCLI::Apipie::OptionBuilder.new(resource, action) }
20
- let(:builder_options) { {} }
20
+ let(:builder_options) { { command: Class.new(HammerCLI::Apipie::Command) } }
21
21
  let(:options) { builder.build(builder_options) }
22
22
 
23
23
  context "with one simple param" do
@@ -51,7 +51,7 @@ describe HammerCLI::Apipie::OptionBuilder do
51
51
  context "required options" do
52
52
 
53
53
  let(:action) {resource.action(:create)}
54
- let(:required_options) { builder.build.reject{|opt| !opt.required?} }
54
+ let(:required_options) { builder.build(builder_options).reject{|opt| !opt.required?} }
55
55
 
56
56
  it "should set required flag for the required options" do
57
57
  required_options.map(&:attribute_name).sort.must_equal [HammerCLI.option_accessor_name("array_param")]
@@ -146,7 +146,12 @@ describe HammerCLI::Apipie::OptionBuilder do
146
146
 
147
147
  context "aliasing resources" do
148
148
  let(:action) {resource.action(:action_with_ids)}
149
- let(:builder_options) { {:resource_mapping => {:organization => 'company', 'compute_resource' => :compute_provider}} }
149
+ let(:builder_options) do
150
+ {
151
+ resource_mapping: { organization: 'company', 'compute_resource' => :compute_provider },
152
+ command: Class.new(HammerCLI::Apipie::Command)
153
+ }
154
+ end
150
155
 
151
156
  it "renames options" do
152
157
  # builder_options[:resource_mapping] = {:organization => 'company', 'compute_resource' => :compute_provider}
@@ -118,7 +118,7 @@ describe HammerCLI::CommandExtensions do
118
118
  it 'should extend option family only' do
119
119
  cmd.extend_with(CmdExtensions.new(only: :option_family))
120
120
  cmd.output_definition.empty?.must_equal true
121
- cmd.recognised_options.map(&:switches).flatten.must_equal ['--test-one', '--test-two', '-h', '--help']
121
+ cmd.recognised_options.map(&:switches).flatten.must_equal ['-h', '--help', '--test-one', '--test-two']
122
122
  end
123
123
  end
124
124
 
@@ -203,5 +203,13 @@ describe HammerCLI::CommandExtensions do
203
203
  end
204
204
  end
205
205
 
206
-
206
+ context 'associate family' do
207
+ it 'should associate option family' do
208
+ cmd.extend_with(CmdExtensions.new(only: :option_family))
209
+ cmd.option_family associate: 'test' do
210
+ child '--test-three', '', ''
211
+ end
212
+ cmd.recognised_options.map(&:switches).flatten.must_equal ['-h', '--help', '--test-one', '--test-two', '--test-three']
213
+ end
214
+ end
207
215
  end