command_kit 0.1.0.pre1
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 +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
data/spec/help_spec.rb
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'command_kit/help'
|
|
3
|
+
|
|
4
|
+
describe CommandKit::Help do
|
|
5
|
+
module TestHelp
|
|
6
|
+
class DefaultCmd
|
|
7
|
+
include CommandKit::Help
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class TestCommandWithInitialize
|
|
11
|
+
include CommandKit::Help
|
|
12
|
+
|
|
13
|
+
attr_reader :foo
|
|
14
|
+
|
|
15
|
+
attr_reader :bar
|
|
16
|
+
|
|
17
|
+
def initialize(foo: 'foo', bar: 'bar', **kwargs)
|
|
18
|
+
super(**kwargs)
|
|
19
|
+
|
|
20
|
+
@foo = foo
|
|
21
|
+
@bar = bar
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
let(:command_class) { TestHelp::TestCmd }
|
|
27
|
+
|
|
28
|
+
describe ".help" do
|
|
29
|
+
subject { command_class }
|
|
30
|
+
|
|
31
|
+
context "when no #initialize method is defined" do
|
|
32
|
+
let(:command_class) { TestHelp::DefaultCmd }
|
|
33
|
+
let(:instance) { command_class.new }
|
|
34
|
+
|
|
35
|
+
it "must initialize the command object and call #help" do
|
|
36
|
+
expect(subject).to receive(:new).with(no_args).and_return(instance)
|
|
37
|
+
expect(instance).to receive(:help).with(no_args)
|
|
38
|
+
|
|
39
|
+
subject.help()
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
context "when an #initialize method is defined" do
|
|
44
|
+
let(:command_class) { TestHelp::TestCommandWithInitialize }
|
|
45
|
+
let(:instance) { command_class.new }
|
|
46
|
+
|
|
47
|
+
context "and given no arguments" do
|
|
48
|
+
it "must initialize the command object and call #help" do
|
|
49
|
+
expect(subject).to receive(:new).with(no_args).and_return(instance)
|
|
50
|
+
expect(instance).to receive(:help).with(no_args)
|
|
51
|
+
|
|
52
|
+
subject.help()
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
context "and given keyword arguments" do
|
|
57
|
+
let(:kwargs) { {foo: 'custom foo', bar: 'custom bar'} }
|
|
58
|
+
let(:instance) { command_class.new(**kwargs) }
|
|
59
|
+
|
|
60
|
+
it "must pass the keyword arguments .new then call #help" do
|
|
61
|
+
expect(subject).to receive(:new).with(**kwargs).and_return(instance)
|
|
62
|
+
expect(instance).to receive(:help).with(no_args)
|
|
63
|
+
|
|
64
|
+
subject.help(**kwargs)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
subject { command_class.new }
|
|
71
|
+
|
|
72
|
+
describe "#help" do
|
|
73
|
+
context "when there is no superclass #help method" do
|
|
74
|
+
module TestHelp
|
|
75
|
+
class SuperclassWithoutHelp
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
class SubclassOfSuperclassWithoutHelp < SuperclassWithoutHelp
|
|
79
|
+
include CommandKit::Help
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
let(:command_superclass) { TestHelp::SuperclassWithoutHelp }
|
|
84
|
+
let(:command_class) { TestHelp::SubclassOfSuperclassWithoutHelp }
|
|
85
|
+
|
|
86
|
+
it "must not attempt to call the superclass'es #help" do
|
|
87
|
+
allow_any_instance_of(command_class).to receive(:help)
|
|
88
|
+
expect_any_instance_of(command_superclass).to_not receive(:help)
|
|
89
|
+
|
|
90
|
+
subject.help()
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
context "when the superclass defines it's own #help method" do
|
|
95
|
+
module TestHelp
|
|
96
|
+
class SuperclassWithHelp
|
|
97
|
+
|
|
98
|
+
def help
|
|
99
|
+
puts 'superclass'
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
class SubclassOfSuperclassWithHelp < SuperclassWithHelp
|
|
105
|
+
include CommandKit::Help
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
let(:command_superclass) { TestHelp::SuperclassWithHelp }
|
|
110
|
+
let(:command_class) { TestHelp::SubclassOfSuperclassWithHelp }
|
|
111
|
+
|
|
112
|
+
it "must call the superclass'es #help" do
|
|
113
|
+
expect_any_instance_of(command_superclass).to receive(:help)
|
|
114
|
+
|
|
115
|
+
subject.help()
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'command_kit/inflector'
|
|
3
|
+
|
|
4
|
+
describe Inflector do
|
|
5
|
+
describe ".demodularize" do
|
|
6
|
+
context "when given a single class or module name" do
|
|
7
|
+
let(:name) { 'Foo' }
|
|
8
|
+
|
|
9
|
+
it "must return the class or module name unchanged" do
|
|
10
|
+
expect(subject.demodularize(name)).to eq(name)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
context "when given a class or module name with a leading namespace" do
|
|
15
|
+
let(:namespace) { 'Foo::Bar' }
|
|
16
|
+
let(:constant) { "Baz" }
|
|
17
|
+
let(:name) { "#{namespace}::#{constant}" }
|
|
18
|
+
|
|
19
|
+
it "must return the constant name, without the leading namespace" do
|
|
20
|
+
expect(subject.demodularize(name)).to eq(constant)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
context "when given a non-String" do
|
|
25
|
+
it "must convert it to a String" do
|
|
26
|
+
expect(subject.demodularize(:"Foo::Bar")).to eq('Bar')
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe ".underscore" do
|
|
32
|
+
it "must convert CamelCase to camel_case" do
|
|
33
|
+
expect(subject.underscore('CamelCase')).to eq('camel_case')
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "must convert camelCase to camel_case" do
|
|
37
|
+
expect(subject.underscore('camelCase')).to eq('camel_case')
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "must convert Camel to camel" do
|
|
41
|
+
expect(subject.underscore('Camel')).to eq('camel')
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "must convert CAMEL to camel" do
|
|
45
|
+
expect(subject.underscore('CAMEL')).to eq('camel')
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
context "when given a String containing '/' characters" do
|
|
49
|
+
it "must replace dashes with underscores" do
|
|
50
|
+
expect(subject.underscore('foo-bar')).to eq('foo_bar')
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context "when given a non-String" do
|
|
55
|
+
it "must convert it to a String" do
|
|
56
|
+
expect(subject.underscore(:CamelCase)).to eq('camel_case')
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
describe ".dasherize" do
|
|
62
|
+
it "must replace all underscores with dashes" do
|
|
63
|
+
expect(subject.dasherize("foo_bar")).to eq('foo-bar')
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
context "when given a non-String" do
|
|
67
|
+
it "must convert it to a String" do
|
|
68
|
+
expect(subject.dasherize(:foo_bar)).to eq('foo-bar')
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
describe ".camelize" do
|
|
74
|
+
context "when given a string with no underscores" do
|
|
75
|
+
it "must capitalize the string" do
|
|
76
|
+
expect(subject.camelize('foo')).to eq('Foo')
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
context "when given a string with underscores" do
|
|
81
|
+
it "must capitalize each word and remove all underscores" do
|
|
82
|
+
expect(subject.camelize('foo_bar')).to eq('FooBar')
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
context "when given a string with dashes" do
|
|
87
|
+
it "must capitalize each word and remove all dashes" do
|
|
88
|
+
expect(subject.camelize('foo-bar')).to eq('FooBar')
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
context "when given a string containing '/' characters" do
|
|
93
|
+
it "must replace the '/' characters with '::' strings" do
|
|
94
|
+
expect(subject.camelize('foo_bar/baz_quox')).to eq('FooBar::BazQuox')
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
context "when given a non-String" do
|
|
99
|
+
it "must convert it to a String" do
|
|
100
|
+
expect(subject.camelize(:foo_bar)).to eq('FooBar')
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
data/spec/main_spec.rb
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'command_kit/main'
|
|
3
|
+
|
|
4
|
+
describe Main do
|
|
5
|
+
module TestMain
|
|
6
|
+
class TestCommand
|
|
7
|
+
include CommandKit::Main
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class TestCommandWithInitialize
|
|
11
|
+
include CommandKit::Main
|
|
12
|
+
|
|
13
|
+
attr_reader :foo
|
|
14
|
+
|
|
15
|
+
attr_reader :bar
|
|
16
|
+
|
|
17
|
+
def initialize(foo: 'foo', bar: 'bar', **kwargs)
|
|
18
|
+
super(**kwargs)
|
|
19
|
+
|
|
20
|
+
@foo = foo
|
|
21
|
+
@bar = bar
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
let(:command_class) { TestMain::TestCommand }
|
|
27
|
+
|
|
28
|
+
describe ".start" do
|
|
29
|
+
subject { command_class }
|
|
30
|
+
|
|
31
|
+
it "must exit with 0 by default" do
|
|
32
|
+
expect(subject).to receive(:exit).with(0)
|
|
33
|
+
|
|
34
|
+
subject.start
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
context "when given an argv argument" do
|
|
38
|
+
let(:argv) { %w[one two three] }
|
|
39
|
+
|
|
40
|
+
it "must pass argv to .main" do
|
|
41
|
+
expect(subject).to receive(:main).with(argv)
|
|
42
|
+
allow(subject).to receive(:exit)
|
|
43
|
+
|
|
44
|
+
subject.start(argv)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
context "when given keyword arguments" do
|
|
49
|
+
let(:command_class) { TestMain::TestCommandWithInitialize }
|
|
50
|
+
|
|
51
|
+
let(:kwargs) { {foo: 'custom foo', bar: 'custom bar'} }
|
|
52
|
+
|
|
53
|
+
it "must pass the keyword arguments down to .main" do
|
|
54
|
+
expect(subject).to receive(:main).with(ARGV, **kwargs)
|
|
55
|
+
allow(subject).to receive(:exit)
|
|
56
|
+
|
|
57
|
+
subject.start(**kwargs)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
context "when Interrupt is raised" do
|
|
62
|
+
module TestMain
|
|
63
|
+
class TestCommandWithInterrupt
|
|
64
|
+
include CommandKit::Main
|
|
65
|
+
|
|
66
|
+
def main(*argv)
|
|
67
|
+
raise(Interrupt)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
let(:command_class) { TestMain::TestCommandWithInterrupt }
|
|
73
|
+
|
|
74
|
+
it "must exit with 130" do
|
|
75
|
+
expect(command_class).to receive(:exit).with(130)
|
|
76
|
+
|
|
77
|
+
command_class.start
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
context "when Errno::EPIPE is raised" do
|
|
82
|
+
module TestMain
|
|
83
|
+
class TestCommandWithBrokenPipe
|
|
84
|
+
include CommandKit::Main
|
|
85
|
+
|
|
86
|
+
def main(*argv)
|
|
87
|
+
raise(Errno::EPIPE)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
let(:command_class) { TestMain::TestCommandWithBrokenPipe }
|
|
93
|
+
|
|
94
|
+
it "must exit with 0" do
|
|
95
|
+
expect(command_class).to receive(:exit).with(0)
|
|
96
|
+
|
|
97
|
+
command_class.start
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
module TestMain
|
|
103
|
+
class TestCommandWithSystemExit
|
|
104
|
+
|
|
105
|
+
include CommandKit::Main
|
|
106
|
+
|
|
107
|
+
def run(*argv)
|
|
108
|
+
raise(SystemExit.new(-1))
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
describe ".main" do
|
|
115
|
+
subject { command_class }
|
|
116
|
+
|
|
117
|
+
it "must return 0 by default" do
|
|
118
|
+
expect(subject.main).to eq(0)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
let(:command_class) { TestMain::TestCommandWithInitialize }
|
|
122
|
+
|
|
123
|
+
context "when given a custom argv" do
|
|
124
|
+
let(:instance) { command_class.new }
|
|
125
|
+
let(:argv) { %w[one two three] }
|
|
126
|
+
|
|
127
|
+
it "must call #main with the custom argv" do
|
|
128
|
+
expect(subject).to receive(:new).with(no_args).and_return(instance)
|
|
129
|
+
expect(instance).to receive(:main).with(argv)
|
|
130
|
+
|
|
131
|
+
subject.main(argv)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
context "when given keyword arguments" do
|
|
136
|
+
let(:kwargs) { {foo: 'custom foo', bar: 'custom bar'} }
|
|
137
|
+
let(:instance) { command_class.new(**kwargs) }
|
|
138
|
+
|
|
139
|
+
it "must pass the keyword arguments .new then call #main" do
|
|
140
|
+
expect(subject).to receive(:new).with(**kwargs).and_return(instance)
|
|
141
|
+
expect(instance).to receive(:main).with([])
|
|
142
|
+
|
|
143
|
+
subject.main(**kwargs)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
context "when #main raises SystemExit" do
|
|
148
|
+
let(:command_class) { TestMain::TestCommandWithSystemExit }
|
|
149
|
+
|
|
150
|
+
it "must rescue SystemExit and return the exit status code" do
|
|
151
|
+
expect(subject.main()).to eq(-1)
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
describe "#main" do
|
|
157
|
+
subject { command_class.new }
|
|
158
|
+
|
|
159
|
+
it "must provide a default #main" do
|
|
160
|
+
expect(subject).to respond_to(:main)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
it "must return 0 by default" do
|
|
164
|
+
expect(subject.main).to eq(0)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it "must accept arbitrary argv" do
|
|
168
|
+
expect { subject.main([1,2,3]) }.to_not raise_error
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
context "when #run raises SystemExit" do
|
|
172
|
+
let(:command_class) { TestMain::TestCommandWithSystemExit }
|
|
173
|
+
|
|
174
|
+
it "must rescue SystemExit and return the exit status code" do
|
|
175
|
+
expect(subject.main()).to eq(-1)
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'command_kit/options/option'
|
|
3
|
+
|
|
4
|
+
describe Options::Option do
|
|
5
|
+
let(:name) { :foo }
|
|
6
|
+
let(:short) { nil }
|
|
7
|
+
let(:long) { '--foo' }
|
|
8
|
+
let(:equals) { false }
|
|
9
|
+
let(:value) do
|
|
10
|
+
{
|
|
11
|
+
usage: 'FOO',
|
|
12
|
+
required: true
|
|
13
|
+
}
|
|
14
|
+
end
|
|
15
|
+
let(:desc) { 'Foo option' }
|
|
16
|
+
let(:block) do
|
|
17
|
+
->(arg) { @foo = arg }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
subject do
|
|
21
|
+
described_class.new name, short: short,
|
|
22
|
+
long: long,
|
|
23
|
+
equals: equals,
|
|
24
|
+
desc: desc,
|
|
25
|
+
value: value,
|
|
26
|
+
&block
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe "#initialize" do
|
|
30
|
+
context "when the short: keyword is given" do
|
|
31
|
+
subject { described_class.new(name, short: short, desc: desc) }
|
|
32
|
+
|
|
33
|
+
it "must set #short" do
|
|
34
|
+
expect(subject.short).to eq(short)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context "when the short: keyword is not given" do
|
|
39
|
+
subject { described_class.new(name, desc: desc) }
|
|
40
|
+
|
|
41
|
+
it { expect(subject.short).to be(nil) }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context "when the long: keyword is given" do
|
|
45
|
+
let(:long) { '--opt' }
|
|
46
|
+
|
|
47
|
+
subject { described_class.new(name, long: long, desc: desc) }
|
|
48
|
+
|
|
49
|
+
it "must set #long" do
|
|
50
|
+
expect(subject.long).to eq(long)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context "when the long: keyword is not given" do
|
|
55
|
+
subject { described_class.new(name, desc: desc) }
|
|
56
|
+
|
|
57
|
+
it "default #long to a '--option' flag based on #name" do
|
|
58
|
+
expect(subject.long).to eq("--#{name}")
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
context "when the equals: keyword is given" do
|
|
63
|
+
let(:equals) { true }
|
|
64
|
+
|
|
65
|
+
subject { described_class.new(name, equals: equals, desc: desc) }
|
|
66
|
+
|
|
67
|
+
it "must set #equals" do
|
|
68
|
+
expect(subject.equals).to eq(equals)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
context "when the equals: keyword is not given" do
|
|
73
|
+
subject { described_class.new(name, desc: desc) }
|
|
74
|
+
|
|
75
|
+
it { expect(subject.equals).to be(false) }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
context "when the values: keyword is given" do
|
|
79
|
+
let(:value) { {} }
|
|
80
|
+
subject { described_class.new(name, value: {}, desc: desc) }
|
|
81
|
+
|
|
82
|
+
it "must initialize #value" do
|
|
83
|
+
expect(subject.value).to be_kind_of(Options::OptionValue)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
context "when the values: keyword is not given" do
|
|
88
|
+
subject { described_class.new(name, desc: desc) }
|
|
89
|
+
|
|
90
|
+
it { expect(subject.value).to be(nil) }
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
context "when the desc: keyword is given" do
|
|
94
|
+
subject { described_class.new(name, desc: desc) }
|
|
95
|
+
|
|
96
|
+
it "must set #desc" do
|
|
97
|
+
expect(subject.desc).to eq(desc)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
context "when the desc: keyword is not given" do
|
|
102
|
+
it do
|
|
103
|
+
expect {
|
|
104
|
+
described_class.new(name)
|
|
105
|
+
}.to raise_error(ArgumentError)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
context "when a block is given" do
|
|
110
|
+
subject { described_class.new(name, desc: desc, &block) }
|
|
111
|
+
|
|
112
|
+
it "must set #block" do
|
|
113
|
+
expect(subject.block).to eq(block)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
context "when no block is given" do
|
|
118
|
+
subject { described_class.new(name, desc: desc) }
|
|
119
|
+
|
|
120
|
+
it { expect(subject.block).to be(nil) }
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
describe "#equals?" do
|
|
125
|
+
context "when initialized with equals: true" do
|
|
126
|
+
let(:equals) { true }
|
|
127
|
+
|
|
128
|
+
it { expect(subject.equals?).to be(true) }
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
context "when initialized with equals: false" do
|
|
132
|
+
let(:equals) { false }
|
|
133
|
+
|
|
134
|
+
it { expect(subject.equals?).to be(false) }
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
describe "#separator" do
|
|
139
|
+
context "when #value is initialized" do
|
|
140
|
+
context "and #equals? is true" do
|
|
141
|
+
let(:equals) { true }
|
|
142
|
+
|
|
143
|
+
it { expect(subject.separator).to eq('=') }
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
context "and #equals? is false" do
|
|
147
|
+
let(:equals) { false }
|
|
148
|
+
|
|
149
|
+
it { expect(subject.separator).to eq(' ') }
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
context "when #value is not initialized" do
|
|
154
|
+
let(:value) { nil }
|
|
155
|
+
|
|
156
|
+
it { expect(subject.separator).to be(nil) }
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
describe "#usage" do
|
|
161
|
+
let(:long) { '--foo' }
|
|
162
|
+
|
|
163
|
+
it "must start with the long '--option'" do
|
|
164
|
+
expect(subject.usage.last).to start_with(long)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
context "when #value is initialized" do
|
|
168
|
+
it "must return '--option USAGE'" do
|
|
169
|
+
expect(subject.usage.last).to eq("#{long} #{subject.value.usage}")
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
context "and #equals? is true" do
|
|
173
|
+
let(:equals) { true }
|
|
174
|
+
|
|
175
|
+
it "must return '--option=USAGE'" do
|
|
176
|
+
expect(subject.usage.last).to eq("#{long}=#{subject.value.usage}")
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
context "when #short is not nil" do
|
|
182
|
+
let(:short) { '-f' }
|
|
183
|
+
|
|
184
|
+
it "to have two elements" do
|
|
185
|
+
expect(subject.usage.length).to eq(2)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
it "the first element should be the short option" do
|
|
189
|
+
expect(subject.usage[0]).to eq(short)
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
describe "#value?" do
|
|
195
|
+
context "when #value has been initialized" do
|
|
196
|
+
let(:value) { {} }
|
|
197
|
+
|
|
198
|
+
it { expect(subject.value?).to be(true) }
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
context "when #value has not been initialized" do
|
|
202
|
+
let(:value) { nil }
|
|
203
|
+
|
|
204
|
+
it { expect(subject.value?).to be(false) }
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
describe "#type" do
|
|
209
|
+
context "when #value has been initialized and has a #type" do
|
|
210
|
+
let(:type) { String }
|
|
211
|
+
let(:value) { {type: type} }
|
|
212
|
+
|
|
213
|
+
it "must return the #value.type" do
|
|
214
|
+
expect(subject.type).to eq(type)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
context "when #value has not been initialized" do
|
|
219
|
+
let(:value) { nil }
|
|
220
|
+
|
|
221
|
+
it { expect(subject.type).to be(nil) }
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
describe "#default_value" do
|
|
226
|
+
context "when #value has been initialized and has a #default" do
|
|
227
|
+
let(:default) { "" }
|
|
228
|
+
let(:value) { {default: default} }
|
|
229
|
+
|
|
230
|
+
it "must return the #value.default_value" do
|
|
231
|
+
expect(subject.default_value).to eq(default)
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
context "when #value has not been initialized" do
|
|
236
|
+
let(:value) { nil }
|
|
237
|
+
|
|
238
|
+
it { expect(subject.default_value).to be(nil) }
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
describe "#desc" do
|
|
243
|
+
let(:desc) { 'Foo option' }
|
|
244
|
+
|
|
245
|
+
it "must return the desc: value" do
|
|
246
|
+
expect(subject.desc).to eq(desc)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
context "when #value has been initialized with a default value" do
|
|
250
|
+
let(:default) { "foo" }
|
|
251
|
+
let(:value) { {default: default} }
|
|
252
|
+
|
|
253
|
+
it "should reutrn the desc value and '(Default: ...)'" do
|
|
254
|
+
expect(subject.desc).to eq("#{desc} (Default: #{default})")
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|