clamp 1.2.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +12 -4
- data/.travis.yml +4 -6
- data/CHANGES.md +7 -0
- data/Gemfile +8 -6
- data/Guardfile +3 -1
- data/Rakefile +8 -0
- data/clamp.gemspec +8 -6
- data/examples/admin +3 -2
- data/examples/defaulted +4 -3
- data/examples/flipflop +1 -0
- data/examples/fubar +1 -0
- data/examples/gitdown +2 -1
- data/examples/scoop +3 -2
- data/examples/speak +3 -2
- data/examples/subcommand_missing +1 -0
- data/examples/word +1 -0
- data/lib/clamp.rb +3 -1
- data/lib/clamp/attribute/declaration.rb +5 -0
- data/lib/clamp/attribute/definition.rb +15 -12
- data/lib/clamp/attribute/instance.rb +5 -3
- data/lib/clamp/command.rb +9 -1
- data/lib/clamp/errors.rb +7 -3
- data/lib/clamp/help.rb +8 -6
- data/lib/clamp/messages.rb +21 -14
- data/lib/clamp/option/declaration.rb +4 -0
- data/lib/clamp/option/definition.rb +9 -3
- data/lib/clamp/option/parsing.rb +37 -32
- data/lib/clamp/parameter/declaration.rb +4 -0
- data/lib/clamp/parameter/definition.rb +9 -3
- data/lib/clamp/parameter/parsing.rb +5 -1
- data/lib/clamp/subcommand/declaration.rb +15 -13
- data/lib/clamp/subcommand/definition.rb +2 -0
- data/lib/clamp/subcommand/execution.rb +11 -0
- data/lib/clamp/subcommand/parsing.rb +4 -0
- data/lib/clamp/truthy.rb +4 -2
- data/lib/clamp/version.rb +3 -1
- data/spec/clamp/command_group_spec.rb +27 -9
- data/spec/clamp/command_spec.rb +84 -49
- data/spec/clamp/messages_spec.rb +5 -4
- data/spec/clamp/option/definition_spec.rb +13 -11
- data/spec/clamp/option_module_spec.rb +3 -1
- data/spec/clamp/option_reordering_spec.rb +6 -4
- data/spec/clamp/parameter/definition_spec.rb +14 -12
- data/spec/spec_helper.rb +3 -3
- metadata +4 -4
data/lib/clamp/version.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "spec_helper"
|
2
4
|
|
3
5
|
describe Clamp::Command do
|
@@ -122,8 +124,7 @@ describe Clamp::Command do
|
|
122
124
|
|
123
125
|
subcommand "bar", "Baaaa!" do
|
124
126
|
|
125
|
-
def self.this_is_bar
|
126
|
-
end
|
127
|
+
def self.this_is_bar; end
|
127
128
|
|
128
129
|
def execute
|
129
130
|
puts "FUBAR"
|
@@ -274,12 +275,12 @@ describe Clamp::Command do
|
|
274
275
|
|
275
276
|
speed_options = Module.new do
|
276
277
|
extend Clamp::Option::Declaration
|
277
|
-
option "--speed", "SPEED", "how fast", :
|
278
|
+
option "--speed", "SPEED", "how fast", default: "slowly"
|
278
279
|
end
|
279
280
|
|
280
281
|
Class.new(Clamp::Command) do
|
281
282
|
|
282
|
-
option "--direction", "DIR", "which way", :
|
283
|
+
option "--direction", "DIR", "which way", default: "home"
|
283
284
|
|
284
285
|
include speed_options
|
285
286
|
|
@@ -315,7 +316,7 @@ describe Clamp::Command do
|
|
315
316
|
end
|
316
317
|
|
317
318
|
it "has access to command context" do
|
318
|
-
command = command_class.new("go", :
|
319
|
+
command = command_class.new("go", motion: "wandering")
|
319
320
|
command.run(["move"])
|
320
321
|
expect(stdout).to match(/wandering home/)
|
321
322
|
end
|
@@ -331,8 +332,7 @@ describe Clamp::Command do
|
|
331
332
|
end
|
332
333
|
|
333
334
|
subcommand "woohoohoo", "like weeheehee but with more o" do
|
334
|
-
def execute
|
335
|
-
end
|
335
|
+
def execute; end
|
336
336
|
end
|
337
337
|
end
|
338
338
|
|
@@ -370,8 +370,7 @@ describe Clamp::Command do
|
|
370
370
|
end
|
371
371
|
end
|
372
372
|
|
373
|
-
def execute
|
374
|
-
end
|
373
|
+
def execute; end
|
375
374
|
end
|
376
375
|
end
|
377
376
|
|
@@ -396,6 +395,25 @@ describe Clamp::Command do
|
|
396
395
|
command.run(["foo"])
|
397
396
|
expect(stdout).to match(/known subcommand/)
|
398
397
|
end
|
398
|
+
|
399
|
+
end
|
400
|
+
|
401
|
+
context "with a subcommand and required options" do
|
402
|
+
|
403
|
+
given_command "movements" do
|
404
|
+
option "--direction", "N|S|E|W", "bearing", required: true
|
405
|
+
subcommand "hop", "Hop" do
|
406
|
+
def execute
|
407
|
+
puts "Hopping #{direction}"
|
408
|
+
end
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
it "allows options after the subcommand" do
|
413
|
+
command.run(%w[hop --direction south])
|
414
|
+
expect(stdout).to eql "Hopping south\n"
|
415
|
+
end
|
416
|
+
|
399
417
|
end
|
400
418
|
|
401
419
|
end
|
data/spec/clamp/command_spec.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
require "spec_helper"
|
3
4
|
|
@@ -60,7 +61,7 @@ describe Clamp::Command do
|
|
60
61
|
context "with explicit :attribute_name" do
|
61
62
|
|
62
63
|
before do
|
63
|
-
command.class.option "--foo", "FOO", "A foo", :
|
64
|
+
command.class.option "--foo", "FOO", "A foo", attribute_name: :bar
|
64
65
|
end
|
65
66
|
|
66
67
|
it "uses the specified attribute_name name to name accessors" do
|
@@ -95,7 +96,7 @@ describe Clamp::Command do
|
|
95
96
|
context "with :default value" do
|
96
97
|
|
97
98
|
before do
|
98
|
-
command.class.option "--port", "PORT", "port to listen on", :
|
99
|
+
command.class.option "--port", "PORT", "port to listen on", default: 4321
|
99
100
|
end
|
100
101
|
|
101
102
|
it "declares default method" do
|
@@ -112,10 +113,22 @@ describe Clamp::Command do
|
|
112
113
|
|
113
114
|
end
|
114
115
|
|
116
|
+
context "without :default value" do
|
117
|
+
|
118
|
+
before do
|
119
|
+
command.class.option "--port", "PORT", "port to listen on"
|
120
|
+
end
|
121
|
+
|
122
|
+
it "does not declare default method" do
|
123
|
+
expect(command).to_not respond_to(:default_port)
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
115
128
|
context "with :multivalued" do
|
116
129
|
|
117
130
|
before do
|
118
|
-
command.class.option "--flavour", "FLAVOUR", "flavour(s)", :
|
131
|
+
command.class.option "--flavour", "FLAVOUR", "flavour(s)", multivalued: true, attribute_name: :flavours
|
119
132
|
end
|
120
133
|
|
121
134
|
it "defaults to empty array" do
|
@@ -123,20 +136,20 @@ describe Clamp::Command do
|
|
123
136
|
end
|
124
137
|
|
125
138
|
it "supports multiple values" do
|
126
|
-
command.parse(%w
|
127
|
-
expect(command.flavours).to eql %w
|
139
|
+
command.parse(%w[--flavour chocolate --flavour vanilla])
|
140
|
+
expect(command.flavours).to eql %w[chocolate vanilla]
|
128
141
|
end
|
129
142
|
|
130
143
|
it "generates a single-value appender method" do
|
131
144
|
command.append_to_flavours("mud")
|
132
145
|
command.append_to_flavours("pie")
|
133
|
-
expect(command.flavours).to eql %w
|
146
|
+
expect(command.flavours).to eql %w[mud pie]
|
134
147
|
end
|
135
148
|
|
136
149
|
it "generates a multi-value setter method" do
|
137
150
|
command.append_to_flavours("replaceme")
|
138
|
-
command.flavours = %w
|
139
|
-
expect(command.flavours).to eql %w
|
151
|
+
command.flavours = %w[mud pie]
|
152
|
+
expect(command.flavours).to eql %w[mud pie]
|
140
153
|
end
|
141
154
|
|
142
155
|
it "does not require a value" do
|
@@ -154,8 +167,8 @@ describe Clamp::Command do
|
|
154
167
|
|
155
168
|
before do
|
156
169
|
command.class.option "--port", "PORT", "port to listen on",
|
157
|
-
:
|
158
|
-
:
|
170
|
+
default: 4321,
|
171
|
+
environment_variable: "PORT",
|
159
172
|
&:to_i
|
160
173
|
set_env("PORT", environment_value)
|
161
174
|
command.parse(args)
|
@@ -179,7 +192,7 @@ describe Clamp::Command do
|
|
179
192
|
|
180
193
|
context "and a value is specified on the command-line" do
|
181
194
|
|
182
|
-
let(:args) { %w
|
195
|
+
let(:args) { %w[--port 1500] }
|
183
196
|
|
184
197
|
it "uses command-line value" do
|
185
198
|
expect(command.port).to eql 1500
|
@@ -204,7 +217,7 @@ describe Clamp::Command do
|
|
204
217
|
let(:environment_value) { nil }
|
205
218
|
|
206
219
|
before do
|
207
|
-
command.class.option "--[no-]enable", :flag, "enable?", :
|
220
|
+
command.class.option "--[no-]enable", :flag, "enable?", default: false, environment_variable: "ENABLE"
|
208
221
|
set_env("ENABLE", environment_value)
|
209
222
|
command.parse([])
|
210
223
|
end
|
@@ -217,7 +230,7 @@ describe Clamp::Command do
|
|
217
230
|
|
218
231
|
end
|
219
232
|
|
220
|
-
%w
|
233
|
+
%w[1 yes enable on true].each do |truthy_value|
|
221
234
|
|
222
235
|
context "when environment variable is #{truthy_value.inspect}" do
|
223
236
|
|
@@ -231,7 +244,7 @@ describe Clamp::Command do
|
|
231
244
|
|
232
245
|
end
|
233
246
|
|
234
|
-
%w
|
247
|
+
%w[0 no disable off false].each do |falsey_value|
|
235
248
|
|
236
249
|
context "when environment variable is #{falsey_value.inspect}" do
|
237
250
|
|
@@ -250,7 +263,15 @@ describe Clamp::Command do
|
|
250
263
|
context "with :required" do
|
251
264
|
|
252
265
|
before do
|
253
|
-
command.class.option "--port", "PORT", "port to listen on", :
|
266
|
+
command.class.option "--port", "PORT", "port to listen on", required: true
|
267
|
+
end
|
268
|
+
|
269
|
+
describe "#help" do
|
270
|
+
|
271
|
+
it "marks it as required" do
|
272
|
+
expect(command.help).to include("port to listen on (required)")
|
273
|
+
end
|
274
|
+
|
254
275
|
end
|
255
276
|
|
256
277
|
context "when no value is provided" do
|
@@ -278,7 +299,7 @@ describe Clamp::Command do
|
|
278
299
|
context "with :required and :multivalued" do
|
279
300
|
|
280
301
|
before do
|
281
|
-
command.class.option "--port", "PORT", "port to listen on", :
|
302
|
+
command.class.option "--port", "PORT", "port to listen on", required: true, multivalued: true
|
282
303
|
end
|
283
304
|
|
284
305
|
context "when no value is provided" do
|
@@ -329,12 +350,12 @@ describe Clamp::Command do
|
|
329
350
|
command.class.option ["-f", "--flavour"], "FLAVOUR", "Flavour of the month"
|
330
351
|
command.class.option ["-c", "--color"], "COLOR", "Preferred hue"
|
331
352
|
command.class.option ["--scoops"], "N", "Number of scoops",
|
332
|
-
:
|
333
|
-
:
|
353
|
+
default: 1,
|
354
|
+
environment_variable: "DEFAULT_SCOOPS" do |arg|
|
334
355
|
Integer(arg)
|
335
356
|
end
|
336
357
|
command.class.option ["-n", "--[no-]nuts"], :flag, "Nuts (or not)\nMay include nuts"
|
337
|
-
command.class.parameter "[ARG] ...", "extra arguments", :
|
358
|
+
command.class.parameter "[ARG] ...", "extra arguments", attribute_name: :arguments
|
338
359
|
end
|
339
360
|
|
340
361
|
describe "#parse" do
|
@@ -343,7 +364,7 @@ describe Clamp::Command do
|
|
343
364
|
|
344
365
|
it "raises a UsageError" do
|
345
366
|
expect do
|
346
|
-
command.parse(%w
|
367
|
+
command.parse(%w[--foo bar])
|
347
368
|
end.to raise_error(Clamp::UsageError)
|
348
369
|
end
|
349
370
|
|
@@ -352,7 +373,7 @@ describe Clamp::Command do
|
|
352
373
|
context "with options" do
|
353
374
|
|
354
375
|
before do
|
355
|
-
command.parse(%w
|
376
|
+
command.parse(%w[--flavour strawberry --nuts --color blue])
|
356
377
|
end
|
357
378
|
|
358
379
|
it "maps the option values onto the command object" do
|
@@ -366,7 +387,7 @@ describe Clamp::Command do
|
|
366
387
|
context "with short options" do
|
367
388
|
|
368
389
|
before do
|
369
|
-
command.parse(%w
|
390
|
+
command.parse(%w[-f strawberry -c blue])
|
370
391
|
end
|
371
392
|
|
372
393
|
it "recognises short options as aliases" do
|
@@ -379,7 +400,7 @@ describe Clamp::Command do
|
|
379
400
|
context "with a value appended to a short option" do
|
380
401
|
|
381
402
|
before do
|
382
|
-
command.parse(%w
|
403
|
+
command.parse(%w[-fstrawberry])
|
383
404
|
end
|
384
405
|
|
385
406
|
it "works as though the value were separated" do
|
@@ -391,7 +412,7 @@ describe Clamp::Command do
|
|
391
412
|
context "with combined short options" do
|
392
413
|
|
393
414
|
before do
|
394
|
-
command.parse(%w
|
415
|
+
command.parse(%w[-nf strawberry])
|
395
416
|
end
|
396
417
|
|
397
418
|
it "works as though the options were separate" do
|
@@ -404,7 +425,7 @@ describe Clamp::Command do
|
|
404
425
|
context "with option arguments attached using equals sign" do
|
405
426
|
|
406
427
|
before do
|
407
|
-
command.parse(%w
|
428
|
+
command.parse(%w[--flavour=strawberry --color=blue])
|
408
429
|
end
|
409
430
|
|
410
431
|
it "works as though the option arguments were separate" do
|
@@ -417,8 +438,8 @@ describe Clamp::Command do
|
|
417
438
|
context "with option-like things beyond the arguments" do
|
418
439
|
|
419
440
|
it "treats them as positional arguments" do
|
420
|
-
command.parse(%w
|
421
|
-
expect(command.arguments).to eql %w
|
441
|
+
command.parse(%w[a b c --flavour strawberry])
|
442
|
+
expect(command.arguments).to eql %w[a b c --flavour strawberry]
|
422
443
|
end
|
423
444
|
|
424
445
|
end
|
@@ -440,8 +461,8 @@ describe Clamp::Command do
|
|
440
461
|
context "with an option terminator" do
|
441
462
|
|
442
463
|
it "considers everything after the terminator to be an argument" do
|
443
|
-
command.parse(%w
|
444
|
-
expect(command.arguments).to eql %w
|
464
|
+
command.parse(%w[--color blue -- --flavour strawberry])
|
465
|
+
expect(command.arguments).to eql %w[--flavour strawberry]
|
445
466
|
end
|
446
467
|
|
447
468
|
end
|
@@ -449,7 +470,7 @@ describe Clamp::Command do
|
|
449
470
|
context "with --flag" do
|
450
471
|
|
451
472
|
before do
|
452
|
-
command.parse(%w
|
473
|
+
command.parse(%w[--nuts])
|
453
474
|
end
|
454
475
|
|
455
476
|
it "sets the flag" do
|
@@ -462,7 +483,7 @@ describe Clamp::Command do
|
|
462
483
|
|
463
484
|
before do
|
464
485
|
command.nuts = true
|
465
|
-
command.parse(%w
|
486
|
+
command.parse(%w[--no-nuts])
|
466
487
|
end
|
467
488
|
|
468
489
|
it "clears the flag" do
|
@@ -475,7 +496,7 @@ describe Clamp::Command do
|
|
475
496
|
|
476
497
|
it "requests help" do
|
477
498
|
expect do
|
478
|
-
command.parse(%w
|
499
|
+
command.parse(%w[--help])
|
479
500
|
end.to raise_error(Clamp::HelpWanted)
|
480
501
|
end
|
481
502
|
|
@@ -485,7 +506,7 @@ describe Clamp::Command do
|
|
485
506
|
|
486
507
|
it "requests help" do
|
487
508
|
expect do
|
488
|
-
command.parse(%w
|
509
|
+
command.parse(%w[-h])
|
489
510
|
end.to raise_error(Clamp::HelpWanted)
|
490
511
|
end
|
491
512
|
|
@@ -495,7 +516,7 @@ describe Clamp::Command do
|
|
495
516
|
|
496
517
|
it "signals a UsageError" do
|
497
518
|
expect do
|
498
|
-
command.parse(%w
|
519
|
+
command.parse(%w[--scoops reginald])
|
499
520
|
end.to raise_error(Clamp::UsageError, /^option '--scoops': invalid value for Integer/)
|
500
521
|
end
|
501
522
|
|
@@ -541,14 +562,14 @@ describe Clamp::Command do
|
|
541
562
|
|
542
563
|
it "does not generate implicit help option" do
|
543
564
|
expect do
|
544
|
-
command.parse(%w
|
565
|
+
command.parse(%w[--help])
|
545
566
|
end.to_not raise_error
|
546
567
|
expect(command.help?).to be true
|
547
568
|
end
|
548
569
|
|
549
570
|
it "does not recognise -h" do
|
550
571
|
expect do
|
551
|
-
command.parse(%w
|
572
|
+
command.parse(%w[-h])
|
552
573
|
end.to raise_error(Clamp::UsageError)
|
553
574
|
end
|
554
575
|
|
@@ -568,7 +589,7 @@ describe Clamp::Command do
|
|
568
589
|
|
569
590
|
it "still recognises --help" do
|
570
591
|
expect do
|
571
|
-
command.parse(%w
|
592
|
+
command.parse(%w[--help])
|
572
593
|
end.to raise_error(Clamp::HelpWanted)
|
573
594
|
end
|
574
595
|
|
@@ -586,7 +607,7 @@ describe Clamp::Command do
|
|
586
607
|
context "with explicit :attribute_name" do
|
587
608
|
|
588
609
|
before do
|
589
|
-
command.class.parameter "FOO", "a foo", :
|
610
|
+
command.class.parameter "FOO", "a foo", attribute_name: :bar
|
590
611
|
end
|
591
612
|
|
592
613
|
it "uses the specified attribute_name name to name accessors" do
|
@@ -599,7 +620,7 @@ describe Clamp::Command do
|
|
599
620
|
context "with :default value" do
|
600
621
|
|
601
622
|
before do
|
602
|
-
command.class.parameter "[ORIENTATION]", "direction", :
|
623
|
+
command.class.parameter "[ORIENTATION]", "direction", default: "west"
|
603
624
|
end
|
604
625
|
|
605
626
|
it "sets the specified default value" do
|
@@ -641,8 +662,8 @@ describe Clamp::Command do
|
|
641
662
|
end
|
642
663
|
|
643
664
|
it "accepts multiple arguments" do
|
644
|
-
command.parse(%w
|
645
|
-
expect(command.file_list).to eql %w
|
665
|
+
command.parse(%w[X Y Z])
|
666
|
+
expect(command.file_list).to eql %w[X Y Z]
|
646
667
|
end
|
647
668
|
|
648
669
|
end
|
@@ -670,8 +691,8 @@ describe Clamp::Command do
|
|
670
691
|
context "with :environment_variable" do
|
671
692
|
|
672
693
|
before do
|
673
|
-
command.class.parameter "[FILE]", "a file", :
|
674
|
-
:
|
694
|
+
command.class.parameter "[FILE]", "a file", environment_variable: "FILE",
|
695
|
+
default: "/dev/null"
|
675
696
|
end
|
676
697
|
|
677
698
|
let(:args) { [] }
|
@@ -749,7 +770,7 @@ describe Clamp::Command do
|
|
749
770
|
before do
|
750
771
|
command.class.parameter "X", "x\nxx"
|
751
772
|
command.class.parameter "Y", "y"
|
752
|
-
command.class.parameter "[Z]", "z", :
|
773
|
+
command.class.parameter "[Z]", "z", default: "ZZZ"
|
753
774
|
end
|
754
775
|
|
755
776
|
describe "#parse" do
|
@@ -832,6 +853,20 @@ describe Clamp::Command do
|
|
832
853
|
|
833
854
|
end
|
834
855
|
|
856
|
+
describe ".execute" do
|
857
|
+
|
858
|
+
it "provides an alternative way to declare execute method" do
|
859
|
+
command_class.class_eval do
|
860
|
+
execute do
|
861
|
+
puts "using execute DSL"
|
862
|
+
end
|
863
|
+
end
|
864
|
+
command.run([])
|
865
|
+
expect(stdout).to eq("using execute DSL\n")
|
866
|
+
end
|
867
|
+
|
868
|
+
end
|
869
|
+
|
835
870
|
context "with explicit usage" do
|
836
871
|
|
837
872
|
given_command("blah") do
|
@@ -874,12 +909,12 @@ describe Clamp::Command do
|
|
874
909
|
|
875
910
|
given_command("punt") do
|
876
911
|
|
877
|
-
banner <<-
|
912
|
+
banner <<-TEXT
|
878
913
|
Punt is an example command. It doesn't do much, really.
|
879
914
|
|
880
915
|
The prefix at the beginning of this description should be normalised
|
881
916
|
to two spaces.
|
882
|
-
|
917
|
+
TEXT
|
883
918
|
|
884
919
|
end
|
885
920
|
|
@@ -903,7 +938,7 @@ describe Clamp::Command do
|
|
903
938
|
print word_list.inspect
|
904
939
|
end
|
905
940
|
end
|
906
|
-
@xyz = %w
|
941
|
+
@xyz = %w[x y z]
|
907
942
|
command.class.run("cmd", @xyz)
|
908
943
|
expect(stdout).to eql @xyz.inspect
|
909
944
|
end
|
@@ -916,7 +951,7 @@ describe Clamp::Command do
|
|
916
951
|
print context[:foo]
|
917
952
|
end
|
918
953
|
end
|
919
|
-
command.class.run("xyz", [], :
|
954
|
+
command.class.run("xyz", [], foo: "bar")
|
920
955
|
expect(stdout).to eql "bar"
|
921
956
|
end
|
922
957
|
|
@@ -928,7 +963,7 @@ describe Clamp::Command do
|
|
928
963
|
|
929
964
|
command.class.class_eval do
|
930
965
|
def execute
|
931
|
-
signal_error "Oh crap!", :
|
966
|
+
signal_error "Oh crap!", status: 456
|
932
967
|
end
|
933
968
|
end
|
934
969
|
|