clamp 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +12 -4
  3. data/.travis.yml +4 -6
  4. data/CHANGES.md +7 -0
  5. data/Gemfile +8 -6
  6. data/Guardfile +3 -1
  7. data/Rakefile +8 -0
  8. data/clamp.gemspec +8 -6
  9. data/examples/admin +3 -2
  10. data/examples/defaulted +4 -3
  11. data/examples/flipflop +1 -0
  12. data/examples/fubar +1 -0
  13. data/examples/gitdown +2 -1
  14. data/examples/scoop +3 -2
  15. data/examples/speak +3 -2
  16. data/examples/subcommand_missing +1 -0
  17. data/examples/word +1 -0
  18. data/lib/clamp.rb +3 -1
  19. data/lib/clamp/attribute/declaration.rb +5 -0
  20. data/lib/clamp/attribute/definition.rb +15 -12
  21. data/lib/clamp/attribute/instance.rb +5 -3
  22. data/lib/clamp/command.rb +9 -1
  23. data/lib/clamp/errors.rb +7 -3
  24. data/lib/clamp/help.rb +8 -6
  25. data/lib/clamp/messages.rb +21 -14
  26. data/lib/clamp/option/declaration.rb +4 -0
  27. data/lib/clamp/option/definition.rb +9 -3
  28. data/lib/clamp/option/parsing.rb +37 -32
  29. data/lib/clamp/parameter/declaration.rb +4 -0
  30. data/lib/clamp/parameter/definition.rb +9 -3
  31. data/lib/clamp/parameter/parsing.rb +5 -1
  32. data/lib/clamp/subcommand/declaration.rb +15 -13
  33. data/lib/clamp/subcommand/definition.rb +2 -0
  34. data/lib/clamp/subcommand/execution.rb +11 -0
  35. data/lib/clamp/subcommand/parsing.rb +4 -0
  36. data/lib/clamp/truthy.rb +4 -2
  37. data/lib/clamp/version.rb +3 -1
  38. data/spec/clamp/command_group_spec.rb +27 -9
  39. data/spec/clamp/command_spec.rb +84 -49
  40. data/spec/clamp/messages_spec.rb +5 -4
  41. data/spec/clamp/option/definition_spec.rb +13 -11
  42. data/spec/clamp/option_module_spec.rb +3 -1
  43. data/spec/clamp/option_reordering_spec.rb +6 -4
  44. data/spec/clamp/parameter/definition_spec.rb +14 -12
  45. data/spec/spec_helper.rb +3 -3
  46. metadata +4 -4
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Clamp
2
- VERSION = "1.2.1".freeze
4
+ VERSION = "1.3.0".freeze
3
5
  end
@@ -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", :default => "slowly"
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", :default => "home"
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", :motion => "wandering")
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
@@ -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", :attribute_name => :bar
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", :default => 4321
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)", :multivalued => true, :attribute_name => :flavours
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(--flavour chocolate --flavour vanilla))
127
- expect(command.flavours).to eql %w(chocolate vanilla)
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(mud pie)
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(mud pie)
139
- expect(command.flavours).to eql %w(mud pie)
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
- :default => 4321,
158
- :environment_variable => "PORT",
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(--port 1500) }
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?", :default => false, :environment_variable => "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(1 yes enable on true).each do |truthy_value|
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(0 no disable off false).each do |falsey_value|
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", :required => true
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", :required => true, :multivalued => true
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
- :default => 1,
333
- :environment_variable => "DEFAULT_SCOOPS" do |arg|
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", :attribute_name => :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(--foo bar))
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(--flavour strawberry --nuts --color blue))
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(-f strawberry -c blue))
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(-fstrawberry))
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(-nf strawberry))
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(--flavour=strawberry --color=blue))
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(a b c --flavour strawberry))
421
- expect(command.arguments).to eql %w(a b c --flavour strawberry)
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(--color blue -- --flavour strawberry))
444
- expect(command.arguments).to eql %w(--flavour strawberry)
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(--nuts))
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(--no-nuts))
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(--help))
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(-h))
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(--scoops reginald))
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(--help))
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(-h))
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(--help))
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", :attribute_name => :bar
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", :default => "west"
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(X Y Z))
645
- expect(command.file_list).to eql %w(X Y Z)
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", :environment_variable => "FILE",
674
- :default => "/dev/null"
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", :default => "ZZZ"
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 <<-EOF
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
- EOF
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(x y z)
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", [], :foo => "bar")
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!", :status => 456
966
+ signal_error "Oh crap!", status: 456
932
967
  end
933
968
  end
934
969