command_kit 0.4.0 → 0.5.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 (88) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +2 -0
  3. data/.rubocop.yml +3 -0
  4. data/ChangeLog.md +18 -0
  5. data/LICENSE.txt +1 -1
  6. data/README.md +4 -1
  7. data/command_kit.gemspec +7 -2
  8. data/examples/subcommands/cli/config/get.rb +47 -0
  9. data/examples/subcommands/cli/config/set.rb +44 -0
  10. data/examples/subcommands/cli/config.rb +23 -0
  11. data/examples/subcommands/cli/list.rb +35 -0
  12. data/examples/subcommands/cli/update.rb +47 -0
  13. data/examples/subcommands/cli.rb +55 -0
  14. data/lib/command_kit/completion/install.rb +276 -0
  15. data/lib/command_kit/env/home.rb +1 -1
  16. data/lib/command_kit/env/prefix.rb +41 -0
  17. data/lib/command_kit/env/shell.rb +58 -0
  18. data/lib/command_kit/inflector.rb +1 -1
  19. data/lib/command_kit/options/parser.rb +1 -1
  20. data/lib/command_kit/os/linux.rb +1 -1
  21. data/lib/command_kit/os.rb +1 -1
  22. data/lib/command_kit/printing/tables/table_formatter.rb +2 -2
  23. data/lib/command_kit/version.rb +1 -1
  24. data/lib/command_kit/xdg.rb +1 -1
  25. metadata +12 -66
  26. data/spec/arguments/argument_spec.rb +0 -133
  27. data/spec/arguments/argument_value_spec.rb +0 -66
  28. data/spec/arguments_spec.rb +0 -279
  29. data/spec/bug_report_spec.rb +0 -266
  30. data/spec/colors_spec.rb +0 -771
  31. data/spec/command_kit_spec.rb +0 -8
  32. data/spec/command_name_spec.rb +0 -130
  33. data/spec/command_spec.rb +0 -123
  34. data/spec/commands/auto_load/subcommand_spec.rb +0 -82
  35. data/spec/commands/auto_load_spec.rb +0 -159
  36. data/spec/commands/auto_require_spec.rb +0 -142
  37. data/spec/commands/fixtures/test_auto_load/cli/commands/test1.rb +0 -10
  38. data/spec/commands/fixtures/test_auto_load/cli/commands/test2.rb +0 -10
  39. data/spec/commands/fixtures/test_auto_require/lib/test_auto_require/cli/commands/test1.rb +0 -10
  40. data/spec/commands/help_spec.rb +0 -66
  41. data/spec/commands/parent_command_spec.rb +0 -40
  42. data/spec/commands/subcommand_spec.rb +0 -99
  43. data/spec/commands_spec.rb +0 -839
  44. data/spec/description_spec.rb +0 -179
  45. data/spec/edit_spec.rb +0 -72
  46. data/spec/env/home_spec.rb +0 -46
  47. data/spec/env/path_spec.rb +0 -84
  48. data/spec/env_spec.rb +0 -123
  49. data/spec/examples_spec.rb +0 -211
  50. data/spec/exception_handler_spec.rb +0 -103
  51. data/spec/file_utils_spec.rb +0 -59
  52. data/spec/fixtures/template.erb +0 -5
  53. data/spec/help/man_spec.rb +0 -345
  54. data/spec/help_spec.rb +0 -94
  55. data/spec/inflector_spec.rb +0 -166
  56. data/spec/interactive_spec.rb +0 -415
  57. data/spec/main_spec.rb +0 -179
  58. data/spec/man_spec.rb +0 -46
  59. data/spec/open_app_spec.rb +0 -85
  60. data/spec/options/option_spec.rb +0 -343
  61. data/spec/options/option_value_spec.rb +0 -171
  62. data/spec/options/parser_spec.rb +0 -255
  63. data/spec/options/quiet_spec.rb +0 -51
  64. data/spec/options/verbose_spec.rb +0 -51
  65. data/spec/options/version_spec.rb +0 -146
  66. data/spec/options_spec.rb +0 -465
  67. data/spec/os/linux_spec.rb +0 -164
  68. data/spec/os_spec.rb +0 -233
  69. data/spec/package_manager_spec.rb +0 -806
  70. data/spec/pager_spec.rb +0 -217
  71. data/spec/printing/fields_spec.rb +0 -167
  72. data/spec/printing/indent_spec.rb +0 -132
  73. data/spec/printing/lists_spec.rb +0 -99
  74. data/spec/printing/tables/border_style.rb +0 -43
  75. data/spec/printing/tables/cell_builer_spec.rb +0 -135
  76. data/spec/printing/tables/row_builder_spec.rb +0 -165
  77. data/spec/printing/tables/style_spec.rb +0 -377
  78. data/spec/printing/tables/table_builder_spec.rb +0 -252
  79. data/spec/printing/tables/table_formatter_spec.rb +0 -1180
  80. data/spec/printing/tables_spec.rb +0 -1069
  81. data/spec/printing_spec.rb +0 -106
  82. data/spec/program_name_spec.rb +0 -70
  83. data/spec/spec_helper.rb +0 -3
  84. data/spec/stdio_spec.rb +0 -264
  85. data/spec/sudo_spec.rb +0 -51
  86. data/spec/terminal_spec.rb +0 -231
  87. data/spec/usage_spec.rb +0 -237
  88. data/spec/xdg_spec.rb +0 -191
@@ -1,839 +0,0 @@
1
- require 'spec_helper'
2
- require 'command_kit/commands'
3
-
4
- describe CommandKit::Commands do
5
- module TestCommands
6
- class TestEmptyCommands
7
-
8
- include CommandKit::Commands
9
-
10
- end
11
-
12
- class TestCommands
13
-
14
- include CommandKit::Commands
15
-
16
- class Test1 < CommandKit::Command
17
- end
18
-
19
- class Test2 < CommandKit::Command
20
- end
21
-
22
- command Test1
23
- command Test2
24
-
25
- end
26
-
27
- class TestCommandsWithAliases
28
-
29
- include CommandKit::Commands
30
-
31
- class Test1 < CommandKit::Command
32
- end
33
-
34
- class Test2 < CommandKit::Command
35
- end
36
-
37
- command Test1, aliases: %w[t1]
38
- command Test2, aliases: %w[t2]
39
-
40
- end
41
-
42
- class TestCommandsWithExplicitNames
43
-
44
- include CommandKit::Commands
45
-
46
- class Test1 < CommandKit::Command
47
- end
48
-
49
- class Test2 < CommandKit::Command
50
- end
51
-
52
- command 'command-name-1', Test1
53
- command 'command-name-2', Test2
54
-
55
- end
56
-
57
- class TestCommandsWithExplicitNamesAndAliases
58
-
59
- include CommandKit::Commands
60
-
61
- class Test1 < CommandKit::Command
62
- end
63
-
64
- class Test2 < CommandKit::Command
65
- end
66
-
67
- command 'command-name-1', Test1, aliases: %w[t1]
68
- command 'command-name-2', Test2, aliases: %w[t2]
69
-
70
- end
71
-
72
- class TestCommandsWithExplicitSummaries
73
-
74
- include CommandKit::Commands
75
-
76
- class Test1 < CommandKit::Command
77
- end
78
-
79
- class Test2 < CommandKit::Command
80
- end
81
-
82
- command Test1, summary: 'Explicit summary 1'
83
- command Test2, summary: 'Explicit summary 2'
84
-
85
- end
86
-
87
- class TestCommandsWithCustomExitStatus
88
-
89
- include CommandKit::Commands
90
-
91
- class Test < CommandKit::Command
92
-
93
- def run(*argv)
94
- exit(2)
95
- end
96
-
97
- end
98
-
99
- command Test
100
-
101
- end
102
-
103
- class TestCommandsWithGlobalOptions
104
-
105
- include CommandKit::Commands
106
-
107
- class Test1 < CommandKit::Command
108
- end
109
-
110
- class Test2 < CommandKit::Command
111
- end
112
-
113
- option :foo, short: '-f',
114
- desc: "Global --foo option"
115
-
116
- option :bar, short: '-b',
117
- value: {
118
- required: true,
119
- type: String,
120
- usage: 'BAR'
121
- },
122
- desc: "Global --bar option"
123
-
124
- command Test1
125
- command Test2
126
-
127
- end
128
-
129
- class TestCommandsWithCommandArguments
130
-
131
- include CommandKit::Commands
132
-
133
- class Test1 < CommandKit::Command
134
- argument :arg1, required: false,
135
- desc: 'Argument 1'
136
-
137
- argument :arg2, required: false,
138
- desc: 'Argument 2'
139
- end
140
-
141
- class Test2 < CommandKit::Command
142
- argument :arg1, required: false,
143
- desc: 'Argument 1'
144
-
145
- argument :arg2, required: false,
146
- desc: 'Argument 2'
147
- end
148
-
149
- command Test1
150
- command Test2
151
-
152
- end
153
-
154
- end
155
-
156
- let(:command_class) { TestCommands::TestCommands }
157
-
158
- describe ".commands" do
159
- subject { command_class }
160
-
161
- it "must return a Hash" do
162
- expect(subject.commands).to be_kind_of(Hash)
163
- end
164
-
165
- it "must provide a default 'help' command" do
166
- expect(subject.commands['help']).to_not be_nil
167
- expect(subject.commands['help'].command).to eq(CommandKit::Commands::Help)
168
- end
169
-
170
- context "when additional commands are defined in a superclass" do
171
- module TestCommands
172
- class TestInheritedCommands < TestCommands
173
-
174
- class Test3 < CommandKit::Command
175
-
176
- def run
177
- puts 'test command three'
178
- end
179
-
180
- end
181
-
182
- command :test3, Test3
183
-
184
- end
185
- end
186
-
187
- let(:command_superclass) { TestCommands::TestCommands }
188
- let(:command_class) { TestCommands::TestInheritedCommands }
189
-
190
- it "must inherit the superclass'es commands" do
191
- expect(subject.commands['test1']).to eq(command_superclass.commands['test1'])
192
- expect(subject.commands['test2']).to eq(command_superclass.commands['test2'])
193
- end
194
-
195
- it "must allow defining additional commands in the subclass" do
196
- expect(subject.commands['test3']).to_not be_nil
197
- expect(subject.commands['test3'].command).to eq(command_class::Test3)
198
- end
199
-
200
- it "must not change the superclass'es commands" do
201
- expect(command_superclass.commands['test3']).to be(nil)
202
- end
203
- end
204
- end
205
-
206
- describe ".command_aliases" do
207
- subject { command_class }
208
-
209
- it "must return an empty Hash by default" do
210
- expect(subject.command_aliases).to eq({})
211
- end
212
-
213
- context "when commands have aliases" do
214
- let(:command_class) { TestCommands::TestCommandsWithAliases }
215
-
216
- it "must contain the mapping of aliases to command names" do
217
- expect(subject.command_aliases).to eq({
218
- 't1' => 'test1',
219
- 't2' => 'test2'
220
- })
221
- end
222
- end
223
-
224
- context "when additional command aliases are defined in a superclass" do
225
- module TestCommands
226
- class TestInheritedCommandsWithAliases < TestCommandsWithAliases
227
-
228
- class Test3 < CommandKit::Command
229
-
230
- def run
231
- puts 'test command three'
232
- end
233
-
234
- end
235
-
236
- command :test3, Test3, aliases: %w[t3]
237
-
238
- end
239
- end
240
-
241
- let(:command_superclass) { TestCommands::TestCommandsWithAliases }
242
- let(:command_class) { TestCommands::TestInheritedCommandsWithAliases }
243
-
244
- it "must inherit the superclass'es command aliases" do
245
- expect(subject.command_aliases['t1']).to eq(command_superclass.command_aliases['t1'])
246
- expect(subject.command_aliases['t2']).to eq(command_superclass.command_aliases['t2'])
247
- end
248
-
249
- it "must allow defining additional command aliases in the subclass" do
250
- expect(subject.command_aliases['t3']).to eq('test3')
251
- end
252
-
253
- it "must not change the superclass'es command aliases" do
254
- expect(command_superclass.command_aliases['test3']).to be(nil)
255
- end
256
- end
257
- end
258
-
259
- describe ".command" do
260
- subject { command_class }
261
-
262
- context "when given only a command class" do
263
- module TestCommands
264
- class TestCommandWithOnlyACommandClass
265
- include CommandKit::Commands
266
-
267
- class Test < CommandKit::Command
268
- end
269
-
270
- command Test
271
- end
272
- end
273
-
274
- let(:command_class) { TestCommands::TestCommandWithOnlyACommandClass }
275
-
276
- it "must default the command name to the command class'es command_name" do
277
- expect(subject.commands['test']).to_not be_nil
278
- expect(subject.commands['test'].command).to eq(command_class::Test)
279
- end
280
-
281
- context "and aliases:" do
282
- let(:command_class) { TestCommands::TestCommandsWithAliases }
283
-
284
- it "must populate aliases with the aliases and the command names" do
285
- expect(subject.command_aliases['t1']).to eq(command_class::Test1.command_name)
286
- expect(subject.command_aliases['t2']).to eq(command_class::Test2.command_name)
287
- end
288
- end
289
- end
290
-
291
- context "when given a command name and a command class" do
292
- let(:command_class) { TestCommands::TestCommandsWithExplicitNames }
293
-
294
- it "must not add an entry for the command class'es command_name" do
295
- expect(subject.commands['test1']).to be_nil
296
- expect(subject.commands['test2']).to be_nil
297
- end
298
-
299
- it "must add an entry for the command name" do
300
- expect(subject.commands['command-name-1']).to_not be_nil
301
- expect(subject.commands['command-name-1'].command).to eq(command_class::Test1)
302
-
303
- expect(subject.commands['command-name-2']).to_not be_nil
304
- expect(subject.commands['command-name-2'].command).to eq(command_class::Test2)
305
- end
306
-
307
- context "and aliases:" do
308
- let(:command_class) { TestCommands::TestCommandsWithExplicitNamesAndAliases }
309
-
310
- it "must populate aliases with the aliases and the explicit command names" do
311
- expect(subject.command_aliases['t1']).to eq('command-name-1')
312
- expect(subject.command_aliases['t2']).to eq('command-name-2')
313
- end
314
- end
315
-
316
- context "when the command name is a Symbol" do
317
- module TestCommands
318
- class TestCommandWithASymbolCommandName
319
- include CommandKit::Commands
320
-
321
- class Test < CommandKit::Command
322
- end
323
-
324
- command :test_sym, Test
325
- end
326
- end
327
-
328
- let(:command_class) { TestCommands::TestCommandWithASymbolCommandName }
329
-
330
- it "must not add an entry for the command class'es command_name" do
331
- expect(subject.commands['test']).to be_nil
332
- end
333
-
334
- it "must not add entries with Symbol keys" do
335
- expect(subject.commands.keys).to all(be_kind_of(String))
336
- end
337
-
338
- it "must convert the command name to a String" do
339
- expect(subject.commands['test_sym']).to_not be_nil
340
- expect(subject.commands['test_sym'].command).to eq(command_class::Test)
341
- end
342
- end
343
- end
344
-
345
- context "when given an explicit summary: keyword argument" do
346
- let(:command_class) { TestCommands::TestCommandsWithExplicitSummaries }
347
-
348
- it "must initialize the Subcommand#summary" do
349
- expect(subject.commands['test1'].summary).to eq('Explicit summary 1')
350
- expect(subject.commands['test2'].summary).to eq('Explicit summary 2')
351
- end
352
- end
353
- end
354
-
355
- describe ".get_command" do
356
- subject { command_class }
357
-
358
- context "when given a command name" do
359
- let(:command_class) { TestCommands::TestCommands }
360
-
361
- it "must return the command's class" do
362
- expect(subject.get_command('test1')).to eq(command_class::Test1)
363
- expect(subject.get_command('test2')).to eq(command_class::Test2)
364
- end
365
- end
366
-
367
- context "when given a command's alias name" do
368
- let(:command_class) { TestCommands::TestCommandsWithAliases }
369
-
370
- it "must return the command's class associated with the alias" do
371
- expect(subject.get_command('t1')).to eq(command_class::Test1)
372
- expect(subject.get_command('t2')).to eq(command_class::Test2)
373
- end
374
- end
375
-
376
- context "when given an unknown command name" do
377
- it "must return nil" do
378
- expect(subject.get_command('foo')).to be(nil)
379
- end
380
- end
381
- end
382
-
383
- subject { command_class.new }
384
-
385
- describe "#command" do
386
- module TestCommands
387
- class TestSubCommandInitialization
388
- include CommandKit::Commands
389
-
390
- class Test < CommandKit::Command
391
- end
392
-
393
- command 'test', Test
394
- end
395
- end
396
-
397
- let(:command_class) { TestCommands::TestSubCommandInitialization }
398
- let(:subcommand_class) { command_class::Test }
399
-
400
- context "when given a valid command name" do
401
- it "must lookup the command and initialize it" do
402
- expect(subject.command(subcommand_class.command_name)).to be_kind_of(subcommand_class)
403
- end
404
- end
405
-
406
- context "when given a command alias" do
407
- let(:command_class) { TestCommands::TestCommandsWithAliases }
408
-
409
- it "must lookup the command and initialize it" do
410
- expect(subject.command('t1')).to be_kind_of(command_class::Test1)
411
- expect(subject.command('t2')).to be_kind_of(command_class::Test2)
412
- end
413
- end
414
-
415
- context "when given an unknown command name" do
416
- it "must return nil" do
417
- expect(subject.command('foo')).to be_nil
418
- end
419
- end
420
-
421
- context "when the command includes CommandKit::Commands::ParentCommand" do
422
- module TestCommands
423
- class TestSubCommandInitializationWithParentCommand
424
- include CommandKit::Commands
425
-
426
- class Test
427
- include CommandKit::Commands::ParentCommand
428
- end
429
-
430
- command 'test', Test
431
- end
432
- end
433
-
434
- let(:command_class) { TestCommands::TestSubCommandInitializationWithParentCommand }
435
- let(:subcommand_class) { command_class::Test }
436
-
437
- it "must initialize the sub-command with a parent_command value" do
438
- subcommand = subject.command('test')
439
-
440
- expect(subcommand.parent_command).to be(subject)
441
- end
442
- end
443
-
444
- context "when the command includes CommandKit::CommandName" do
445
- module TestCommands
446
- class TestSubCommandInitializationWithCommandName
447
- include CommandKit::Commands
448
-
449
- class Test
450
- include CommandKit::CommandName
451
- end
452
-
453
- command 'test', Test
454
- end
455
- end
456
-
457
- let(:command_class) { TestCommands::TestSubCommandInitializationWithCommandName }
458
- let(:subcommand_class) { command_class::Test }
459
- let(:expected_subcommand_name) do
460
- "#{command_class.command_name} #{subcommand_class.command_name}"
461
- end
462
-
463
- it "must initialize the sub-command with the command and subcommand name" do
464
- subcommand = subject.command('test')
465
-
466
- expect(subcommand.command_name).to eq(expected_subcommand_name)
467
- end
468
- end
469
-
470
- context "when the command includes CommandKit::Stdio" do
471
- module TestCommands
472
- class TestSubCommandInitializationWithStdio
473
- include CommandKit::Commands
474
-
475
- class Test
476
- include CommandKit::Stdio
477
- end
478
-
479
- command 'test', Test
480
- end
481
- end
482
-
483
- let(:command_class) { TestCommands::TestSubCommandInitializationWithStdio }
484
- let(:subcommand_class) { command_class::Test }
485
-
486
- let(:stdin) { StringIO.new }
487
- let(:stdout) { StringIO.new }
488
- let(:stderr) { StringIO.new }
489
-
490
- subject do
491
- command_class.new(stdin: stdin, stdout: stdout, stderr: stderr)
492
- end
493
-
494
- it "must initialize the sub-command with the command's #stdin, #stdout, #stderr" do
495
- subcommand = subject.command('test')
496
-
497
- expect(subcommand.stdin).to be(stdin)
498
- expect(subcommand.stdout).to be(stdout)
499
- expect(subcommand.stderr).to be(stderr)
500
- end
501
- end
502
-
503
- context "when the command includes CommandKit::Env" do
504
- module TestCommands
505
- class TestSubCommandInitializationWithEnv
506
- include CommandKit::Commands
507
-
508
- class Test
509
- include CommandKit::Env
510
- end
511
-
512
- command 'test', Test
513
- end
514
- end
515
-
516
- let(:command_class) { TestCommands::TestSubCommandInitializationWithEnv }
517
- let(:subcommand_class) { command_class::Test }
518
-
519
- let(:env) { {'FOO' => 'bar'} }
520
- subject { command_class.new(env: env) }
521
-
522
- it "must initialize the sub-command with a copy of the command's #env" do
523
- subcommand = subject.command('test')
524
-
525
- expect(subcommand.env).to eq(env)
526
- expect(subcommand.env).to_not be(env)
527
- end
528
- end
529
-
530
- context "when the command includes CommandKit::Options" do
531
- module TestCommands
532
- class TestSubCommandInitializationWithOptions
533
- include CommandKit::Commands
534
-
535
- class Test
536
- include CommandKit::Options
537
- end
538
-
539
- command 'test', Test
540
- end
541
- end
542
-
543
- let(:command_class) { TestCommands::TestSubCommandInitializationWithOptions }
544
- let(:subcommand_class) { command_class::Test }
545
-
546
- let(:options) { {foo: 'bar'} }
547
- subject { command_class.new(options: options) }
548
-
549
- it "must initialize the sub-command with a copy of the command's #options Hash" do
550
- subcommand = subject.command('test')
551
-
552
- expect(subcommand.options).to eq(options)
553
- expect(subcommand.options).to_not be(options)
554
- end
555
- end
556
- end
557
-
558
- describe "#invoke" do
559
- context "when given a valid command name" do
560
- let(:command_name) { 'test2' }
561
- let(:argv) { %w[--opt arg1 arg2] }
562
-
563
- it "must call the command's #main method with the given argv" do
564
- expect_any_instance_of(command_class::Test2).to receive(:main).with(argv)
565
-
566
- subject.invoke(command_name,*argv)
567
- end
568
-
569
- context "when the command returns a custom exit code" do
570
- let(:command_class) { TestCommands::TestCommandsWithCustomExitStatus }
571
-
572
- it "must return the exit code" do
573
- expect(subject.invoke('test')).to eq(2)
574
- end
575
- end
576
- end
577
-
578
- context "when given an unknown command name" do
579
- let(:command_name) { 'xxx' }
580
- let(:argv) { %w[--opt arg1 arg2] }
581
-
582
- it "must call #on_unknown_command with the given name and argv" do
583
- expect(subject).to receive(:on_unknown_command).with(command_name,argv)
584
-
585
- subject.invoke(command_name,*argv)
586
- end
587
- end
588
- end
589
-
590
- let(:unknown_command) { 'xxx' }
591
-
592
- describe "#command_not_found" do
593
- it "must print an error message to stderr and exit with 1" do
594
- expect(subject).to receive(:exit).with(1)
595
-
596
- expect { subject.command_not_found(unknown_command) }.to output(
597
- "#{subject.command_name}: '#{unknown_command}' is not a #{subject.command_name} command. See `#{subject.command_name} help`" + $/
598
- ).to_stderr
599
- end
600
- end
601
-
602
- describe "#on_unknown_command" do
603
- it "must call #command_not_found with the given command name by default" do
604
- expect(subject).to receive(:command_not_found).with(unknown_command)
605
-
606
- subject.on_unknown_command(unknown_command)
607
- end
608
- end
609
-
610
- describe "#option_parser" do
611
- let(:command_name) { 'test1' }
612
- let(:command_argv) { %w[foo bar baz] }
613
- let(:argv) { [command_name, *command_argv] }
614
-
615
- it "must stop before the first non-option argument" do
616
- expect(subject.option_parser.parse(argv)).to eq(
617
- [command_name, *command_argv]
618
- )
619
- end
620
-
621
- context "when an unknown command name is given" do
622
- let(:command_argv) { %w[bar baz] }
623
- let(:argv) { ['foo', command_name, *command_argv] }
624
-
625
- it "must stop before the first non-option argument" do
626
- expect(subject.option_parser.parse(argv)).to eq(argv)
627
- end
628
- end
629
-
630
- context "when additional global options are defined" do
631
- let(:command_class) { TestCommands::TestCommandsWithGlobalOptions }
632
- let(:bar) { '2' }
633
- let(:argv) do
634
- ['--foo', '--bar', bar.to_s, command_name, *command_argv]
635
- end
636
-
637
- it "must parse the global options, but stop before the first non-option associated argument" do
638
- expect(subject.option_parser.parse(argv)).to eq(
639
- [command_name, *command_argv]
640
- )
641
-
642
- expect(subject.options[:foo]).to be(true)
643
- expect(subject.options[:bar]).to eq(bar)
644
- end
645
- end
646
- end
647
-
648
- describe "#run" do
649
- context "when a command name is the first argument" do
650
- let(:command) { 'test1' }
651
- let(:exit_status) { 2 }
652
-
653
- it "must invoke the command and exit with it's status" do
654
- expect(subject).to receive(:invoke).with(command).and_return(exit_status)
655
- expect(subject).to receive(:exit).with(exit_status)
656
-
657
- subject.run(command)
658
- end
659
-
660
- context "when additional argv is given after the command name" do
661
- let(:argv) { %w[--opt arg1 arg2] }
662
-
663
- it "must pass the additional argv to the command" do
664
- expect(subject).to receive(:invoke).with(command,*argv).and_return(exit_status)
665
- expect(subject).to receive(:exit).with(exit_status)
666
-
667
- subject.run(command,*argv)
668
- end
669
- end
670
- end
671
-
672
- context "when given no arguments" do
673
- let(:exit_status) { 1 }
674
-
675
- it "must default to calling #help and exit with 1" do
676
- expect(subject).to receive(:help)
677
- expect(subject).to receive(:exit).with(exit_status)
678
-
679
- subject.run()
680
- end
681
- end
682
- end
683
-
684
- describe "#main" do
685
- let(:command_class) { TestCommands::TestCommandsWithCommandArguments }
686
-
687
- context "when a command name is the first argument" do
688
- let(:command) { 'test1' }
689
- let(:argv) { [command] }
690
-
691
- it "must return 0" do
692
- expect(subject.main(argv)).to eq(0)
693
- end
694
- end
695
-
696
- context "when given additional command arguments" do
697
- let(:argv) { %w[test1 arg1 arg2] }
698
-
699
- it "must pass them to the command" do
700
- expect(subject.main(argv)).to eq(0)
701
- end
702
- end
703
-
704
- context "when given no arguments" do
705
- let(:exit_status) { 1 }
706
- let(:argv) { %w[] }
707
-
708
- it "must call #help and return 1" do
709
- expect(subject).to receive(:help)
710
-
711
- expect(subject.main(argv)).to eq(exit_status)
712
- end
713
- end
714
- end
715
-
716
- describe "#help_commands" do
717
- it "must print usage and the list of available commands" do
718
- expect { subject.help_commands }.to output(
719
- [
720
- "",
721
- "Commands:",
722
- " help",
723
- " test1",
724
- " test2",
725
- ""
726
- ].join($/)
727
- ).to_stdout
728
- end
729
-
730
- context "when the commands have custom names" do
731
- let(:command_class) { TestCommands::TestCommandsWithExplicitNames }
732
-
733
- it "must print the command names, not the command class'es #command_name" do
734
- expect { subject.help_commands }.to output(
735
- [
736
- "",
737
- "Commands:",
738
- " command-name-1",
739
- " command-name-2",
740
- " help",
741
- ""
742
- ].join($/)
743
- ).to_stdout
744
- end
745
- end
746
-
747
- context "when the commands have summaries" do
748
- let(:command_class) { TestCommands::TestCommandsWithExplicitSummaries }
749
-
750
- it "must print the command names and their summaries" do
751
- expect { subject.help_commands }.to output(
752
- [
753
- "",
754
- "Commands:",
755
- " help",
756
- " test1\t#{command_class.commands['test1'].summary}",
757
- " test2\t#{command_class.commands['test2'].summary}",
758
- ""
759
- ].join($/)
760
- ).to_stdout
761
- end
762
- end
763
- end
764
-
765
- describe "#help" do
766
- it "must print the list of available commands after other help output" do
767
- expect { subject.help }.to output(
768
- [
769
- "Usage: #{subject.command_name} [options] [COMMAND [ARGS...]]",
770
- "",
771
- "Options:",
772
- " -h, --help Print help information",
773
- "",
774
- "Arguments:",
775
- " [COMMAND] The command name to run",
776
- " [ARGS ...] Additional arguments for the command",
777
- "",
778
- "Commands:",
779
- " help",
780
- " test1",
781
- " test2",
782
- ""
783
- ].join($/)
784
- ).to_stdout
785
- end
786
-
787
- context "when the command has command alises" do
788
- let(:command_class) { TestCommands::TestCommandsWithAliases }
789
-
790
- it "must print the command names, along with their command aliases" do
791
- expect { subject.help }.to output(
792
- [
793
- "Usage: #{subject.command_name} [options] [COMMAND [ARGS...]]",
794
- "",
795
- "Options:",
796
- " -h, --help Print help information",
797
- "",
798
- "Arguments:",
799
- " [COMMAND] The command name to run",
800
- " [ARGS ...] Additional arguments for the command",
801
- "",
802
- "Commands:",
803
- " help",
804
- " test1, t1",
805
- " test2, t2",
806
- ""
807
- ].join($/)
808
- ).to_stdout
809
- end
810
- end
811
-
812
- context "when the command defines additional global options" do
813
- let(:command_class) { TestCommands::TestCommandsWithGlobalOptions }
814
-
815
- it "must print any global options" do
816
- expect { subject.help }.to output(
817
- [
818
- "Usage: #{subject.command_name} [options] [COMMAND [ARGS...]]",
819
- "",
820
- "Options:",
821
- " -f, --foo Global --foo option",
822
- " -b, --bar BAR Global --bar option",
823
- " -h, --help Print help information",
824
- "",
825
- "Arguments:",
826
- " [COMMAND] The command name to run",
827
- " [ARGS ...] Additional arguments for the command",
828
- "",
829
- "Commands:",
830
- " help",
831
- " test1",
832
- " test2",
833
- ""
834
- ].join($/)
835
- ).to_stdout
836
- end
837
- end
838
- end
839
- end