clamp 1.2.1 → 1.3.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.
- 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
|
|