command_kit 0.1.0.rc1 → 0.2.2
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/.github/workflows/ruby.yml +17 -3
- data/.rubocop.yml +141 -0
- data/ChangeLog.md +102 -1
- data/Gemfile +3 -0
- data/README.md +187 -116
- data/Rakefile +3 -2
- data/command_kit.gemspec +4 -4
- data/examples/command.rb +1 -1
- data/gemspec.yml +8 -1
- data/lib/command_kit/arguments/argument.rb +2 -0
- data/lib/command_kit/arguments/argument_value.rb +2 -0
- data/lib/command_kit/arguments.rb +25 -6
- data/lib/command_kit/colors.rb +253 -45
- data/lib/command_kit/command.rb +6 -1
- data/lib/command_kit/command_name.rb +9 -0
- data/lib/command_kit/commands/auto_load.rb +24 -1
- data/lib/command_kit/commands/auto_require.rb +16 -0
- data/lib/command_kit/commands/command.rb +3 -0
- data/lib/command_kit/commands/help.rb +5 -2
- data/lib/command_kit/commands/parent_command.rb +7 -0
- data/lib/command_kit/commands/subcommand.rb +13 -1
- data/lib/command_kit/commands.rb +54 -9
- data/lib/command_kit/description.rb +12 -1
- data/lib/command_kit/env/home.rb +9 -0
- data/lib/command_kit/env/path.rb +16 -1
- data/lib/command_kit/env.rb +4 -0
- data/lib/command_kit/examples.rb +12 -1
- data/lib/command_kit/exception_handler.rb +4 -0
- data/lib/command_kit/help/man.rb +28 -31
- data/lib/command_kit/help.rb +7 -1
- data/lib/command_kit/inflector.rb +49 -17
- data/lib/command_kit/interactive.rb +71 -1
- data/lib/command_kit/main.rb +18 -9
- data/lib/command_kit/man.rb +44 -0
- data/lib/command_kit/open_app.rb +69 -0
- data/lib/command_kit/options/option.rb +3 -6
- data/lib/command_kit/options/option_value.rb +5 -2
- data/lib/command_kit/options/parser.rb +46 -19
- data/lib/command_kit/options/quiet.rb +3 -0
- data/lib/command_kit/options/verbose.rb +5 -0
- data/lib/command_kit/options/version.rb +6 -0
- data/lib/command_kit/options.rb +32 -7
- data/lib/command_kit/os/linux.rb +157 -0
- data/lib/command_kit/os.rb +165 -11
- data/lib/command_kit/package_manager.rb +200 -0
- data/lib/command_kit/pager.rb +73 -4
- data/lib/command_kit/printing/indent.rb +27 -4
- data/lib/command_kit/printing.rb +35 -1
- data/lib/command_kit/program_name.rb +7 -0
- data/lib/command_kit/stdio.rb +24 -0
- data/lib/command_kit/sudo.rb +40 -0
- data/lib/command_kit/terminal.rb +17 -0
- data/lib/command_kit/usage.rb +14 -0
- data/lib/command_kit/version.rb +1 -1
- data/lib/command_kit/xdg.rb +13 -0
- data/lib/command_kit.rb +1 -0
- data/spec/arguments/argument_spec.rb +2 -2
- data/spec/arguments_spec.rb +54 -28
- data/spec/colors_spec.rb +277 -13
- data/spec/command_name_spec.rb +1 -1
- data/spec/command_spec.rb +79 -5
- data/spec/commands/auto_load/subcommand_spec.rb +1 -1
- data/spec/commands/auto_load_spec.rb +34 -3
- data/spec/commands/auto_require_spec.rb +2 -2
- data/spec/commands/help_spec.rb +1 -1
- data/spec/commands/parent_command_spec.rb +1 -1
- data/spec/commands/subcommand_spec.rb +1 -1
- data/spec/commands_spec.rb +102 -30
- data/spec/description_spec.rb +1 -25
- data/spec/env/home_spec.rb +1 -1
- data/spec/env/path_spec.rb +7 -1
- data/spec/examples_spec.rb +1 -25
- data/spec/exception_handler_spec.rb +1 -1
- data/spec/help/man_spec.rb +55 -58
- data/spec/help_spec.rb +0 -25
- data/spec/inflector_spec.rb +71 -9
- data/spec/main_spec.rb +7 -7
- data/spec/man_spec.rb +46 -0
- data/spec/open_app_spec.rb +85 -0
- data/spec/options/option_spec.rb +5 -5
- data/spec/options/option_value_spec.rb +56 -1
- data/spec/options_spec.rb +283 -1
- data/spec/os/linux_spec.rb +164 -0
- data/spec/os_spec.rb +201 -14
- data/spec/package_manager_spec.rb +806 -0
- data/spec/pager_spec.rb +72 -7
- data/spec/printing/indent_spec.rb +8 -6
- data/spec/printing_spec.rb +33 -3
- data/spec/program_name_spec.rb +1 -1
- data/spec/spec_helper.rb +0 -3
- data/spec/sudo_spec.rb +51 -0
- data/spec/terminal_spec.rb +31 -1
- data/spec/usage_spec.rb +2 -2
- data/spec/xdg_spec.rb +1 -1
- metadata +21 -5
data/spec/inflector_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'command_kit/inflector'
|
3
3
|
|
4
|
-
describe Inflector do
|
4
|
+
describe CommandKit::Inflector do
|
5
5
|
describe ".demodularize" do
|
6
6
|
context "when given a single class or module name" do
|
7
7
|
let(:name) { 'Foo' }
|
@@ -28,6 +28,10 @@ describe Inflector do
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
ascii = (0..255).map(&:chr)
|
32
|
+
alpha = ('a'..'z').to_a + ('A'..'Z').to_a
|
33
|
+
numeric = ('0'..'9').to_a
|
34
|
+
|
31
35
|
describe ".underscore" do
|
32
36
|
it "must convert CamelCase to camel_case" do
|
33
37
|
expect(subject.underscore('CamelCase')).to eq('camel_case')
|
@@ -37,18 +41,48 @@ describe Inflector do
|
|
37
41
|
expect(subject.underscore('camelCase')).to eq('camel_case')
|
38
42
|
end
|
39
43
|
|
40
|
-
it "must convert
|
41
|
-
expect(subject.underscore('
|
44
|
+
it "must convert Camelcase to camelcase" do
|
45
|
+
expect(subject.underscore('Camelcase')).to eq('camelcase')
|
42
46
|
end
|
43
47
|
|
44
|
-
it "must convert
|
45
|
-
expect(subject.underscore('
|
48
|
+
it "must convert CAMELCASE to camelcase" do
|
49
|
+
expect(subject.underscore('CAMELCASE')).to eq('camelcase')
|
46
50
|
end
|
47
51
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
+
it "must convert CAMELCase to camel_case" do
|
53
|
+
expect(subject.underscore('CAMELCase')).to eq('camel_case')
|
54
|
+
end
|
55
|
+
|
56
|
+
it "must convert CamelCASE to camel_case" do
|
57
|
+
expect(subject.underscore('CAMELCase')).to eq('camel_case')
|
58
|
+
end
|
59
|
+
|
60
|
+
it "must convert FooBARBaz to foo_bar_baz" do
|
61
|
+
expect(subject.underscore('FooBARBaz')).to eq('foo_bar_baz')
|
62
|
+
end
|
63
|
+
|
64
|
+
it "must convert foo_bar_baz to foo_bar_baz" do
|
65
|
+
expect(subject.underscore('foo_bar_baz')).to eq('foo_bar_baz')
|
66
|
+
end
|
67
|
+
|
68
|
+
it "must convert foo___bar___baz to foo___bar___baz" do
|
69
|
+
expect(subject.underscore('foo___bar___baz')).to eq('foo___bar___baz')
|
70
|
+
end
|
71
|
+
|
72
|
+
it "must convert foo-bar-baz to foo_bar_baz" do
|
73
|
+
expect(subject.underscore('foo-bar-baz')).to eq('foo_bar_baz')
|
74
|
+
end
|
75
|
+
|
76
|
+
it "must convert foo---bar---baz to foo___bar___baz" do
|
77
|
+
expect(subject.underscore('foo---bar---baz')).to eq('foo___bar___baz')
|
78
|
+
end
|
79
|
+
|
80
|
+
it "must convert foo_BAR_baz to foo_bar_baz" do
|
81
|
+
expect(subject.underscore('foo_BAR_baz')).to eq('foo_bar_baz')
|
82
|
+
end
|
83
|
+
|
84
|
+
it "must convert foo-BAR-baz to foo_bar_baz" do
|
85
|
+
expect(subject.underscore('foo-BAR-baz')).to eq('foo_bar_baz')
|
52
86
|
end
|
53
87
|
|
54
88
|
context "when given a non-String" do
|
@@ -56,6 +90,20 @@ describe Inflector do
|
|
56
90
|
expect(subject.underscore(:CamelCase)).to eq('camel_case')
|
57
91
|
end
|
58
92
|
end
|
93
|
+
|
94
|
+
separators = %w[_ -]
|
95
|
+
|
96
|
+
(ascii - alpha - numeric - separators).each do |char|
|
97
|
+
context "when the given String contains a #{char.inspect} character" do
|
98
|
+
let(:string) { "Foo#{char}Bar" }
|
99
|
+
|
100
|
+
it do
|
101
|
+
expect {
|
102
|
+
subject.underscore(string)
|
103
|
+
}.to raise_error(ArgumentError,"cannot convert string to underscored: #{string.inspect}")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
59
107
|
end
|
60
108
|
|
61
109
|
describe ".dasherize" do
|
@@ -100,5 +148,19 @@ describe Inflector do
|
|
100
148
|
expect(subject.camelize(:foo_bar)).to eq('FooBar')
|
101
149
|
end
|
102
150
|
end
|
151
|
+
|
152
|
+
separators = %w[_ - /]
|
153
|
+
|
154
|
+
(ascii - alpha - numeric - separators).each do |char|
|
155
|
+
context "when the given String contains a #{char.inspect} character" do
|
156
|
+
let(:string) { "foo#{char}bar" }
|
157
|
+
|
158
|
+
it do
|
159
|
+
expect {
|
160
|
+
subject.camelize(string)
|
161
|
+
}.to raise_error(ArgumentError,"cannot convert string to CamelCase: #{string.inspect}")
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
103
165
|
end
|
104
166
|
end
|
data/spec/main_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'command_kit/main'
|
3
3
|
|
4
|
-
describe Main do
|
4
|
+
describe CommandKit::Main do
|
5
5
|
module TestMain
|
6
6
|
class TestCommand
|
7
7
|
include CommandKit::Main
|
@@ -156,16 +156,16 @@ describe Main do
|
|
156
156
|
describe "#main" do
|
157
157
|
subject { command_class.new }
|
158
158
|
|
159
|
-
it "must provide a default #main" do
|
160
|
-
expect(subject).to respond_to(:main)
|
161
|
-
end
|
162
|
-
|
163
159
|
it "must return 0 by default" do
|
164
160
|
expect(subject.main).to eq(0)
|
165
161
|
end
|
166
162
|
|
167
|
-
it "must
|
168
|
-
|
163
|
+
it "must call #run with the given argv" do
|
164
|
+
argv = ["foo", "bar", "baz"]
|
165
|
+
|
166
|
+
expect(subject).to receive(:run).with(*argv)
|
167
|
+
|
168
|
+
subject.main(argv)
|
169
169
|
end
|
170
170
|
|
171
171
|
context "when #run raises SystemExit" do
|
data/spec/man_spec.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'command_kit/man'
|
3
|
+
|
4
|
+
describe CommandKit::Man do
|
5
|
+
module TestMan
|
6
|
+
class TestCommand
|
7
|
+
include CommandKit::Man
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:command_class) { TestMan::TestCommand }
|
12
|
+
|
13
|
+
subject { command_class.new }
|
14
|
+
|
15
|
+
describe "#man" do
|
16
|
+
let(:man_page) { 'foo' }
|
17
|
+
|
18
|
+
it "must call system() with the given man page" do
|
19
|
+
expect(subject).to receive(:system).with('man',man_page)
|
20
|
+
|
21
|
+
subject.man(man_page)
|
22
|
+
end
|
23
|
+
|
24
|
+
context "when given a non-String man-page argument" do
|
25
|
+
let(:man_page_arg) { double(:non_string_arg) }
|
26
|
+
|
27
|
+
it "must call #to_s on the man-page argument" do
|
28
|
+
expect(man_page_arg).to receive(:to_s).and_return(man_page)
|
29
|
+
|
30
|
+
expect(subject).to receive(:system).with('man',man_page)
|
31
|
+
|
32
|
+
subject.man(man_page_arg)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when given the section: keyword argument" do
|
37
|
+
let(:section) { 7 }
|
38
|
+
|
39
|
+
it "must call system() with the given section number and man page" do
|
40
|
+
expect(subject).to receive(:system).with('man',section.to_s,man_page)
|
41
|
+
|
42
|
+
subject.man(man_page, section: section)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'command_kit/open_app'
|
3
|
+
|
4
|
+
describe CommandKit::OpenApp do
|
5
|
+
module TestOpenApp
|
6
|
+
class TestCommand
|
7
|
+
include CommandKit::OpenApp
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:command_class) { TestOpenApp::TestCommand }
|
12
|
+
|
13
|
+
subject { command_class.new }
|
14
|
+
|
15
|
+
describe "#initialize" do
|
16
|
+
context "when the OS is macOS" do
|
17
|
+
subject { command_class.new(os: :macos) }
|
18
|
+
|
19
|
+
it "must set @open_command to \"open\"" do
|
20
|
+
expect(subject.instance_variable_get("@open_command")).to eq("open")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "when the OS is Linux" do
|
25
|
+
subject { command_class.new(os: :linux) }
|
26
|
+
|
27
|
+
it "must set @open_command to \"xdg-open\"" do
|
28
|
+
expect(subject.instance_variable_get("@open_command")).to eq("xdg-open")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when the OS is FreeBSD" do
|
33
|
+
subject { command_class.new(os: :freebsd) }
|
34
|
+
|
35
|
+
it "must set @open_command to \"xdg-open\"" do
|
36
|
+
expect(subject.instance_variable_get("@open_command")).to eq("xdg-open")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when the OS is OpenBSD" do
|
41
|
+
subject { command_class.new(os: :openbsd) }
|
42
|
+
|
43
|
+
it "must set @open_command to \"xdg-open\"" do
|
44
|
+
expect(subject.instance_variable_get("@open_command")).to eq("xdg-open")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when the OS is NetBSD" do
|
49
|
+
subject { command_class.new(os: :openbsd) }
|
50
|
+
|
51
|
+
it "must set @open_command to \"xdg-open\"" do
|
52
|
+
expect(subject.instance_variable_get("@open_command")).to eq("xdg-open")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "when the OS is Windows" do
|
57
|
+
subject { command_class.new(os: :windows) }
|
58
|
+
|
59
|
+
it "must set @open_command to \"start\"" do
|
60
|
+
expect(subject.instance_variable_get("@open_command")).to eq("start")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#open_app_for" do
|
66
|
+
context "when @open_command is set" do
|
67
|
+
let(:file_or_uri) { "foo" }
|
68
|
+
let(:status) { true }
|
69
|
+
|
70
|
+
it "must execute the @open_command with the given URI or file" do
|
71
|
+
expect(subject).to receive(:system).with(subject.instance_variable_get("@open_command"),file_or_uri).and_return(status)
|
72
|
+
|
73
|
+
expect(subject.open_app_for(file_or_uri)).to be(status)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context "when @open_command is not set" do
|
78
|
+
before do
|
79
|
+
subject.instance_variable_set("@open_command",nil)
|
80
|
+
end
|
81
|
+
|
82
|
+
it { expect(subject.open_app_for("foo")).to be(nil) }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/spec/options/option_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'command_kit/options/option'
|
3
3
|
|
4
|
-
describe Options::Option do
|
4
|
+
describe CommandKit::Options::Option do
|
5
5
|
let(:name) { :foo }
|
6
6
|
let(:short) { nil }
|
7
7
|
let(:long) { '--foo' }
|
@@ -18,12 +18,12 @@ describe Options::Option do
|
|
18
18
|
end
|
19
19
|
|
20
20
|
subject do
|
21
|
-
described_class.new
|
21
|
+
described_class.new(name, short: short,
|
22
22
|
long: long,
|
23
23
|
equals: equals,
|
24
24
|
desc: desc,
|
25
25
|
value: value,
|
26
|
-
&block
|
26
|
+
&block)
|
27
27
|
end
|
28
28
|
|
29
29
|
describe "#initialize" do
|
@@ -82,7 +82,7 @@ describe Options::Option do
|
|
82
82
|
subject { described_class.new(name, value: {type: type}, desc: desc) }
|
83
83
|
|
84
84
|
it "must initialize #value" do
|
85
|
-
expect(subject.value).to be_kind_of(Options::OptionValue)
|
85
|
+
expect(subject.value).to be_kind_of(CommandKit::Options::OptionValue)
|
86
86
|
expect(subject.value.type).to eq(type)
|
87
87
|
end
|
88
88
|
end
|
@@ -91,7 +91,7 @@ describe Options::Option do
|
|
91
91
|
subject { described_class.new(name, value: true, desc: desc) }
|
92
92
|
|
93
93
|
it "must initialize #value with defaults" do
|
94
|
-
expect(subject.value).to be_kind_of(Options::OptionValue)
|
94
|
+
expect(subject.value).to be_kind_of(CommandKit::Options::OptionValue)
|
95
95
|
expect(subject.value.type).to eq(String)
|
96
96
|
expect(subject.value.required?).to be(true)
|
97
97
|
expect(subject.value.usage).to eq('STR')
|
@@ -1,12 +1,67 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'command_kit/options/option_value'
|
3
3
|
|
4
|
-
describe Options::OptionValue do
|
4
|
+
describe CommandKit::Options::OptionValue do
|
5
5
|
let(:type) { Integer }
|
6
6
|
let(:usage) { 'COUNT' }
|
7
7
|
let(:required) { true }
|
8
8
|
let(:default) { 1 }
|
9
9
|
|
10
|
+
describe ".default_usage" do
|
11
|
+
subject { described_class }
|
12
|
+
|
13
|
+
context "when given a Hash" do
|
14
|
+
let(:type) do
|
15
|
+
{'foo' => :foo, "bar" => :bar}
|
16
|
+
end
|
17
|
+
|
18
|
+
it "must join the Hash's keys with a '|' character" do
|
19
|
+
expect(subject.default_usage(type)).to eq(type.keys.join('|'))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when given an Array" do
|
24
|
+
let(:type) do
|
25
|
+
['foo', 'bar', 'baz']
|
26
|
+
end
|
27
|
+
|
28
|
+
it "must join the Array's elements with a '|' character" do
|
29
|
+
expect(subject.default_usage(type)).to eq(type.join('|'))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "when given a Regexp" do
|
34
|
+
let(:type) { /[0-9a-f]+/ }
|
35
|
+
|
36
|
+
it "must return the Regexp's source" do
|
37
|
+
expect(subject.default_usage(type)).to eq(type.source)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "when given a Class" do
|
42
|
+
module TestOptionValue
|
43
|
+
class FooBarBaz
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
let(:type) { TestOptionValue::FooBarBaz }
|
48
|
+
|
49
|
+
it "must return the uppercase and underscored version of it's name" do
|
50
|
+
expect(subject.default_usage(type)).to eq("FOO_BAR_BAZ")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when given another kind of Object" do
|
55
|
+
let(:type) { Object.new }
|
56
|
+
|
57
|
+
it do
|
58
|
+
expect {
|
59
|
+
subject.default_usage(type)
|
60
|
+
}.to raise_error(TypeError,"unsupported option type: #{type.inspect}")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
10
65
|
describe "#initialize" do
|
11
66
|
context "when the type: keyword is given" do
|
12
67
|
let(:type) { Integer }
|
data/spec/options_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'command_kit/options'
|
3
3
|
|
4
|
-
describe Options do
|
4
|
+
describe CommandKit::Options do
|
5
5
|
module TestOptions
|
6
6
|
class ImplicitCmd
|
7
7
|
include CommandKit::Options
|
@@ -133,5 +133,287 @@ describe 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
|