command_mapper 0.1.0 → 0.2.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.
data/spec/commnad_spec.rb CHANGED
@@ -7,10 +7,17 @@ describe CommandMapper::Command do
7
7
  command 'foo'
8
8
  end
9
9
 
10
+ class InheritedCommandName < WithCommandName
11
+ end
12
+
10
13
  class NoCommandName < CommandMapper::Command
11
14
  end
12
15
  end
13
16
 
17
+ it "must include Types" do
18
+ expect(command_class).to include(CommandMapper::Types)
19
+ end
20
+
14
21
  describe ".command_name" do
15
22
  subject { command_class }
16
23
 
@@ -47,6 +54,14 @@ describe CommandMapper::Command do
47
54
  expect(subject.command_name).to eq('foo')
48
55
  end
49
56
  end
57
+
58
+ context "when the command class inherits from another command class" do
59
+ let(:command_class) { TestCommand::InheritedCommandName }
60
+
61
+ it "must check the superclass" do
62
+ expect(subject.command_name).to eq("foo")
63
+ end
64
+ end
50
65
  end
51
66
 
52
67
  module TestCommand
@@ -54,6 +69,20 @@ describe CommandMapper::Command do
54
69
  end
55
70
  end
56
71
 
72
+ module TestCommand
73
+ class BaseClassWithOptions < CommandMapper::Command
74
+ option "--foo"
75
+ option "--bar"
76
+ end
77
+
78
+ class InheritedOptions < BaseClassWithOptions
79
+ end
80
+
81
+ class InheritsAndDefinesOptions < BaseClassWithOptions
82
+ option "--baz"
83
+ end
84
+ end
85
+
57
86
  describe ".options" do
58
87
  subject { command_class }
59
88
 
@@ -64,16 +93,6 @@ describe CommandMapper::Command do
64
93
  end
65
94
 
66
95
  context "and when the command inherits from another command class" do
67
- module TestCommand
68
- class BaseClassWithOptions < CommandMapper::Command
69
- option "--foo"
70
- option "--bar"
71
- end
72
-
73
- class InheritedOptions < BaseClassWithOptions
74
- end
75
- end
76
-
77
96
  let(:command_class) { TestCommand::InheritedOptions }
78
97
  let(:command_superclass) { TestCommand::BaseClassWithOptions }
79
98
 
@@ -82,12 +101,6 @@ describe CommandMapper::Command do
82
101
  end
83
102
 
84
103
  context "and when the class defines options of it's own" do
85
- module TestCommand
86
- class InheritsAndDefinesOptions < BaseClassWithOptions
87
- option "--baz"
88
- end
89
- end
90
-
91
104
  let(:command_class) { TestCommand::InheritsAndDefinesOptions }
92
105
 
93
106
  it "must copy the options defined in the superclass" do
@@ -105,6 +118,38 @@ describe CommandMapper::Command do
105
118
  end
106
119
  end
107
120
 
121
+ describe ".has_option?" do
122
+ subject { command_class }
123
+
124
+ let(:name) { :bar }
125
+
126
+ context "when the command has no defined options" do
127
+ let(:command_class) { TestCommand::EmptyCommand }
128
+
129
+ it "must return false" do
130
+ expect(subject.has_option?(name)).to be(false)
131
+ end
132
+ end
133
+
134
+ context "when the command does have defined options" do
135
+ let(:command_class) { TestCommand::BaseClassWithOptions }
136
+
137
+ context "and has the option with the given name" do
138
+ it "must return true" do
139
+ expect(subject.has_option?(name)).to be(true)
140
+ end
141
+ end
142
+
143
+ context "but does not have the option with the given name" do
144
+ let(:name) { :xxx }
145
+
146
+ it "must return false" do
147
+ expect(subject.has_option?(name)).to be(false)
148
+ end
149
+ end
150
+ end
151
+ end
152
+
108
153
  describe ".option" do
109
154
  module TestCommand
110
155
  class DefinesItsOwnOptions < CommandMapper::Command
@@ -227,6 +272,55 @@ describe CommandMapper::Command do
227
272
  }.to raise_error(ArgumentError,"option #{flag.inspect} maps to method name ##{name} and cannot override the internal method with same name: ##{name}")
228
273
  end
229
274
  end
275
+
276
+ context "when the option name conflicts with another defined argument" do
277
+ let(:command_class) do
278
+ Class.new(described_class) do
279
+ argument :foo
280
+ end
281
+ end
282
+
283
+ let(:flag) { "--foo" }
284
+ let(:name) { :foo }
285
+
286
+ it do
287
+ expect {
288
+ subject.option(flag)
289
+ }.to raise_error(ArgumentError,"option #{flag.inspect} with name #{name.inspect} conflicts with another argument with the same name")
290
+ end
291
+ end
292
+
293
+ context "when the option name conflicts with another defined subcommand" do
294
+ let(:command_class) do
295
+ Class.new(described_class) do
296
+ subcommand 'foo' do
297
+ end
298
+ end
299
+ end
300
+
301
+ let(:flag) { "--foo" }
302
+ let(:name) { :foo }
303
+
304
+ it do
305
+ expect {
306
+ subject.option(flag)
307
+ }.to raise_error(ArgumentError,"option #{flag.inspect} with name #{name.inspect} conflicts with another subcommand with the same name")
308
+ end
309
+ end
310
+ end
311
+
312
+ module TestCommand
313
+ class BaseClassWithArguments < CommandMapper::Command
314
+ argument :foo
315
+ argument :bar
316
+ end
317
+
318
+ class InheritedArguments < BaseClassWithArguments
319
+ end
320
+
321
+ class InheritsAndDefinesArguments < BaseClassWithArguments
322
+ argument :baz
323
+ end
230
324
  end
231
325
 
232
326
  describe ".arguments" do
@@ -239,31 +333,15 @@ describe CommandMapper::Command do
239
333
  end
240
334
 
241
335
  context "when the comand does have defined arguments" do
242
- module TestCommand
243
- class BaseClassWithOptions < CommandMapper::Command
244
- argument :foo
245
- argument :bar
246
- end
247
-
248
- class InheritedOptions < BaseClassWithOptions
249
- end
250
- end
251
-
252
- let(:command_class) { TestCommand::InheritedOptions }
253
- let(:command_superclass) { TestCommand::BaseClassWithOptions }
336
+ let(:command_class) { TestCommand::InheritedArguments }
337
+ let(:command_superclass) { TestCommand::BaseClassWithArguments }
254
338
 
255
339
  it "must copy the arguments defined in the superclass" do
256
340
  expect(subject.arguments).to eq(command_superclass.arguments)
257
341
  end
258
342
 
259
343
  context "and when the class defines arguments of it's own" do
260
- module TestCommand
261
- class InheritsAndDefinesOptions < BaseClassWithOptions
262
- argument :baz
263
- end
264
- end
265
-
266
- let(:command_class) { TestCommand::InheritsAndDefinesOptions }
344
+ let(:command_class) { TestCommand::InheritsAndDefinesArguments }
267
345
 
268
346
  it "must copy the arguments defined in the superclass" do
269
347
  expect(subject.arguments).to include(command_superclass.arguments)
@@ -280,6 +358,38 @@ describe CommandMapper::Command do
280
358
  end
281
359
  end
282
360
 
361
+ describe ".has_argument?" do
362
+ subject { command_class }
363
+
364
+ let(:name) { :bar }
365
+
366
+ context "when the command has no defined arguments" do
367
+ let(:command_class) { TestCommand::EmptyCommand }
368
+
369
+ it "must return false" do
370
+ expect(subject.has_argument?(name)).to be(false)
371
+ end
372
+ end
373
+
374
+ context "when the command does have defined arguments" do
375
+ let(:command_class) { TestCommand::BaseClassWithArguments }
376
+
377
+ context "and has the argument with the given name" do
378
+ it "must return true" do
379
+ expect(subject.has_argument?(name)).to be(true)
380
+ end
381
+ end
382
+
383
+ context "but does not have the argument with the given name" do
384
+ let(:name) { :xxx }
385
+
386
+ it "must return false" do
387
+ expect(subject.has_argument?(name)).to be(false)
388
+ end
389
+ end
390
+ end
391
+ end
392
+
283
393
  describe ".argument" do
284
394
  module TestCommand
285
395
  class DefinesArgument < CommandMapper::Command
@@ -342,6 +452,59 @@ describe CommandMapper::Command do
342
452
  }.to raise_error(ArgumentError,"argument #{name.inspect} cannot override internal method with same name: ##{name}")
343
453
  end
344
454
  end
455
+
456
+ context "when the argument name conflicts with another defined option" do
457
+ let(:command_class) do
458
+ Class.new(described_class) do
459
+ option '--foo'
460
+ end
461
+ end
462
+
463
+ let(:name) { :foo }
464
+
465
+ it do
466
+ expect {
467
+ subject.argument(name)
468
+ }.to raise_error(ArgumentError,"argument #{name.inspect} conflicts with another option with the same name")
469
+ end
470
+ end
471
+
472
+ context "when the argument name conflicts with another defined subcommand" do
473
+ let(:command_class) do
474
+ Class.new(described_class) do
475
+ subcommand 'foo' do
476
+ end
477
+ end
478
+ end
479
+
480
+ let(:name) { :foo }
481
+
482
+ it do
483
+ expect {
484
+ subject.argument(name)
485
+ }.to raise_error(ArgumentError,"argument #{name.inspect} conflicts with another subcommand with the same name")
486
+ end
487
+ end
488
+ end
489
+
490
+ module TestCommand
491
+ class BaseClassWithSubcommands < CommandMapper::Command
492
+ subcommand :foo do
493
+ end
494
+
495
+ subcommand :bar do
496
+ end
497
+ end
498
+
499
+ class InheritedSubcommands < BaseClassWithSubcommands
500
+ end
501
+
502
+ class InheritsAndDefinesSubcommands < BaseClassWithSubcommands
503
+
504
+ subcommand :baz do
505
+ end
506
+
507
+ end
345
508
  end
346
509
 
347
510
  describe ".subcommands" do
@@ -354,37 +517,15 @@ describe CommandMapper::Command do
354
517
  end
355
518
 
356
519
  context "when the comand does have defined subcommands" do
357
- module TestCommand
358
- class BaseClassWithOptions < CommandMapper::Command
359
- subcommand :foo do
360
- end
361
-
362
- subcommand :bar do
363
- end
364
- end
365
-
366
- class InheritedOptions < BaseClassWithOptions
367
- end
368
- end
369
-
370
- let(:command_class) { TestCommand::InheritedOptions }
371
- let(:command_superclass) { TestCommand::BaseClassWithOptions }
520
+ let(:command_class) { TestCommand::InheritedSubcommands }
521
+ let(:command_superclass) { TestCommand::BaseClassWithSubcommands }
372
522
 
373
523
  it "must copy the subcommands defined in the superclass" do
374
524
  expect(subject.subcommands).to eq(command_superclass.subcommands)
375
525
  end
376
526
 
377
527
  context "and when the class defines subcommands of it's own" do
378
- module TestCommand
379
- class InheritsAndDefinesOptions < BaseClassWithOptions
380
-
381
- subcommand :baz do
382
- end
383
-
384
- end
385
- end
386
-
387
- let(:command_class) { TestCommand::InheritsAndDefinesOptions }
528
+ let(:command_class) { TestCommand::InheritsAndDefinesSubcommands }
388
529
 
389
530
  it "must copy the subcommands defined in the superclass" do
390
531
  expect(subject.subcommands).to include(command_superclass.subcommands)
@@ -401,6 +542,38 @@ describe CommandMapper::Command do
401
542
  end
402
543
  end
403
544
 
545
+ describe ".has_subcommand?" do
546
+ subject { command_class }
547
+
548
+ let(:name) { :bar }
549
+
550
+ context "when the command has no defined subcommands" do
551
+ let(:command_class) { TestCommand::EmptyCommand }
552
+
553
+ it "must return false" do
554
+ expect(subject.has_subcommand?(name)).to be(false)
555
+ end
556
+ end
557
+
558
+ context "when the command does have defined subcommands" do
559
+ let(:command_class) { TestCommand::BaseClassWithSubcommands }
560
+
561
+ context "and has the subcommand with the given name" do
562
+ it "must return true" do
563
+ expect(subject.has_subcommand?(name)).to be(true)
564
+ end
565
+ end
566
+
567
+ context "but does not have the subcommand with the given name" do
568
+ let(:name) { :xxx }
569
+
570
+ it "must return false" do
571
+ expect(subject.has_subcommand?(name)).to be(false)
572
+ end
573
+ end
574
+ end
575
+ end
576
+
404
577
  describe ".subcommand" do
405
578
  module TestCommand
406
579
  class DefinesSubcommand < CommandMapper::Command
@@ -552,11 +725,45 @@ describe CommandMapper::Command do
552
725
 
553
726
  it do
554
727
  expect {
555
- command_class.subcommand(name) do
728
+ subject.subcommand(name) do
556
729
  end
557
730
  }.to raise_error(ArgumentError,"subcommand #{name.inspect} maps to method name ##{method_name} and cannot override the internal method with same name: ##{method_name}")
558
731
  end
559
732
  end
733
+
734
+ context "when the subcommand name conflicts with another defined option" do
735
+ let(:command_class) do
736
+ Class.new(described_class) do
737
+ option '--foo'
738
+ end
739
+ end
740
+
741
+ let(:name) { 'foo' }
742
+
743
+ it do
744
+ expect {
745
+ subject.subcommand(name) do
746
+ end
747
+ }.to raise_error(ArgumentError,"subcommand #{name.inspect} conflicts with another option with the same name")
748
+ end
749
+ end
750
+
751
+ context "when the subcommand name conflicts with another defined argument" do
752
+ let(:command_class) do
753
+ Class.new(described_class) do
754
+ argument :foo
755
+ end
756
+ end
757
+
758
+ let(:name) { 'foo' }
759
+
760
+ it do
761
+ expect {
762
+ subject.subcommand(name) do
763
+ end
764
+ }.to raise_error(ArgumentError,"subcommand #{name.inspect} conflicts with another argument with the same name")
765
+ end
766
+ end
560
767
  end
561
768
 
562
769
  module TestCommand
@@ -600,8 +807,8 @@ describe CommandMapper::Command do
600
807
  {opt1: opt1, arg1: arg1}
601
808
  end
602
809
 
603
- it "must initialize a new command with the Hash of params and call #run" do
604
- if RUBY_VERSION < '3.'
810
+ it "must initialize a new command with the Hash of params and call #run_command" do
811
+ if RUBY_VERSION < '3.' || RUBY_ENGINE == 'truffleruby'
605
812
  expect(subject).to receive(:new).with({},params).and_return(command_instance)
606
813
  else
607
814
  expect(subject).to receive(:new).with(params).and_return(command_instance)
@@ -618,7 +825,7 @@ describe CommandMapper::Command do
618
825
  {opt1: opt1, arg1: arg1}
619
826
  end
620
827
 
621
- it "must initialize a new command with the keyword arguments and call #run" do
828
+ it "must initialize a new command with the keyword arguments and call #run_command" do
622
829
  expect(subject).to receive(:new).with({},**kwargs).and_return(command_instance)
623
830
  expect(command_instance).to receive(:run_command).and_return(return_value)
624
831
 
@@ -627,6 +834,44 @@ describe CommandMapper::Command do
627
834
  end
628
835
  end
629
836
 
837
+ describe ".spawn" do
838
+ let(:command_instance) { double(:command_instance) }
839
+ let(:return_value) { double(:boolean) }
840
+
841
+ subject { command_class }
842
+
843
+ context "when called with a Hash of params" do
844
+ let(:params) do
845
+ {opt1: opt1, arg1: arg1}
846
+ end
847
+
848
+ it "must initialize a new command with the Hash of params and call #spawn_command" do
849
+ if RUBY_VERSION < '3.' || RUBY_ENGINE == 'truffleruby'
850
+ expect(subject).to receive(:new).with({},params).and_return(command_instance)
851
+ else
852
+ expect(subject).to receive(:new).with(params).and_return(command_instance)
853
+ end
854
+
855
+ expect(command_instance).to receive(:spawn_command).and_return(return_value)
856
+
857
+ expect(subject.spawn(params)).to be(return_value)
858
+ end
859
+ end
860
+
861
+ context "when called with keyword aguments" do
862
+ let(:kwargs) do
863
+ {opt1: opt1, arg1: arg1}
864
+ end
865
+
866
+ it "must initialize a new command with the keyword arguments and call #spawn_command" do
867
+ expect(subject).to receive(:new).with({},**kwargs).and_return(command_instance)
868
+ expect(command_instance).to receive(:spawn_command).and_return(return_value)
869
+
870
+ expect(subject.spawn(**kwargs)).to be(return_value)
871
+ end
872
+ end
873
+ end
874
+
630
875
  describe ".capture" do
631
876
  let(:command_instance) { double(:command_instance) }
632
877
  let(:return_value) { double(:string) }
@@ -638,8 +883,8 @@ describe CommandMapper::Command do
638
883
  {opt1: opt1, arg1: arg1}
639
884
  end
640
885
 
641
- it "must initialize a new command with the Hash of params and call #capture" do
642
- if RUBY_VERSION < '3.'
886
+ it "must initialize a new command with the Hash of params and call #capture_command" do
887
+ if RUBY_VERSION < '3.' || RUBY_ENGINE == 'truffleruby'
643
888
  expect(subject).to receive(:new).with({},params).and_return(command_instance)
644
889
  else
645
890
  expect(subject).to receive(:new).with(params).and_return(command_instance)
@@ -656,7 +901,7 @@ describe CommandMapper::Command do
656
901
  {opt1: opt1, arg1: arg1}
657
902
  end
658
903
 
659
- it "must initialize a new command with the keyword arguments and call #capture" do
904
+ it "must initialize a new command with the keyword arguments and call #capture_command" do
660
905
  expect(subject).to receive(:new).with({},**kwargs).and_return(command_instance)
661
906
  expect(command_instance).to receive(:capture_command).and_return(return_value)
662
907
 
@@ -676,8 +921,8 @@ describe CommandMapper::Command do
676
921
  {opt1: opt1, arg1: arg1}
677
922
  end
678
923
 
679
- it "must initialize a new command with the Hash of params and call #popen" do
680
- if RUBY_VERSION < '3.'
924
+ it "must initialize a new command with the Hash of params and call #popen_command" do
925
+ if RUBY_VERSION < '3.' || RUBY_ENGINE == 'truffleruby'
681
926
  expect(subject).to receive(:new).with({},params).and_return(command_instance)
682
927
  else
683
928
  expect(subject).to receive(:new).with(params).and_return(command_instance)
@@ -694,7 +939,7 @@ describe CommandMapper::Command do
694
939
  {opt1: opt1, arg1: arg1}
695
940
  end
696
941
 
697
- it "must initialize a new command with the keyword arguments and call #popen" do
942
+ it "must initialize a new command with the keyword arguments and call #popen_command" do
698
943
  expect(subject).to receive(:new).with({},**kwargs).and_return(command_instance)
699
944
  expect(command_instance).to receive(:popen_command).and_return(return_value)
700
945
 
@@ -714,8 +959,8 @@ describe CommandMapper::Command do
714
959
  {opt1: opt1, arg1: arg1}
715
960
  end
716
961
 
717
- it "must initialize a new command with the Hash of params and call #sudo" do
718
- if RUBY_VERSION < '3.'
962
+ it "must initialize a new command with the Hash of params and call #sudo_command" do
963
+ if RUBY_VERSION < '3.' || RUBY_ENGINE == 'truffleruby'
719
964
  expect(subject).to receive(:new).with({},params).and_return(command_instance)
720
965
  else
721
966
  expect(subject).to receive(:new).with(params).and_return(command_instance)
@@ -732,7 +977,7 @@ describe CommandMapper::Command do
732
977
  {opt1: opt1, arg1: arg1}
733
978
  end
734
979
 
735
- it "must initialize a new command with the keyword arguments and call #sudo" do
980
+ it "must initialize a new command with the keyword arguments and call #sudo_command" do
736
981
  expect(subject).to receive(:new).with({},**kwargs).and_return(command_instance)
737
982
  expect(command_instance).to receive(:sudo_command).and_return(return_value)
738
983
 
@@ -1105,12 +1350,22 @@ describe CommandMapper::Command do
1105
1350
  subject { command_class.new({opt1: opt1, arg1: arg1}, command_env: env) }
1106
1351
 
1107
1352
  it "must pass the command's env and argv to Kenrel.system" do
1108
- expect(subject).to receive(:system).with(env,*subject.command_argv)
1353
+ expect(Kernel).to receive(:system).with(env,*subject.command_argv)
1109
1354
 
1110
1355
  subject.run_command
1111
1356
  end
1112
1357
  end
1113
1358
 
1359
+ describe "#spawn_command" do
1360
+ subject { command_class.new({opt1: opt1, arg1: arg1}, command_env: env) }
1361
+
1362
+ it "must pass the command's env and argv to Kenrel.system" do
1363
+ expect(Process).to receive(:spawn).with(env,*subject.command_argv)
1364
+
1365
+ subject.spawn_command
1366
+ end
1367
+ end
1368
+
1114
1369
  describe "#capture_command" do
1115
1370
  subject { command_class.new({opt1: opt1, arg1: arg1}, command_env: env) }
1116
1371