command_kit 0.2.0 → 0.2.1
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 +4 -1
- data/ChangeLog.md +64 -0
- data/README.md +48 -0
- data/gemspec.yml +1 -1
- data/lib/command_kit/arguments.rb +6 -2
- data/lib/command_kit/colors.rb +1 -1
- data/lib/command_kit/commands/auto_load.rb +8 -1
- data/lib/command_kit/commands/help.rb +3 -2
- data/lib/command_kit/commands/subcommand.rb +1 -1
- data/lib/command_kit/commands.rb +20 -5
- data/lib/command_kit/env/path.rb +1 -1
- data/lib/command_kit/help/man.rb +11 -7
- data/lib/command_kit/inflector.rb +2 -2
- data/lib/command_kit/interactive.rb +9 -0
- data/lib/command_kit/open_app.rb +1 -1
- data/lib/command_kit/options/option_value.rb +3 -2
- data/lib/command_kit/options/parser.rb +2 -2
- data/lib/command_kit/options.rb +18 -5
- data/lib/command_kit/printing/indent.rb +2 -2
- data/lib/command_kit/printing.rb +13 -2
- data/lib/command_kit/version.rb +1 -1
- data/spec/arguments_spec.rb +50 -0
- data/spec/command_spec.rb +75 -4
- data/spec/commands/auto_load_spec.rb +33 -2
- data/spec/commands_spec.rb +101 -27
- data/spec/env/path_spec.rb +6 -0
- data/spec/help/man_spec.rb +44 -25
- data/spec/options/option_value_spec.rb +55 -0
- data/spec/options_spec.rb +282 -0
- data/spec/os/linux_spec.rb +20 -10
- data/spec/pager_spec.rb +2 -2
- data/spec/printing/indent_spec.rb +7 -5
- data/spec/printing_spec.rb +23 -1
- metadata +3 -2
data/spec/options_spec.rb
CHANGED
@@ -133,5 +133,287 @@ describe CommandKit::Options do
|
|
133
133
|
it "must initialize #options" do
|
134
134
|
expect(subject.options).to eq({})
|
135
135
|
end
|
136
|
+
|
137
|
+
context "when options have default values" do
|
138
|
+
module TestOptions
|
139
|
+
class TestCommandWithDefaultValues
|
140
|
+
|
141
|
+
include CommandKit::Options
|
142
|
+
|
143
|
+
option :option1, value: {
|
144
|
+
required: true,
|
145
|
+
type: String
|
146
|
+
},
|
147
|
+
desc: 'Option 1'
|
148
|
+
|
149
|
+
option :option2, value: {
|
150
|
+
required: false,
|
151
|
+
type: String,
|
152
|
+
default: "foo"
|
153
|
+
},
|
154
|
+
desc: 'Option 2'
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
let(:command_class) { TestOptions::TestCommandWithDefaultValues }
|
159
|
+
|
160
|
+
it "must pre-populate #options with the default values" do
|
161
|
+
expect(subject.options).to_not have_key(:option1)
|
162
|
+
expect(subject.options).to have_key(:option2)
|
163
|
+
expect(subject.options[:option2]).to eq("foo")
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
module TestOptions
|
169
|
+
class TestCommandWithOptionsAndArguments
|
170
|
+
|
171
|
+
include CommandKit::Options
|
172
|
+
|
173
|
+
usage '[OPTIONS] ARG1 [ARG2]'
|
174
|
+
|
175
|
+
option :option1, short: '-a',
|
176
|
+
value: {
|
177
|
+
type: Integer,
|
178
|
+
default: 1
|
179
|
+
},
|
180
|
+
desc: "Option 1"
|
181
|
+
|
182
|
+
option :option2, short: '-b',
|
183
|
+
value: {
|
184
|
+
type: String,
|
185
|
+
usage: 'FILE'
|
186
|
+
},
|
187
|
+
desc: "Option 2"
|
188
|
+
|
189
|
+
argument :argument1, required: true,
|
190
|
+
usage: 'ARG1',
|
191
|
+
desc: "Argument 1"
|
192
|
+
|
193
|
+
argument :argument2, required: false,
|
194
|
+
usage: 'ARG2',
|
195
|
+
desc: "Argument 2"
|
196
|
+
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe "#option_parser" do
|
201
|
+
context "when an option does not accept a value" do
|
202
|
+
module TestOptions
|
203
|
+
class TestCommandWithOptionWithoutValue
|
204
|
+
|
205
|
+
include CommandKit::Options
|
206
|
+
|
207
|
+
option :opt, desc: "Option without a value"
|
208
|
+
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
let(:command_class) { TestOptions::TestCommandWithOptionWithoutValue }
|
213
|
+
|
214
|
+
context "but the option flag was not given" do
|
215
|
+
let(:argv) { [] }
|
216
|
+
|
217
|
+
before { subject.option_parser.parse(argv) }
|
218
|
+
|
219
|
+
it "must not populate #options with a value" do
|
220
|
+
expect(subject.options).to be_empty
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
context "and the option flag was given" do
|
225
|
+
let(:argv) { %w[--opt] }
|
226
|
+
|
227
|
+
before { subject.option_parser.parse(argv) }
|
228
|
+
|
229
|
+
it "must set a key in #options to true" do
|
230
|
+
expect(subject.options[:opt]).to be(true)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
context "when an option requires a value" do
|
236
|
+
module TestOptions
|
237
|
+
class TestCommandWithOptionWithRequiredValue
|
238
|
+
|
239
|
+
include CommandKit::Options
|
240
|
+
|
241
|
+
option :opt, value: {
|
242
|
+
required: true,
|
243
|
+
type: String
|
244
|
+
},
|
245
|
+
desc: "Option without a value"
|
246
|
+
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
let(:command_class) do
|
251
|
+
TestOptions::TestCommandWithOptionWithRequiredValue
|
252
|
+
end
|
253
|
+
|
254
|
+
context "but the option flag was not given" do
|
255
|
+
let(:argv) { [] }
|
256
|
+
|
257
|
+
before { subject.option_parser.parse(argv) }
|
258
|
+
|
259
|
+
it "must not populate #options with a value" do
|
260
|
+
expect(subject.options).to be_empty
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
context "and the option flag and value were given" do
|
265
|
+
let(:value) { 'foo' }
|
266
|
+
let(:argv) { ['--opt', value] }
|
267
|
+
|
268
|
+
before { subject.option_parser.parse(argv) }
|
269
|
+
|
270
|
+
it "must set a key in #options to the value" do
|
271
|
+
expect(subject.options[:opt]).to eq(value)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
context "when an option does not require a value" do
|
277
|
+
module TestOptions
|
278
|
+
class TestCommandWithOptionWithOptionalValue
|
279
|
+
|
280
|
+
include CommandKit::Options
|
281
|
+
|
282
|
+
option :opt, value: {
|
283
|
+
required: false,
|
284
|
+
type: String
|
285
|
+
},
|
286
|
+
desc: "Option without a value"
|
287
|
+
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
let(:command_class) do
|
292
|
+
TestOptions::TestCommandWithOptionWithOptionalValue
|
293
|
+
end
|
294
|
+
|
295
|
+
context "but the option flag was not given" do
|
296
|
+
let(:argv) { [] }
|
297
|
+
|
298
|
+
before { subject.option_parser.parse(argv) }
|
299
|
+
|
300
|
+
it "must not populate #options with a value" do
|
301
|
+
expect(subject.options).to be_empty
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
context "and the option flag and value were given" do
|
306
|
+
let(:value) { 'foo' }
|
307
|
+
let(:argv) { ['--opt', value] }
|
308
|
+
|
309
|
+
before { subject.option_parser.parse(argv) }
|
310
|
+
|
311
|
+
it "must set a key in #options to the value" do
|
312
|
+
expect(subject.options[:opt]).to eq(value)
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
context "and the option has a default value" do
|
317
|
+
module TestOptions
|
318
|
+
class TestCommandWithOptionWithOptionalValueAndDefaultValue
|
319
|
+
|
320
|
+
include CommandKit::Options
|
321
|
+
|
322
|
+
option :opt, value: {
|
323
|
+
required: false,
|
324
|
+
type: String,
|
325
|
+
default: "bar"
|
326
|
+
},
|
327
|
+
desc: "Option without a value"
|
328
|
+
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
let(:command_class) do
|
333
|
+
TestOptions::TestCommandWithOptionWithOptionalValueAndDefaultValue
|
334
|
+
end
|
335
|
+
|
336
|
+
context "but the option flag was not given" do
|
337
|
+
let(:argv) { [] }
|
338
|
+
|
339
|
+
before { subject.option_parser.parse(argv) }
|
340
|
+
|
341
|
+
it "must set a key in #options to the default value" do
|
342
|
+
expect(subject.options[:opt]).to eq("bar")
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
context "and the option flag and value were given" do
|
347
|
+
let(:value) { 'foo' }
|
348
|
+
let(:argv) { ['--opt', value] }
|
349
|
+
|
350
|
+
before { subject.option_parser.parse(argv) }
|
351
|
+
|
352
|
+
it "must set a key in #options to the value" do
|
353
|
+
expect(subject.options[:opt]).to eq(value)
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
context "and the option flag but not the value are given" do
|
358
|
+
let(:argv) { ['--opt'] }
|
359
|
+
|
360
|
+
before { subject.option_parser.parse(argv) }
|
361
|
+
|
362
|
+
it "must set a key in #options to nil" do
|
363
|
+
expect(subject.options).to have_key(:opt)
|
364
|
+
expect(subject.options[:opt]).to be(nil)
|
365
|
+
end
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
describe "#main" do
|
372
|
+
let(:command_class) { TestOptions::TestCommandWithOptionsAndArguments }
|
373
|
+
|
374
|
+
let(:argv) { %w[-a 42 -b foo.txt arg1 arg2] }
|
375
|
+
|
376
|
+
it "must parse options before validating the number of arguments" do
|
377
|
+
expect {
|
378
|
+
expect(subject.main(argv)).to eq(0)
|
379
|
+
}.to_not output.to_stderr
|
380
|
+
end
|
381
|
+
|
382
|
+
context "but the wrong number of arguments are given" do
|
383
|
+
let(:argv) { %w[-a 42 -b foo.txt] }
|
384
|
+
|
385
|
+
it "must still validate the number of arguments" do
|
386
|
+
expect {
|
387
|
+
expect(subject.main(argv)).to eq(1)
|
388
|
+
}.to output("#{subject.command_name}: insufficient number of arguments.#{$/}").to_stderr
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
describe "#help" do
|
394
|
+
let(:command_class) { TestOptions::TestCommandWithOptionsAndArguments }
|
395
|
+
|
396
|
+
let(:option1) { command_class.options[:option1] }
|
397
|
+
let(:option2) { command_class.options[:option2] }
|
398
|
+
let(:argument1) { command_class.arguments[:argument1] }
|
399
|
+
let(:argument2) { command_class.arguments[:argument2] }
|
400
|
+
|
401
|
+
it "must print the usage, options and arguments" do
|
402
|
+
expect { subject.help }.to output(
|
403
|
+
[
|
404
|
+
"Usage: #{subject.usage}",
|
405
|
+
'',
|
406
|
+
'Options:',
|
407
|
+
" #{option1.usage.join(', ').ljust(33 - 1)} #{option1.desc}",
|
408
|
+
" #{option2.usage.join(', ').ljust(33 - 1)} #{option2.desc}",
|
409
|
+
' -h, --help Print help information',
|
410
|
+
'',
|
411
|
+
"Arguments:",
|
412
|
+
" #{argument1.usage.ljust(33)}#{argument1.desc}",
|
413
|
+
" #{argument2.usage.ljust(33)}#{argument2.desc}",
|
414
|
+
''
|
415
|
+
].join($/)
|
416
|
+
).to_stdout
|
417
|
+
end
|
136
418
|
end
|
137
419
|
end
|
data/spec/os/linux_spec.rb
CHANGED
@@ -83,70 +83,80 @@ describe CommandKit::OS::Linux do
|
|
83
83
|
end
|
84
84
|
|
85
85
|
describe "#redhat_linux?" do
|
86
|
+
subject { command_class.new(linux_distro: linux_distro) }
|
87
|
+
|
86
88
|
context "when #linux_distro is :redhat" do
|
87
|
-
|
89
|
+
let(:linux_distro) { :redhat }
|
88
90
|
|
89
91
|
it { expect(subject.redhat_linux?).to be(true) }
|
90
92
|
end
|
91
93
|
|
92
94
|
context "when #linux_distro is not :redhat" do
|
93
|
-
|
95
|
+
let(:linux_distro) { :debian }
|
94
96
|
|
95
97
|
it { expect(subject.redhat_linux?).to be(false) }
|
96
98
|
end
|
97
99
|
end
|
98
100
|
|
99
101
|
describe "#fedora_linux?" do
|
102
|
+
subject { command_class.new(linux_distro: linux_distro) }
|
103
|
+
|
100
104
|
context "when #linux_distro is :fedora" do
|
101
|
-
|
105
|
+
let(:linux_distro) { :fedora }
|
102
106
|
|
103
107
|
it { expect(subject.fedora_linux?).to be(true) }
|
104
108
|
end
|
105
109
|
|
106
110
|
context "when #linux_distro is not :fedora" do
|
107
|
-
|
111
|
+
let(:linux_distro) { :debian }
|
108
112
|
|
109
113
|
it { expect(subject.fedora_linux?).to be(false) }
|
110
114
|
end
|
111
115
|
end
|
112
116
|
|
113
117
|
describe "#debian_linux?" do
|
118
|
+
subject { command_class.new(linux_distro: linux_distro) }
|
119
|
+
|
114
120
|
context "when #linux_distro is :debian" do
|
115
|
-
|
121
|
+
let(:linux_distro) { :debian }
|
116
122
|
|
117
123
|
it { expect(subject.debian_linux?).to be(true) }
|
118
124
|
end
|
119
125
|
|
120
126
|
context "when #linux_distro is not :fedora" do
|
121
|
-
|
127
|
+
let(:linux_distro) { :redhat }
|
122
128
|
|
123
129
|
it { expect(subject.debian_linux?).to be(false) }
|
124
130
|
end
|
125
131
|
end
|
126
132
|
|
127
133
|
describe "#suse_linux?" do
|
134
|
+
subject { command_class.new(linux_distro: linux_distro) }
|
135
|
+
|
128
136
|
context "when #linux_distro is :suse" do
|
129
|
-
|
137
|
+
let(:linux_distro) { :suse }
|
130
138
|
|
131
139
|
it { expect(subject.suse_linux?).to be(true) }
|
132
140
|
end
|
133
141
|
|
134
142
|
context "when #linux_distro is not :suse" do
|
135
|
-
|
143
|
+
let(:linux_distro) { :debian }
|
136
144
|
|
137
145
|
it { expect(subject.suse_linux?).to be(false) }
|
138
146
|
end
|
139
147
|
end
|
140
148
|
|
141
149
|
describe "#arch_linux?" do
|
150
|
+
subject { command_class.new(linux_distro: linux_distro) }
|
151
|
+
|
142
152
|
context "when #linux_distro is :arch" do
|
143
|
-
|
153
|
+
let(:linux_distro) { :arch }
|
144
154
|
|
145
155
|
it { expect(subject.arch_linux?).to be(true) }
|
146
156
|
end
|
147
157
|
|
148
158
|
context "when #linux_distro is not :arch" do
|
149
|
-
|
159
|
+
let(:linux_distro) { :debian }
|
150
160
|
|
151
161
|
it { expect(subject.arch_linux?).to be(false) }
|
152
162
|
end
|
data/spec/pager_spec.rb
CHANGED
@@ -170,7 +170,7 @@ describe CommandKit::Pager do
|
|
170
170
|
|
171
171
|
context "and when given a String and additional arguments" do
|
172
172
|
let(:command) { 'find' }
|
173
|
-
let(:arguments) { %[. -name *.md] }
|
173
|
+
let(:arguments) { %w[. -name *.md] }
|
174
174
|
|
175
175
|
let(:escaped_command) do
|
176
176
|
Shellwords.shelljoin([command,*arguments])
|
@@ -192,7 +192,7 @@ describe CommandKit::Pager do
|
|
192
192
|
end
|
193
193
|
|
194
194
|
let(:command) { 'find' }
|
195
|
-
let(:arguments) { %[. -name *.md] }
|
195
|
+
let(:arguments) { %w[. -name *.md] }
|
196
196
|
|
197
197
|
it "must pass the command and any additional arguments to #system" do
|
198
198
|
expect(subject).to receive(:system).with(command,*arguments)
|
@@ -12,14 +12,16 @@ describe CommandKit::Printing::Indent do
|
|
12
12
|
subject { command_class.new }
|
13
13
|
|
14
14
|
describe "#initialize" do
|
15
|
-
it "must initialize
|
16
|
-
expect(subject.
|
15
|
+
it "must initialize #indent to 0" do
|
16
|
+
expect(subject.indent).to eq(0)
|
17
17
|
end
|
18
18
|
|
19
19
|
context "when the class has a superclass" do
|
20
20
|
module TestIndent
|
21
21
|
class TestSuperCommand
|
22
22
|
|
23
|
+
attr_reader :var
|
24
|
+
|
23
25
|
def initialize(var: 'default')
|
24
26
|
@var = var
|
25
27
|
end
|
@@ -36,11 +38,11 @@ describe CommandKit::Printing::Indent do
|
|
36
38
|
let(:command_class) { TestIndent::TestSubCommand }
|
37
39
|
|
38
40
|
it "must initialize @indent to 0" do
|
39
|
-
expect(subject.
|
41
|
+
expect(subject.indent).to eq(0)
|
40
42
|
end
|
41
43
|
|
42
44
|
it "must call super()" do
|
43
|
-
expect(subject.
|
45
|
+
expect(subject.var).to eq('default')
|
44
46
|
end
|
45
47
|
|
46
48
|
context "and additional keyword arguments are given" do
|
@@ -49,7 +51,7 @@ describe CommandKit::Printing::Indent do
|
|
49
51
|
subject { command_class.new(var: var) }
|
50
52
|
|
51
53
|
it "must call super() with the additional keyword arguments" do
|
52
|
-
expect(subject.
|
54
|
+
expect(subject.var).to eq(var)
|
53
55
|
end
|
54
56
|
end
|
55
57
|
end
|
data/spec/printing_spec.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'command_kit/printing'
|
3
|
+
require 'command_kit/command_name'
|
3
4
|
|
4
5
|
require 'stringio'
|
5
6
|
|
@@ -34,11 +35,32 @@ describe CommandKit::Printing do
|
|
34
35
|
describe "#print_error" do
|
35
36
|
let(:message) { "oh no!" }
|
36
37
|
|
37
|
-
it "must print
|
38
|
+
it "must print the error message to stderr" do
|
38
39
|
expect {
|
39
40
|
subject.print_error(message)
|
40
41
|
}.to output("#{message}#{nl}").to_stderr
|
41
42
|
end
|
43
|
+
|
44
|
+
context "and when CommandKit::CommandName is included" do
|
45
|
+
module TestPrinting
|
46
|
+
class TestCmdWithCommandName
|
47
|
+
|
48
|
+
include CommandKit::CommandName
|
49
|
+
include CommandKit::Printing
|
50
|
+
|
51
|
+
command_name 'foo'
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
let(:command_class) { TestPrinting::TestCmdWithCommandName }
|
57
|
+
|
58
|
+
it "must print the command_name and the error message" do
|
59
|
+
expect {
|
60
|
+
subject.print_error(message)
|
61
|
+
}.to output("#{subject.command_name}: #{message}#{nl}").to_stderr
|
62
|
+
end
|
63
|
+
end
|
42
64
|
end
|
43
65
|
|
44
66
|
describe "#print_exception" do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: command_kit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Postmodern
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-11-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -153,6 +153,7 @@ metadata:
|
|
153
153
|
source_code_uri: https://github.com/postmodern/command_kit.rb
|
154
154
|
bug_tracker_uri: https://github.com/postmodern/command_kit.rb/issues
|
155
155
|
changelog_uri: https://github.com/postmodern/command_kit.rb/blob/main/ChangeLog.md
|
156
|
+
rubygems_mfa_required: 'true'
|
156
157
|
post_install_message:
|
157
158
|
rdoc_options: []
|
158
159
|
require_paths:
|