command_kit 0.1.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +3 -0
- data/.github/workflows/ruby.yml +29 -0
- data/.gitignore +7 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +29 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +20 -0
- data/README.md +283 -0
- data/Rakefile +23 -0
- data/command_kit.gemspec +60 -0
- data/gemspec.yml +14 -0
- data/lib/command_kit.rb +1 -0
- data/lib/command_kit/arguments.rb +161 -0
- data/lib/command_kit/arguments/argument.rb +111 -0
- data/lib/command_kit/arguments/argument_value.rb +81 -0
- data/lib/command_kit/arguments/usage.rb +6 -0
- data/lib/command_kit/colors.rb +355 -0
- data/lib/command_kit/command.rb +42 -0
- data/lib/command_kit/command_name.rb +95 -0
- data/lib/command_kit/commands.rb +299 -0
- data/lib/command_kit/commands/auto_load.rb +153 -0
- data/lib/command_kit/commands/auto_load/subcommand.rb +90 -0
- data/lib/command_kit/commands/auto_require.rb +138 -0
- data/lib/command_kit/commands/command.rb +12 -0
- data/lib/command_kit/commands/help.rb +43 -0
- data/lib/command_kit/commands/parent_command.rb +21 -0
- data/lib/command_kit/commands/subcommand.rb +51 -0
- data/lib/command_kit/console.rb +141 -0
- data/lib/command_kit/description.rb +89 -0
- data/lib/command_kit/env.rb +43 -0
- data/lib/command_kit/env/home.rb +71 -0
- data/lib/command_kit/env/path.rb +71 -0
- data/lib/command_kit/examples.rb +99 -0
- data/lib/command_kit/exception_handler.rb +55 -0
- data/lib/command_kit/help.rb +62 -0
- data/lib/command_kit/help/man.rb +125 -0
- data/lib/command_kit/inflector.rb +84 -0
- data/lib/command_kit/main.rb +103 -0
- data/lib/command_kit/options.rb +179 -0
- data/lib/command_kit/options/option.rb +171 -0
- data/lib/command_kit/options/option_value.rb +90 -0
- data/lib/command_kit/options/parser.rb +227 -0
- data/lib/command_kit/options/quiet.rb +53 -0
- data/lib/command_kit/options/usage.rb +6 -0
- data/lib/command_kit/options/verbose.rb +55 -0
- data/lib/command_kit/options/version.rb +62 -0
- data/lib/command_kit/os.rb +47 -0
- data/lib/command_kit/pager.rb +115 -0
- data/lib/command_kit/printing.rb +32 -0
- data/lib/command_kit/printing/indent.rb +78 -0
- data/lib/command_kit/program_name.rb +57 -0
- data/lib/command_kit/stdio.rb +138 -0
- data/lib/command_kit/usage.rb +102 -0
- data/lib/command_kit/version.rb +4 -0
- data/lib/command_kit/xdg.rb +138 -0
- data/spec/arguments/argument_spec.rb +169 -0
- data/spec/arguments/argument_value_spec.rb +126 -0
- data/spec/arguments_spec.rb +213 -0
- data/spec/colors_spec.rb +470 -0
- data/spec/command_kit_spec.rb +8 -0
- data/spec/command_name_spec.rb +130 -0
- data/spec/command_spec.rb +49 -0
- data/spec/commands/auto_load/subcommand_spec.rb +82 -0
- data/spec/commands/auto_load_spec.rb +128 -0
- data/spec/commands/auto_require_spec.rb +142 -0
- data/spec/commands/fixtures/test_auto_load/cli/commands/test1.rb +10 -0
- data/spec/commands/fixtures/test_auto_load/cli/commands/test2.rb +10 -0
- data/spec/commands/fixtures/test_auto_require/lib/test_auto_require/cli/commands/test1.rb +10 -0
- data/spec/commands/help_spec.rb +66 -0
- data/spec/commands/parent_command_spec.rb +40 -0
- data/spec/commands/subcommand_spec.rb +99 -0
- data/spec/commands_spec.rb +767 -0
- data/spec/console_spec.rb +201 -0
- data/spec/description_spec.rb +203 -0
- data/spec/env/home_spec.rb +46 -0
- data/spec/env/path_spec.rb +78 -0
- data/spec/env_spec.rb +123 -0
- data/spec/examples_spec.rb +235 -0
- data/spec/exception_handler_spec.rb +103 -0
- data/spec/help_spec.rb +119 -0
- data/spec/inflector_spec.rb +104 -0
- data/spec/main_spec.rb +179 -0
- data/spec/options/option_spec.rb +258 -0
- data/spec/options/option_value_spec.rb +67 -0
- data/spec/options/parser_spec.rb +265 -0
- data/spec/options_spec.rb +137 -0
- data/spec/os_spec.rb +46 -0
- data/spec/pager_spec.rb +154 -0
- data/spec/printing/indent_spec.rb +130 -0
- data/spec/printing_spec.rb +76 -0
- data/spec/program_name_spec.rb +62 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/stdio_spec.rb +264 -0
- data/spec/usage_spec.rb +237 -0
- data/spec/xdg_spec.rb +191 -0
- metadata +156 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'command_kit/options/option_value'
|
3
|
+
|
4
|
+
describe Options::OptionValue do
|
5
|
+
let(:type) { Integer }
|
6
|
+
let(:usage) { 'COUNT' }
|
7
|
+
let(:required) { true }
|
8
|
+
let(:default) { 1 }
|
9
|
+
|
10
|
+
describe "#initialize" do
|
11
|
+
context "when the type: keyword is given" do
|
12
|
+
let(:type) { Integer }
|
13
|
+
|
14
|
+
subject { described_class.new(type: type) }
|
15
|
+
|
16
|
+
it "must default #type to String" do
|
17
|
+
expect(subject.type).to eq(type)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "when the type: keyword is not given" do
|
22
|
+
subject { described_class.new }
|
23
|
+
|
24
|
+
it "must default #type to String" do
|
25
|
+
expect(subject.type).to eq(String)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when the usage: keyword is given" do
|
30
|
+
let(:usage) { 'FOO' }
|
31
|
+
|
32
|
+
subject { described_class.new(usage: usage) }
|
33
|
+
|
34
|
+
it "must default #usage to String" do
|
35
|
+
expect(subject.usage).to eq(usage)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "when the usage: keyword is not given" do
|
40
|
+
subject { described_class.new }
|
41
|
+
|
42
|
+
it "must default #usage based on #type" do
|
43
|
+
expect(subject.usage).to eq(described_class.default_usage(subject.type))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#usage" do
|
49
|
+
let(:usage) { 'FOO' }
|
50
|
+
|
51
|
+
context "when #optional? is true" do
|
52
|
+
subject { described_class.new(usage: usage, required: false) }
|
53
|
+
|
54
|
+
it "must wrap the usage within [ ] brackets" do
|
55
|
+
expect(subject.usage).to eq("[#{usage}]")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when #optional? is false" do
|
60
|
+
subject { described_class.new(usage: usage, required: true) }
|
61
|
+
|
62
|
+
it "should return the usage string unchanged" do
|
63
|
+
expect(subject.usage).to eq(usage)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,265 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'command_kit/options/parser'
|
3
|
+
|
4
|
+
describe CommandKit::Options::Parser do
|
5
|
+
module TestOptionsParser
|
6
|
+
class TestCommand
|
7
|
+
include CommandKit::Options::Parser
|
8
|
+
|
9
|
+
command_name 'cmd'
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:command_class) { TestOptionsParser::TestCommand }
|
15
|
+
|
16
|
+
describe ".included" do
|
17
|
+
subject { command_class }
|
18
|
+
|
19
|
+
it { expect(subject).to include(CommandKit::Main) }
|
20
|
+
it { expect(subject).to include(CommandKit::Usage) }
|
21
|
+
it { expect(subject.usage).to eq('[options]') }
|
22
|
+
end
|
23
|
+
|
24
|
+
subject { command_class.new }
|
25
|
+
|
26
|
+
describe "#initialize" do
|
27
|
+
it "must initialize #option_parser" do
|
28
|
+
expect(subject.option_parser).to be_kind_of(OptionParser)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#option_parser" do
|
33
|
+
it "must have a default #banner" do
|
34
|
+
expect(subject.option_parser.banner).to eq("Usage: #{subject.usage}")
|
35
|
+
end
|
36
|
+
|
37
|
+
it "must include a 'Options:' separator" do
|
38
|
+
expect(subject.option_parser.to_s).to include(
|
39
|
+
[
|
40
|
+
'',
|
41
|
+
'Options:',
|
42
|
+
''
|
43
|
+
].join($/)
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "must define a default --help option" do
|
48
|
+
expect(subject.option_parser.to_s).to include(
|
49
|
+
[
|
50
|
+
'',
|
51
|
+
' -h, --help Print help information',
|
52
|
+
''
|
53
|
+
].join($/)
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
module TestOptionsParser
|
59
|
+
class CommandWithOptions
|
60
|
+
|
61
|
+
include CommandKit::Options::Parser
|
62
|
+
|
63
|
+
command_name 'cmd'
|
64
|
+
|
65
|
+
attr_reader :foo
|
66
|
+
|
67
|
+
attr_reader :bar
|
68
|
+
|
69
|
+
attr_reader :argv
|
70
|
+
|
71
|
+
def initialize(**kwargs)
|
72
|
+
super(**kwargs)
|
73
|
+
|
74
|
+
@option_parser.on('-f','--foo','Foo option') do
|
75
|
+
@foo = true
|
76
|
+
end
|
77
|
+
|
78
|
+
@option_parser.on('-b','--bar BAR',Integer,'Bar option') do |bar|
|
79
|
+
@bar = bar
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def run(*argv)
|
84
|
+
@argv = argv
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
let(:command_class) { TestOptionsParser::CommandWithOptions }
|
91
|
+
subject { command_class.new }
|
92
|
+
|
93
|
+
describe "#option_parser" do
|
94
|
+
it { expect(subject.option_parser).to be_kind_of(OptionParser) }
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "#main" do
|
98
|
+
context "when --help is given as an argument" do
|
99
|
+
it "must call #help" do
|
100
|
+
expect(subject).to receive(:help)
|
101
|
+
|
102
|
+
subject.main(['--help'])
|
103
|
+
end
|
104
|
+
|
105
|
+
it "must return 0" do
|
106
|
+
allow(subject).to receive(:help)
|
107
|
+
|
108
|
+
expect(subject.main(['--help'])).to eq(0)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "must stop parsing options" do
|
112
|
+
allow(subject).to receive(:help)
|
113
|
+
subject.main(['--help', '--foo', '1'])
|
114
|
+
|
115
|
+
expect(subject.foo).to be(nil)
|
116
|
+
expect(subject.argv).to be(nil)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe "#parse_options" do
|
122
|
+
it "must parse options and return any additional arguments" do
|
123
|
+
additional_args = %w[arg1 arg2]
|
124
|
+
bar = 2
|
125
|
+
argv = ['--foo', '--bar', bar.to_s, *additional_args]
|
126
|
+
|
127
|
+
expect(subject.parse_options(argv)).to eq(additional_args)
|
128
|
+
expect(subject.foo).to eq(true)
|
129
|
+
expect(subject.bar).to eq(bar)
|
130
|
+
end
|
131
|
+
|
132
|
+
context "when -h,--help is passed" do
|
133
|
+
it "must call #help and exit with 0" do
|
134
|
+
expect(subject).to receive(:help)
|
135
|
+
expect(subject).to receive(:exit).with(0)
|
136
|
+
|
137
|
+
subject.parse_options(['--help'])
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context "when an invalid option is given" do
|
142
|
+
it "must call #on_invalid_option" do
|
143
|
+
expect(subject).to receive(:on_invalid_option).with(OptionParser::InvalidOption)
|
144
|
+
|
145
|
+
subject.parse_options(['--xxx'])
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context "when an invalid argument is given" do
|
150
|
+
it "must call #on_invalid_argument" do
|
151
|
+
expect(subject).to receive(:on_invalid_argument).with(OptionParser::InvalidArgument)
|
152
|
+
|
153
|
+
subject.parse_options(['--bar', 'xxx'])
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
context "when a required argument is missing" do
|
158
|
+
it "must call #on_missing_argument" do
|
159
|
+
expect(subject).to receive(:on_missing_argument).with(OptionParser::MissingArgument)
|
160
|
+
|
161
|
+
subject.parse_options(['--bar'])
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
context "when a needless argument is given" do
|
166
|
+
it "must call #on_needless_argument" do
|
167
|
+
expect(subject).to receive(:on_needless_argument).with(OptionParser::NeedlessArgument)
|
168
|
+
|
169
|
+
subject.parse_options(['--foo=xxx'])
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "#on_parse_error" do
|
175
|
+
let(:error) { OptionParser::InvalidOption.new("--xxx") }
|
176
|
+
|
177
|
+
it "must print an error message and exit with 1" do
|
178
|
+
expect(subject).to receive(:exit).with(1)
|
179
|
+
|
180
|
+
expect { subject.on_parse_error(error) }.to output(
|
181
|
+
[
|
182
|
+
"#{subject.command_name}: #{error.message}",
|
183
|
+
"Try '#{subject.command_name} --help' for more information.",
|
184
|
+
''
|
185
|
+
].join($/)
|
186
|
+
).to_stderr
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
describe "#on_invalid_option" do
|
191
|
+
let(:error) { OptionParser::InvalidOption.new('--xxx') }
|
192
|
+
|
193
|
+
it "must call #on_parse_error by default" do
|
194
|
+
expect(subject).to receive(:on_parse_error).with(error)
|
195
|
+
|
196
|
+
subject.on_invalid_option(error)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe "#on_ambiguous_option" do
|
201
|
+
let(:error) { OptionParser::AmbiguousOption.new('--xxx') }
|
202
|
+
|
203
|
+
it "must call #on_parse_error by default" do
|
204
|
+
expect(subject).to receive(:on_parse_error).with(error)
|
205
|
+
|
206
|
+
subject.on_ambiguous_option(error)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
describe "#on_invalid_argument" do
|
211
|
+
let(:error) { OptionParser::InvalidArgument.new('--xxx') }
|
212
|
+
|
213
|
+
it "must call #on_parse_error by default" do
|
214
|
+
expect(subject).to receive(:on_parse_error).with(error)
|
215
|
+
|
216
|
+
subject.on_invalid_argument(error)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
describe "#on_missing_argument" do
|
221
|
+
let(:error) { OptionParser::MissingArgument.new('--xxx') }
|
222
|
+
|
223
|
+
it "must call #on_parse_error by default" do
|
224
|
+
expect(subject).to receive(:on_parse_error).with(error)
|
225
|
+
|
226
|
+
subject.on_missing_argument(error)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
describe "#on_needless_argument" do
|
231
|
+
let(:error) { OptionParser::NeedlessArgument.new('--xxx') }
|
232
|
+
|
233
|
+
it "must call #on_parse_error by default" do
|
234
|
+
expect(subject).to receive(:on_parse_error).with(error)
|
235
|
+
|
236
|
+
subject.on_needless_argument(error)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
describe "#on_ambiguous_argument" do
|
241
|
+
let(:error) { OptionParser::AmbiguousArgument.new('--xxx') }
|
242
|
+
|
243
|
+
it "must call #on_parse_error by default" do
|
244
|
+
expect(subject).to receive(:on_parse_error).with(error)
|
245
|
+
|
246
|
+
subject.on_ambiguous_argument(error)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
describe "#help_options" do
|
251
|
+
it "must print the #option_parser" do
|
252
|
+
expect { subject.help_options }.to output(
|
253
|
+
subject.option_parser.to_s
|
254
|
+
).to_stdout
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
describe "#help" do
|
259
|
+
it "must call #help_options" do
|
260
|
+
expect(subject).to receive(:help_options)
|
261
|
+
|
262
|
+
subject.help
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'command_kit/options'
|
3
|
+
|
4
|
+
describe Options do
|
5
|
+
module TestOptions
|
6
|
+
class ImplicitCmd
|
7
|
+
include CommandKit::Options
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:command_class) { TestOptions::ImplicitCmd }
|
12
|
+
subject { command_class.new }
|
13
|
+
|
14
|
+
describe ".options" do
|
15
|
+
subject { TestOptions::ImplicitCmd }
|
16
|
+
|
17
|
+
context "when no options have been defined" do
|
18
|
+
it "should default to {}" do
|
19
|
+
expect(subject.options).to eq({})
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when a options is explicitly set" do
|
24
|
+
module TestOptions
|
25
|
+
class ExplicitCmd
|
26
|
+
include CommandKit::Options
|
27
|
+
option :foo, desc: 'Foo option'
|
28
|
+
option :bar, desc: 'Bar option'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
subject { TestOptions::ExplicitCmd }
|
33
|
+
|
34
|
+
it "must return the explicitly set options" do
|
35
|
+
expect(subject.options.keys).to eq([:foo, :bar])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "when the command class inherites from another class" do
|
40
|
+
context "but no options are defined" do
|
41
|
+
module TestOptions
|
42
|
+
class BaseCmd
|
43
|
+
include CommandKit::Options
|
44
|
+
end
|
45
|
+
|
46
|
+
class InheritedCmd < BaseCmd
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
subject { TestOptions::InheritedCmd }
|
51
|
+
|
52
|
+
it "must search each class then return {}"do
|
53
|
+
expect(subject.options).to eq({})
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
module TestOptions
|
58
|
+
class ExplicitBaseCmd
|
59
|
+
include CommandKit::Options
|
60
|
+
option :foo, desc: 'Foo option'
|
61
|
+
option :bar, desc: 'Bar option'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when the superclass defines options" do
|
66
|
+
module TestOptions
|
67
|
+
class ImplicitInheritedCmd < ExplicitBaseCmd
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
let(:super_subject) { TestOptions::ExplicitBaseCmd }
|
72
|
+
subject { TestOptions::ImplicitInheritedCmd }
|
73
|
+
|
74
|
+
it "must inherit the superclass'es options" do
|
75
|
+
expect(subject.options).to eq(super_subject.options)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "must not change the superclass'es options" do
|
79
|
+
expect(super_subject.options.keys).to eq([:foo, :bar])
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "when the subclass defines options" do
|
84
|
+
module TestOptions
|
85
|
+
class ImplicitBaseCmd
|
86
|
+
include CommandKit::Options
|
87
|
+
end
|
88
|
+
|
89
|
+
class ExplicitInheritedCmd < ImplicitBaseCmd
|
90
|
+
option :baz, desc: 'Baz option'
|
91
|
+
option :qux, desc: 'Qux option'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
let(:super_subject) { TestOptions::ImplicitBaseCmd }
|
96
|
+
subject { TestOptions::ExplicitInheritedCmd }
|
97
|
+
|
98
|
+
it "must return the subclass'es options" do
|
99
|
+
expect(subject.options.keys).to eq([:baz, :qux])
|
100
|
+
end
|
101
|
+
|
102
|
+
it "must not change the superclass'es options" do
|
103
|
+
expect(super_subject.options).to eq({})
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context "when subclass overrides the superclass's optionss" do
|
108
|
+
module TestOptions
|
109
|
+
class ExplicitOverridingInheritedCmd < ExplicitBaseCmd
|
110
|
+
option :foo, desc: "Overriden foo option"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
let(:super_subject) { TestOptions::ExplicitBaseCmd }
|
115
|
+
subject { TestOptions::ExplicitOverridingInheritedCmd }
|
116
|
+
|
117
|
+
it "must combine the superclass'es options with the subclass'es" do
|
118
|
+
expect(subject.options.keys).to eq([:foo, :bar])
|
119
|
+
expect(subject.options[:foo].desc).to eq("Overriden foo option")
|
120
|
+
expect(subject.options[:bar].desc).to eq("Bar option")
|
121
|
+
end
|
122
|
+
|
123
|
+
it "must not change the superclass'es options" do
|
124
|
+
expect(super_subject.options.keys).to eq([:foo, :bar])
|
125
|
+
expect(super_subject.options[:foo].desc).to eq("Foo option")
|
126
|
+
expect(super_subject.options[:bar].desc).to eq("Bar option")
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe "#initialize" do
|
133
|
+
it "must initialize #options" do
|
134
|
+
expect(subject.options).to eq({})
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|