cuprum-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +34 -0
  3. data/CODE_OF_CONDUCT.md +10 -0
  4. data/LICENSE +21 -0
  5. data/README.md +163 -0
  6. data/lib/cuprum/cli/argument.rb +172 -0
  7. data/lib/cuprum/cli/arguments/class_methods.rb +283 -0
  8. data/lib/cuprum/cli/arguments.rb +16 -0
  9. data/lib/cuprum/cli/coercion.rb +131 -0
  10. data/lib/cuprum/cli/command.rb +102 -0
  11. data/lib/cuprum/cli/commands/ci/report.rb +121 -0
  12. data/lib/cuprum/cli/commands/ci/rspec_command.rb +108 -0
  13. data/lib/cuprum/cli/commands/ci/rspec_each_command.rb +185 -0
  14. data/lib/cuprum/cli/commands/ci.rb +12 -0
  15. data/lib/cuprum/cli/commands/echo_command.rb +76 -0
  16. data/lib/cuprum/cli/commands/file/generate_file.rb +141 -0
  17. data/lib/cuprum/cli/commands/file/new_command.rb +86 -0
  18. data/lib/cuprum/cli/commands/file/render_erb.rb +88 -0
  19. data/lib/cuprum/cli/commands/file/resolve_template.rb +136 -0
  20. data/lib/cuprum/cli/commands/file/templates/rspec.rb.erb +14 -0
  21. data/lib/cuprum/cli/commands/file/templates/ruby.rb.erb +29 -0
  22. data/lib/cuprum/cli/commands/file/templates.rb +71 -0
  23. data/lib/cuprum/cli/commands/file.rb +14 -0
  24. data/lib/cuprum/cli/commands.rb +12 -0
  25. data/lib/cuprum/cli/dependencies/file_system/mock.rb +297 -0
  26. data/lib/cuprum/cli/dependencies/file_system.rb +247 -0
  27. data/lib/cuprum/cli/dependencies/standard_io/helpers.rb +138 -0
  28. data/lib/cuprum/cli/dependencies/standard_io/mock.rb +85 -0
  29. data/lib/cuprum/cli/dependencies/standard_io.rb +110 -0
  30. data/lib/cuprum/cli/dependencies/system_command/mock.rb +57 -0
  31. data/lib/cuprum/cli/dependencies/system_command.rb +147 -0
  32. data/lib/cuprum/cli/dependencies.rb +25 -0
  33. data/lib/cuprum/cli/errors/files/file_not_writeable.rb +42 -0
  34. data/lib/cuprum/cli/errors/files/missing_parameter.rb +71 -0
  35. data/lib/cuprum/cli/errors/files/missing_template.rb +36 -0
  36. data/lib/cuprum/cli/errors/files/template_error.rb +37 -0
  37. data/lib/cuprum/cli/errors/files/template_not_resolved.rb +54 -0
  38. data/lib/cuprum/cli/errors/files.rb +19 -0
  39. data/lib/cuprum/cli/errors/system_command_failure.rb +44 -0
  40. data/lib/cuprum/cli/errors.rb +11 -0
  41. data/lib/cuprum/cli/integrations/thor/arguments_parser.rb +99 -0
  42. data/lib/cuprum/cli/integrations/thor/registry.rb +42 -0
  43. data/lib/cuprum/cli/integrations/thor/task.rb +211 -0
  44. data/lib/cuprum/cli/integrations/thor.rb +14 -0
  45. data/lib/cuprum/cli/integrations.rb +8 -0
  46. data/lib/cuprum/cli/metadata.rb +215 -0
  47. data/lib/cuprum/cli/option.rb +165 -0
  48. data/lib/cuprum/cli/options/class_methods.rb +232 -0
  49. data/lib/cuprum/cli/options/quiet.rb +32 -0
  50. data/lib/cuprum/cli/options/verbose.rb +32 -0
  51. data/lib/cuprum/cli/options.rb +18 -0
  52. data/lib/cuprum/cli/registry.rb +141 -0
  53. data/lib/cuprum/cli/rspec/deferred/arguments_examples.rb +203 -0
  54. data/lib/cuprum/cli/rspec/deferred/ci/report_examples.rb +450 -0
  55. data/lib/cuprum/cli/rspec/deferred/ci.rb +8 -0
  56. data/lib/cuprum/cli/rspec/deferred/dependencies/file_system_examples.rb +1469 -0
  57. data/lib/cuprum/cli/rspec/deferred/dependencies.rb +8 -0
  58. data/lib/cuprum/cli/rspec/deferred/metadata_examples.rb +856 -0
  59. data/lib/cuprum/cli/rspec/deferred/options_examples.rb +234 -0
  60. data/lib/cuprum/cli/rspec/deferred/registry_examples.rb +451 -0
  61. data/lib/cuprum/cli/rspec/deferred.rb +8 -0
  62. data/lib/cuprum/cli/rspec.rb +8 -0
  63. data/lib/cuprum/cli/version.rb +59 -0
  64. data/lib/cuprum/cli.rb +47 -0
  65. metadata +173 -0
@@ -0,0 +1,234 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec/sleeping_king_studios/deferred/provider'
4
+
5
+ require 'cuprum/cli/rspec/deferred'
6
+
7
+ module Cuprum::Cli::RSpec::Deferred
8
+ # Deferred examples for testing command options.
9
+ module OptionsExamples
10
+ include RSpec::SleepingKingStudios::Deferred::Provider
11
+
12
+ deferred_examples 'should define option' do |option_name, **option_options|
13
+ describe "should define option #{option_name.inspect}" do
14
+ boolean_option =
15
+ option_options[:type] == :boolean && !option_options[:variadic]
16
+ expect_method =
17
+ option_options
18
+ .fetch(:define_method, !boolean_option)
19
+ expect_predicate =
20
+ option_options
21
+ .fetch(:define_predicate, boolean_option)
22
+
23
+ let(:configured_aliases) do
24
+ value = option_options.fetch(:aliases, [])
25
+ value = value.instance_exec(&value) if value.is_a?(Proc)
26
+
27
+ value
28
+ .then { |ary| Array(ary) }
29
+ .map(&:to_s)
30
+ end
31
+ let(:configured_default) do
32
+ value = option_options[:default]
33
+
34
+ value.is_a?(Proc) ? instance_exec(&value) : value
35
+ end
36
+ let(:configured_description) do
37
+ value = option_options[:description]
38
+
39
+ value.is_a?(Proc) ? instance_exec(&value) : value
40
+ end
41
+ let(:configured_parameter_name) do
42
+ value = option_options[:parameter_name]
43
+
44
+ value.is_a?(Proc) ? instance_exec(&value) : value
45
+ end
46
+ let(:configured_required) do
47
+ value = option_options[:required] ? true : false
48
+
49
+ value.is_a?(Proc) ? instance_exec(&value) : value
50
+ end
51
+ let(:configured_type) do
52
+ value = option_options.fetch(:type, :string)
53
+
54
+ value.is_a?(Proc) ? instance_exec(&value) : value
55
+ end
56
+ let(:configured_variadic) do
57
+ value = option_options.fetch(:variadic, false)
58
+
59
+ value.is_a?(Proc) ? instance_exec(&value) : value
60
+ end
61
+ let(:configured_options) do
62
+ value = option_options.fetch(:options) do
63
+ defined?(options) ? options : {}
64
+ end
65
+
66
+ value.is_a?(Proc) ? instance_exec(&value) : value
67
+ end
68
+ let(:defined_option) { described_class.options[option_name.to_sym] }
69
+
70
+ define_method :set_option do |option, value|
71
+ options = subject.instance_variable_get(:@options)
72
+
73
+ options[option] = value
74
+ end
75
+
76
+ it { expect(described_class.options).to have_key(option_name.to_sym) }
77
+
78
+ describe '#:option_name' do
79
+ if expect_method
80
+ let(:reader_name) { option_name }
81
+
82
+ it { expect(subject).to respond_to(reader_name).with(0).arguments }
83
+
84
+ context 'when the option is not initialized' do
85
+ before(:example) do
86
+ set_option(option_name, configured_default)
87
+ end
88
+
89
+ it 'should return the default value' do
90
+ expect(subject.public_send(reader_name))
91
+ .to be == configured_default
92
+ end
93
+ end
94
+
95
+ context 'when the option is set' do
96
+ let(:value) { 'option value' }
97
+
98
+ before(:example) do
99
+ set_option(option_name, value)
100
+ end
101
+
102
+ it { expect(subject.public_send(reader_name)).to be == value }
103
+ end
104
+ else
105
+ it { expect(subject).not_to respond_to(option_name) }
106
+ end
107
+ end
108
+
109
+ describe '#:option_name?' do
110
+ if expect_predicate
111
+ let(:predicate_name) { "#{option_name}?" }
112
+
113
+ it 'should define the predicate' do
114
+ expect(subject).to respond_to(predicate_name).with(0).arguments
115
+ end
116
+
117
+ context 'when the option is not initialized' do
118
+ let(:expected) do
119
+ next false if configured_default.nil?
120
+ next false if configured_default == false
121
+ next true unless configured_default.respond_to?(:empty?)
122
+
123
+ !configured_default.empty?
124
+ end
125
+
126
+ before(:example) do
127
+ set_option(option_name, configured_default)
128
+ end
129
+
130
+ it 'should return the default value' do
131
+ expect(subject.public_send(predicate_name)).to be == expected
132
+ end
133
+ end
134
+
135
+ context 'when the option is set to false' do
136
+ before(:example) do
137
+ set_option(option_name, false)
138
+ end
139
+
140
+ it { expect(subject.public_send(predicate_name)).to be false }
141
+ end
142
+
143
+ context 'when the option is set to true' do
144
+ before(:example) do
145
+ set_option(option_name, true)
146
+ end
147
+
148
+ it { expect(subject.public_send(predicate_name)).to be true }
149
+ end
150
+
151
+ if option_options[:type] != :boolean
152
+ context 'when the option is set to an Object' do
153
+ before(:example) do
154
+ set_option(option_name, Object.new.freeze)
155
+ end
156
+
157
+ it { expect(subject.public_send(predicate_name)).to be true }
158
+ end
159
+
160
+ context 'when the option is set to an empty value' do
161
+ before(:example) do
162
+ set_option(option_name, '')
163
+ end
164
+
165
+ it { expect(subject.public_send(predicate_name)).to be false }
166
+ end
167
+
168
+ context 'when the option is set to a non-empty value' do
169
+ before(:example) do
170
+ set_option(option_name, 'value')
171
+ end
172
+
173
+ it { expect(subject.public_send(predicate_name)).to be true }
174
+ end
175
+ end
176
+ else
177
+ it { expect(subject).not_to respond_to(:"#{option_name}?") }
178
+ end
179
+ end
180
+
181
+ describe '#aliases' do
182
+ it { expect(defined_option.aliases).to be == configured_aliases }
183
+ end
184
+
185
+ describe '#default' do
186
+ it { expect(defined_option.default).to be == configured_default }
187
+ end
188
+
189
+ describe '#description' do
190
+ it 'should return the option description' do
191
+ expect(defined_option.description).to be == configured_description
192
+ end
193
+ end
194
+
195
+ describe '#parameter_name' do
196
+ it 'should return the option parameter name' do
197
+ expect(defined_option.parameter_name)
198
+ .to be == configured_parameter_name
199
+ end
200
+ end
201
+
202
+ describe '#required?' do
203
+ it { expect(defined_option.required?).to be configured_required }
204
+ end
205
+
206
+ describe '#type' do
207
+ it { expect(defined_option.type).to be configured_type }
208
+ end
209
+
210
+ describe '#variadic?' do
211
+ it { expect(defined_option.variadic?).to be configured_variadic }
212
+ end
213
+ end
214
+ end
215
+
216
+ deferred_examples 'should define --quiet option' do
217
+ include_deferred 'should define option',
218
+ :quiet,
219
+ aliases: %w[q],
220
+ description: 'Silences non-essential console outputs.',
221
+ type: :boolean,
222
+ default: false
223
+ end
224
+
225
+ deferred_examples 'should define --verbose option' do
226
+ include_deferred 'should define option',
227
+ :verbose,
228
+ aliases: %w[v],
229
+ description: 'Enables optional console outputs.',
230
+ type: :boolean,
231
+ default: false
232
+ end
233
+ end
234
+ end
@@ -0,0 +1,451 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec/sleeping_king_studios/deferred/provider'
4
+
5
+ require 'cuprum/cli/rspec/deferred'
6
+
7
+ module Cuprum::Cli::RSpec::Deferred
8
+ # Deferred examples for testing command registries.
9
+ module RegistryExamples
10
+ include RSpec::SleepingKingStudios::Deferred::Provider
11
+
12
+ deferred_context 'when the registry has many commands' do
13
+ let(:commands) do
14
+ {
15
+ 'spec:example' => Spec::ExampleCommand,
16
+ 'spec:other' => Spec::OtherCommand,
17
+ 'spec:scoped' => Spec::Scoped::Command
18
+ }
19
+ end
20
+
21
+ example_class 'Spec::ExampleCommand', Cuprum::Cli::Command
22
+ example_class 'Spec::OtherCommand', Cuprum::Cli::Command
23
+ example_class 'Spec::Scoped::Command', Cuprum::Cli::Command
24
+
25
+ before(:example) do
26
+ Spec::ExampleCommand.description 'An example command.'
27
+ Spec::OtherCommand.description 'Another command.'
28
+ Spec::Scoped::Command.description 'A scoped command.'
29
+
30
+ commands.each do |name, command|
31
+ command.full_name(name)
32
+
33
+ subject.register(command)
34
+ end
35
+ end
36
+ end
37
+
38
+ deferred_examples 'should implement the Registry interface' do
39
+ describe '#[]' do
40
+ it { expect(subject).to respond_to(:[]).with(1).argument }
41
+
42
+ describe 'with nil' do
43
+ let(:error_message) do
44
+ tools.assertions.error_message_for('presence', as: 'full_name')
45
+ end
46
+
47
+ it 'should raise an exception' do
48
+ expect { subject[nil] }
49
+ .to raise_error ArgumentError, error_message
50
+ end
51
+ end
52
+
53
+ describe 'with an Object' do
54
+ let(:error_message) do
55
+ tools.assertions.error_message_for('name', as: 'full_name')
56
+ end
57
+
58
+ it 'should raise an exception' do
59
+ expect { subject[Object.new.freeze] }
60
+ .to raise_error ArgumentError, error_message
61
+ end
62
+ end
63
+
64
+ describe 'with an empty String' do
65
+ let(:error_message) do
66
+ tools.assertions.error_message_for('presence', as: 'full_name')
67
+ end
68
+
69
+ it 'should raise an exception' do
70
+ expect { subject[''] }
71
+ .to raise_error ArgumentError, error_message
72
+ end
73
+ end
74
+
75
+ describe 'with an invalid String' do
76
+ it { expect(subject['invalid:command']).to be nil }
77
+ end
78
+
79
+ wrap_deferred 'when the registry has many commands' do
80
+ describe 'with an invalid String' do
81
+ it { expect(subject['invalid:command']).to be nil }
82
+ end
83
+
84
+ describe 'with a valid String' do
85
+ let(:name) { 'spec:example' }
86
+ let(:expected) { commands[name] }
87
+
88
+ it { expect(subject[name]).to be expected }
89
+ end
90
+ end
91
+ end
92
+
93
+ describe '#commands' do
94
+ include_examples 'should define reader', :commands, {}
95
+
96
+ it { expect(subject.commands).to be_frozen }
97
+
98
+ wrap_deferred 'when the registry has many commands' do
99
+ it { expect(subject.commands).to be == commands }
100
+ end
101
+ end
102
+
103
+ describe '#register' do
104
+ deferred_examples 'should configure the command' do
105
+ context 'when the command is registered' do
106
+ let(:expected_arguments) do
107
+ config.fetch(:arguments, [])
108
+ end
109
+ let(:expected_description) do
110
+ config.fetch(:description, command.description)
111
+ end
112
+ let(:expected_full_description) do
113
+ config.fetch(:full_description) do
114
+ config.fetch(:description, command.full_description)
115
+ end
116
+ end
117
+ let(:expected_full_name) do
118
+ config.fetch(:full_name, command.full_name)
119
+ end
120
+ let(:expected_options) do
121
+ config.fetch(:options, {})
122
+ end
123
+
124
+ before(:example) { registry.register(command, **config) }
125
+
126
+ it { expect(registered).to be_a(Class).and(be < command) }
127
+
128
+ it 'should configure the command argument values' do
129
+ expect(registered.argument_values).to be == expected_arguments
130
+ end
131
+
132
+ it 'should configure the command description' do
133
+ expect(registered.description).to be == expected_description
134
+ end
135
+
136
+ it 'should configure the command full description' do
137
+ expect(registered.full_description)
138
+ .to be == expected_full_description
139
+ end
140
+
141
+ it 'should configure the command full name' do
142
+ expect(registered.full_name).to be == expected_full_name
143
+ end
144
+
145
+ it 'should configure the command option values' do
146
+ expect(registered.option_values).to be == expected_options
147
+ end
148
+ end
149
+ end
150
+
151
+ let(:command) { Spec::CustomCommand }
152
+ let(:config) { {} }
153
+ let(:expected_keywords) do
154
+ %i[
155
+ arguments
156
+ description
157
+ full_description
158
+ full_name
159
+ options
160
+ ]
161
+ end
162
+ let(:registered) do
163
+ name = config.fetch(:full_name, command.full_name)
164
+
165
+ registry.commands[name]
166
+ end
167
+
168
+ example_class 'Spec::CustomCommand', Cuprum::Cli::Command do |klass|
169
+ klass.description 'A custom command.'
170
+ end
171
+
172
+ it 'should define the method' do
173
+ expect(subject)
174
+ .to respond_to(:register)
175
+ .with(1).argument
176
+ .and_keywords(*expected_keywords)
177
+ end
178
+
179
+ it 'should alias the method as #add' do
180
+ expect(subject)
181
+ .to have_aliased_method(:register)
182
+ .as(:add)
183
+ end
184
+
185
+ describe 'with command: nil' do
186
+ let(:error_message) do
187
+ tools.assertions.error_message_for('class', as: 'command')
188
+ end
189
+
190
+ it 'should raise an exception' do
191
+ expect { subject.register(nil) }
192
+ .to raise_error ArgumentError, error_message
193
+ end
194
+ end
195
+
196
+ describe 'with command: an Object' do
197
+ let(:error_message) do
198
+ tools.assertions.error_message_for('class', as: 'command')
199
+ end
200
+
201
+ it 'should raise an exception' do
202
+ expect { subject.register(Object.new.freeze) }
203
+ .to raise_error ArgumentError, error_message
204
+ end
205
+ end
206
+
207
+ describe 'with command: a non-Command class' do
208
+ let(:error_message) do
209
+ tools.assertions.error_message_for(
210
+ 'inherit_from',
211
+ as: 'command',
212
+ expected: Cuprum::Cli::Command
213
+ )
214
+ end
215
+
216
+ it 'should raise an exception' do
217
+ expect { subject.register(Class.new) }
218
+ .to raise_error ArgumentError, error_message
219
+ end
220
+ end
221
+
222
+ describe 'with full_name: an Object' do
223
+ let(:error_message) do
224
+ tools.assertions.error_message_for('name', as: 'full_name')
225
+ end
226
+
227
+ it 'should raise an exception' do
228
+ expect { subject.register(command, full_name: Object.new.freeze) }
229
+ .to raise_error ArgumentError, error_message
230
+ end
231
+ end
232
+
233
+ describe 'with full_name: an empty String' do
234
+ let(:error_message) do
235
+ tools.assertions.error_message_for('presence', as: 'full_name')
236
+ end
237
+
238
+ it 'should raise an exception' do
239
+ expect { subject.register(command, full_name: '') }
240
+ .to raise_error ArgumentError, error_message
241
+ end
242
+ end
243
+
244
+ describe 'with full_name: an invalid String' do
245
+ let(:error_message) do
246
+ 'full_name does not match format category:sub_category:do_something'
247
+ end
248
+
249
+ it 'should raise an exception' do
250
+ expect { subject.register(command, full_name: 'UPPER_CASE') }
251
+ .to raise_error ArgumentError, error_message
252
+ end
253
+ end
254
+
255
+ describe 'with command: an anonymous command class' do
256
+ let(:command) do
257
+ Class.new(Cuprum::Cli::Command) do
258
+ description 'An anonymous command.'
259
+ end
260
+ end
261
+ let(:error_message) do
262
+ tools.assertions.error_message_for('presence', as: 'full_name')
263
+ end
264
+
265
+ it 'should raise an exception' do
266
+ expect { subject.register(command) }
267
+ .to raise_error ArgumentError, error_message
268
+ end
269
+
270
+ describe 'with full_name: value' do
271
+ let(:full_name) { 'custom:scoped:command' }
272
+ let(:config) { super().merge(full_name:) }
273
+
274
+ it 'should register the command' do
275
+ expect { subject.register(command, full_name:) }
276
+ .to change(registry, :commands)
277
+ .to have_key(full_name)
278
+ end
279
+
280
+ include_deferred 'should configure the command'
281
+
282
+ context 'when the registry already defines the command' do
283
+ let(:other_command) do
284
+ Class.new(Cuprum::Cli::Command) do
285
+ description 'Another anonymous command.'
286
+ end
287
+ end
288
+ let(:error_message) do
289
+ "command already registered as #{full_name} - " \
290
+ 'Cuprum::Cli::Command'
291
+ end
292
+
293
+ before(:example) do
294
+ subject.register(other_command, full_name:)
295
+ end
296
+
297
+ it 'should raise an exception' do
298
+ expect { subject.register(command, full_name:) }
299
+ .to raise_error NameError, error_message
300
+ end
301
+ end
302
+ end
303
+ end
304
+
305
+ describe 'with command: a command class' do
306
+ it { expect(subject.register(command)).to be registry }
307
+
308
+ it 'should register the command', :aggregate_failures do
309
+ expect { subject.register(command) }
310
+ .to change(registry, :commands)
311
+ .to have_key(command.full_name)
312
+
313
+ expect(registry.commands[command.full_name]).to be command
314
+ end
315
+
316
+ context 'when the registry already defines the command' do
317
+ let(:other_command) do
318
+ Class.new(Cuprum::Cli::Command) do
319
+ description 'Another anonymous command.'
320
+ end
321
+ end
322
+ let(:error_message) do
323
+ "command already registered as #{command.full_name} - " \
324
+ 'Cuprum::Cli::Command'
325
+ end
326
+
327
+ before(:example) do
328
+ subject.register(other_command, full_name: command.full_name)
329
+ end
330
+
331
+ it 'should raise an exception' do
332
+ expect { subject.register(command) }
333
+ .to raise_error NameError, error_message
334
+ end
335
+ end
336
+
337
+ describe 'with full_name: value' do
338
+ let(:full_name) { 'custom:scoped:command' }
339
+ let(:config) { super().merge(full_name:) }
340
+
341
+ it 'should register the command' do
342
+ expect { subject.register(command, full_name:) }
343
+ .to change(registry, :commands)
344
+ .to have_key(full_name)
345
+ end
346
+
347
+ include_deferred 'should configure the command'
348
+
349
+ context 'when the registry already defines the command' do
350
+ let(:other_command) do
351
+ Class.new(Cuprum::Cli::Command) do
352
+ description 'Another anonymous command.'
353
+ end
354
+ end
355
+ let(:error_message) do
356
+ "command already registered as #{full_name} - " \
357
+ 'Cuprum::Cli::Command'
358
+ end
359
+
360
+ before(:example) do
361
+ subject.register(other_command, full_name:)
362
+ end
363
+
364
+ it 'should raise an exception' do
365
+ expect { subject.register(command, full_name:) }
366
+ .to raise_error NameError, error_message
367
+ end
368
+ end
369
+ end
370
+ end
371
+
372
+ describe 'with arguments: value' do
373
+ let(:arguments) { %w[ichi ni san] }
374
+ let(:config) { super().merge(arguments:) }
375
+
376
+ it { expect(subject.register(command)).to be registry }
377
+
378
+ it 'should register the command' do
379
+ expect { subject.register(command, arguments:) }
380
+ .to change(registry, :commands)
381
+ .to have_key(command.full_name)
382
+ end
383
+
384
+ include_deferred 'should configure the command'
385
+ end
386
+
387
+ describe 'with description: value' do
388
+ let(:description) { 'No one is quite sure what this does.' }
389
+ let(:config) { super().merge(description:) }
390
+
391
+ it 'should register the command' do
392
+ expect { subject.register(command, description:) }
393
+ .to change(registry, :commands)
394
+ .to have_key(command.full_name)
395
+ end
396
+
397
+ include_deferred 'should configure the command'
398
+ end
399
+
400
+ describe 'with full_description: value' do
401
+ let(:full_description) do
402
+ <<~DESC
403
+ No one is quite sure what this does.
404
+
405
+ ...but it sure looks cool!
406
+ DESC
407
+ end
408
+ let(:config) { super().merge(full_description:) }
409
+
410
+ it 'should register the command' do
411
+ expect { subject.register(command, full_description:) }
412
+ .to change(registry, :commands)
413
+ .to have_key(command.full_name)
414
+ end
415
+
416
+ include_deferred 'should configure the command'
417
+ end
418
+
419
+ describe 'with options: value' do
420
+ let(:options) { { option: 'value', other: 'other' } }
421
+ let(:config) { super().merge(options:) }
422
+
423
+ it 'should register the command' do
424
+ expect { subject.register(command, options:) }
425
+ .to change(registry, :commands)
426
+ .to have_key(command.full_name)
427
+ end
428
+
429
+ include_deferred 'should configure the command'
430
+ end
431
+
432
+ describe 'with multiple config options' do
433
+ let(:arguments) { %w[ichi ni san] }
434
+ let(:description) { 'No one is quite sure what this does.' }
435
+ let(:options) { { option: 'value', other: 'other' } }
436
+ let(:config) do
437
+ super().merge(arguments:, description:, options:)
438
+ end
439
+
440
+ it 'should register the command' do
441
+ expect { subject.register(command, **config) }
442
+ .to change(registry, :commands)
443
+ .to have_key(command.full_name)
444
+ end
445
+
446
+ include_deferred 'should configure the command'
447
+ end
448
+ end
449
+ end
450
+ end
451
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/cli/rspec'
4
+
5
+ module Cuprum::Cli::RSpec
6
+ # Namespace for deferred examples used to test Cuprum::Cli functionality.
7
+ module Deferred; end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/cli'
4
+
5
+ module Cuprum::Cli
6
+ # Namespace for tooling to support testing Cuprum::Cli.
7
+ module RSpec; end
8
+ end