optparse-plus 3.0.0
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/.gitignore +17 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/CHANGES.md +66 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +201 -0
- data/README.rdoc +173 -0
- data/Rakefile +94 -0
- data/bin/optparse_plus +130 -0
- data/fix.rb +29 -0
- data/lib/optparse-plus.rb +1 -0
- data/lib/optparse_plus.rb +15 -0
- data/lib/optparse_plus/argv_parser.rb +50 -0
- data/lib/optparse_plus/cli.rb +116 -0
- data/lib/optparse_plus/cli_logger.rb +133 -0
- data/lib/optparse_plus/cli_logging.rb +138 -0
- data/lib/optparse_plus/cucumber.rb +119 -0
- data/lib/optparse_plus/error.rb +32 -0
- data/lib/optparse_plus/execution_strategy/base.rb +34 -0
- data/lib/optparse_plus/execution_strategy/jvm.rb +37 -0
- data/lib/optparse_plus/execution_strategy/mri.rb +16 -0
- data/lib/optparse_plus/execution_strategy/open_3.rb +16 -0
- data/lib/optparse_plus/execution_strategy/open_4.rb +22 -0
- data/lib/optparse_plus/execution_strategy/rbx_open_4.rb +12 -0
- data/lib/optparse_plus/exit_now.rb +40 -0
- data/lib/optparse_plus/main.rb +603 -0
- data/lib/optparse_plus/process_status.rb +45 -0
- data/lib/optparse_plus/sh.rb +223 -0
- data/lib/optparse_plus/test/base_integration_test.rb +31 -0
- data/lib/optparse_plus/test/integration_test_assertions.rb +65 -0
- data/lib/optparse_plus/version.rb +3 -0
- data/optparse_plus.gemspec +28 -0
- data/templates/full/.gitignore.erb +4 -0
- data/templates/full/README.rdoc.erb +24 -0
- data/templates/full/Rakefile.erb +71 -0
- data/templates/full/_license_head.txt.erb +2 -0
- data/templates/full/apache_LICENSE.txt.erb +203 -0
- data/templates/full/bin/executable.erb +45 -0
- data/templates/full/custom_LICENSE.txt.erb +0 -0
- data/templates/full/gplv2_LICENSE.txt.erb +14 -0
- data/templates/full/gplv3_LICENSE.txt.erb +14 -0
- data/templates/full/mit_LICENSE.txt.erb +7 -0
- data/templates/rspec/spec/something_spec.rb.erb +5 -0
- data/templates/test_unit/test/integration/test_cli.rb.erb +11 -0
- data/templates/test_unit/test/unit/test_something.rb.erb +7 -0
- data/test/integration/base_integration_test.rb +60 -0
- data/test/integration/test_bootstrap.rb +150 -0
- data/test/integration/test_cli.rb +21 -0
- data/test/integration/test_license.rb +56 -0
- data/test/integration/test_readme.rb +53 -0
- data/test/integration/test_rspec.rb +28 -0
- data/test/integration/test_version.rb +21 -0
- data/test/unit/base_test.rb +19 -0
- data/test/unit/command_for_tests.sh +7 -0
- data/test/unit/execution_strategy/test_base.rb +24 -0
- data/test/unit/execution_strategy/test_jvm.rb +77 -0
- data/test/unit/execution_strategy/test_mri.rb +32 -0
- data/test/unit/execution_strategy/test_open_3.rb +70 -0
- data/test/unit/execution_strategy/test_open_4.rb +86 -0
- data/test/unit/execution_strategy/test_rbx_open_4.rb +25 -0
- data/test/unit/test/test_integration_test_assertions.rb +211 -0
- data/test/unit/test_cli_logger.rb +219 -0
- data/test/unit/test_cli_logging.rb +243 -0
- data/test/unit/test_exit_now.rb +37 -0
- data/test/unit/test_main.rb +840 -0
- data/test/unit/test_sh.rb +404 -0
- metadata +260 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'base_test'
|
2
|
+
require 'mocha/test_unit'
|
3
|
+
|
4
|
+
# Define this symbol without requiring the library;
|
5
|
+
# all we're going to do is mock calls to it
|
6
|
+
module Open4
|
7
|
+
end
|
8
|
+
|
9
|
+
module ExecutionStrategy
|
10
|
+
class TestRBXOpen_4 < BaseTest
|
11
|
+
include OptparsePlus::ExecutionStrategy
|
12
|
+
|
13
|
+
test_that "exception_meaning_command_not_found returns Errno::EINVAL" do
|
14
|
+
Given {
|
15
|
+
@strategy = RBXOpen_4.new
|
16
|
+
}
|
17
|
+
When {
|
18
|
+
@klass = @strategy.exception_meaning_command_not_found
|
19
|
+
}
|
20
|
+
Then {
|
21
|
+
@klass.should == [Errno::EINVAL,Errno::ENOENT]
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
require 'base_test'
|
2
|
+
require 'optparse_plus'
|
3
|
+
require 'optparse_plus/test/integration_test_assertions'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'tmpdir'
|
6
|
+
|
7
|
+
class TestIntegrationTestAssertions < BaseTest
|
8
|
+
include OptparsePlus::IntegrationTestAssertions
|
9
|
+
include FileUtils
|
10
|
+
|
11
|
+
def setup
|
12
|
+
@pwd = pwd
|
13
|
+
@tmpdir = Dir.mktmpdir
|
14
|
+
chdir @tmpdir
|
15
|
+
end
|
16
|
+
|
17
|
+
def teardown
|
18
|
+
chdir @pwd
|
19
|
+
rm_rf @tmpdir
|
20
|
+
end
|
21
|
+
|
22
|
+
test_that "assert_file works with one regexp" do
|
23
|
+
Given { some_file }
|
24
|
+
When {
|
25
|
+
@code = ->() { assert_file("some_file.txt", contains: /foo/) }
|
26
|
+
}
|
27
|
+
Then { refute_raises(&@code) }
|
28
|
+
end
|
29
|
+
|
30
|
+
test_that "assert_file works with many regexps" do
|
31
|
+
Given { some_file }
|
32
|
+
When {
|
33
|
+
@code = ->() { assert_file("some_file.txt", contains: [ /foo/, /bar/ ]) }
|
34
|
+
}
|
35
|
+
Then { refute_raises(&@code) }
|
36
|
+
end
|
37
|
+
|
38
|
+
test_that "assert_file fails if any regexp fails to match" do
|
39
|
+
Given { some_file }
|
40
|
+
When {
|
41
|
+
@code = ->() { assert_file("some_file.txt", contains: [ /foo/, /baz/ ]) }
|
42
|
+
}
|
43
|
+
Then { assert_raises(&@code) }
|
44
|
+
end
|
45
|
+
|
46
|
+
test_that "assert_banner without takes_options passes for a banner with the bin name and no '[options]'" do
|
47
|
+
Given {
|
48
|
+
@bin_name = "foobar"
|
49
|
+
@stdout = "Usage: foobar"
|
50
|
+
}
|
51
|
+
When {
|
52
|
+
@code = ->() { assert_banner(@stdout,@bin_name,takes_options: false) }
|
53
|
+
}
|
54
|
+
Then { refute_raises(&@code) }
|
55
|
+
end
|
56
|
+
|
57
|
+
test_that "assert_banner without takes_options fails for a banner with the bin name and '[options]'" do
|
58
|
+
Given {
|
59
|
+
@bin_name = "foobar"
|
60
|
+
@stdout = "Usage: foobar [options]"
|
61
|
+
}
|
62
|
+
When {
|
63
|
+
@code = ->() { assert_banner(@stdout,@bin_name,takes_options: false) }
|
64
|
+
}
|
65
|
+
Then { assert_raises(&@code) }
|
66
|
+
end
|
67
|
+
|
68
|
+
test_that "assert_banner with takes_options passes for a banner with the bin name and '[options]'" do
|
69
|
+
Given {
|
70
|
+
@bin_name = "foobar"
|
71
|
+
@stdout = "Usage: foobar [options]\nOptions\n --help"
|
72
|
+
}
|
73
|
+
When {
|
74
|
+
@code = ->() { assert_banner(@stdout,@bin_name,takes_options: true) }
|
75
|
+
}
|
76
|
+
Then { refute_raises(&@code) }
|
77
|
+
end
|
78
|
+
|
79
|
+
test_that "assert_banner with takes_options fails for a banner with the bin name but no '[options]'" do
|
80
|
+
Given {
|
81
|
+
@bin_name = "foobar"
|
82
|
+
@stdout = "Usage: foobar\nOptions\n --help"
|
83
|
+
}
|
84
|
+
When {
|
85
|
+
@code = ->() { assert_banner(@stdout,@bin_name,takes_options: true) }
|
86
|
+
}
|
87
|
+
Then { assert_raises(&@code) }
|
88
|
+
end
|
89
|
+
|
90
|
+
test_that "assert_banner with takes_options and takes_arguments passes for a banner with the bin name, '[options]' and the arg list" do
|
91
|
+
Given {
|
92
|
+
@bin_name = "foobar"
|
93
|
+
@stdout = "Usage: foobar [options] some_arg [some_other_arg]\nOptions\n --help"
|
94
|
+
}
|
95
|
+
When {
|
96
|
+
@code = ->() {
|
97
|
+
assert_banner(@stdout,
|
98
|
+
@bin_name,
|
99
|
+
takes_options: true,
|
100
|
+
takes_arguments: { some_arg: :required, some_other_arg: :optional }
|
101
|
+
)
|
102
|
+
}
|
103
|
+
}
|
104
|
+
Then { refute_raises(&@code) }
|
105
|
+
end
|
106
|
+
|
107
|
+
test_that "assert_banner with takes_options and takes_arguments failes for a banner with the bin name, '[options]' and no arg list" do
|
108
|
+
Given {
|
109
|
+
@bin_name = "foobar"
|
110
|
+
@stdout = "Usage: foobar [options]\nOptions\n --help"
|
111
|
+
}
|
112
|
+
When {
|
113
|
+
@code = ->() {
|
114
|
+
assert_banner(@stdout,
|
115
|
+
@bin_name,
|
116
|
+
takes_options: true,
|
117
|
+
takes_arguments: { some_arg: :required, some_other_arg: :optional }
|
118
|
+
)
|
119
|
+
}
|
120
|
+
}
|
121
|
+
Then { assert_raises(&@code) }
|
122
|
+
end
|
123
|
+
|
124
|
+
test_that "assert_options with one option passes when stdout contains that option" do
|
125
|
+
Given { @stdout = some_options }
|
126
|
+
When { @code = ->() { assert_option(@stdout,"--help") } }
|
127
|
+
Then { refute_raises(&@code) }
|
128
|
+
end
|
129
|
+
|
130
|
+
test_that "assert_options with many option passes when stdout contains that option" do
|
131
|
+
Given { @stdout = some_options }
|
132
|
+
When { @code = ->() { assert_option(@stdout,"-h", "--help") } }
|
133
|
+
Then { refute_raises(&@code) }
|
134
|
+
end
|
135
|
+
|
136
|
+
test_that "assert_options fails when stdout does not the option" do
|
137
|
+
Given { @stdout = some_options }
|
138
|
+
When { @code = ->() { assert_option(@stdout,"--bleorg") } }
|
139
|
+
Then { assert_raises(&@code) }
|
140
|
+
end
|
141
|
+
|
142
|
+
test_that "assert_oneline_summary passes when the stdout has at least three lines, the second of which is blank and the third of which has some words in it" do
|
143
|
+
Given {
|
144
|
+
@stdout = [
|
145
|
+
"Usage: foobar",
|
146
|
+
"",
|
147
|
+
"The awesome app of awesome",
|
148
|
+
].join("\n")
|
149
|
+
}
|
150
|
+
When { @code = ->() { assert_oneline_summary(@stdout) } }
|
151
|
+
Then { refute_raises(&@code) }
|
152
|
+
end
|
153
|
+
|
154
|
+
test_that "assert_oneline_summary fails when the stdout has at least three lines, the second of which is blank and the third of which has only one word in it" do
|
155
|
+
Given {
|
156
|
+
@stdout = [
|
157
|
+
"Usage: foobar",
|
158
|
+
"",
|
159
|
+
"awesome",
|
160
|
+
].join("\n")
|
161
|
+
}
|
162
|
+
When { @code = ->() { assert_oneline_summary(@stdout) } }
|
163
|
+
Then { assert_raises(&@code) }
|
164
|
+
end
|
165
|
+
|
166
|
+
test_that "assert_oneline_summary fails when the stdout has at least three lines, the second of which is not blank and the third of which has words in it" do
|
167
|
+
Given {
|
168
|
+
@stdout = [
|
169
|
+
"Usage: foobar",
|
170
|
+
"foo",
|
171
|
+
"awesome app of awesome",
|
172
|
+
].join("\n")
|
173
|
+
}
|
174
|
+
When { @code = ->() { assert_oneline_summary(@stdout) } }
|
175
|
+
Then { assert_raises(&@code) }
|
176
|
+
end
|
177
|
+
|
178
|
+
test_that "assert_oneline_summary fails when the stdout has less than three lines" do
|
179
|
+
Given {
|
180
|
+
@stdout = [
|
181
|
+
"Usage: foobar",
|
182
|
+
"awesome app of awesome",
|
183
|
+
].join("\n")
|
184
|
+
}
|
185
|
+
When { @code = ->() { assert_oneline_summary(@stdout) } }
|
186
|
+
Then { assert_raises(&@code) }
|
187
|
+
end
|
188
|
+
|
189
|
+
private
|
190
|
+
|
191
|
+
def some_options
|
192
|
+
[
|
193
|
+
"-h, --help Get Help",
|
194
|
+
"--version Show the version",
|
195
|
+
"--[no-]output Print output",
|
196
|
+
].join("\n")
|
197
|
+
end
|
198
|
+
|
199
|
+
def refute_raises(&block)
|
200
|
+
block.()
|
201
|
+
rescue Exception => ex
|
202
|
+
assert false, "Expected block NOT to raise, but got a #{ex.class}/#{ex.message}"
|
203
|
+
end
|
204
|
+
|
205
|
+
def some_file
|
206
|
+
File.open("some_file.txt","w") do |file|
|
207
|
+
file.puts "foo"
|
208
|
+
file.puts "bar"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
@@ -0,0 +1,219 @@
|
|
1
|
+
require 'base_test'
|
2
|
+
require 'optparse_plus'
|
3
|
+
require 'stringio'
|
4
|
+
require 'tempfile'
|
5
|
+
|
6
|
+
class TestCLILogger < BaseTest
|
7
|
+
include OptparsePlus
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@blank_format = proc { |severity,datetime,progname,msg|
|
11
|
+
msg + "\n"
|
12
|
+
}
|
13
|
+
@real_stderr = $stderr
|
14
|
+
@real_stdout = $stdout
|
15
|
+
$stderr = StringIO.new
|
16
|
+
$stdout = StringIO.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def teardown
|
20
|
+
$stderr = @real_stderr
|
21
|
+
$stdout = @real_stdout
|
22
|
+
end
|
23
|
+
|
24
|
+
test_that "when both stderr and stdin are ttys, split the log messages between them and don't format" do
|
25
|
+
Given {
|
26
|
+
class << $stderr
|
27
|
+
def tty?; true; end
|
28
|
+
end
|
29
|
+
class << $stdout
|
30
|
+
def tty?; true; end
|
31
|
+
end
|
32
|
+
|
33
|
+
@logger = CLILogger.new
|
34
|
+
@logger.level = Logger::DEBUG
|
35
|
+
}
|
36
|
+
|
37
|
+
When log_all_levels
|
38
|
+
|
39
|
+
Then {
|
40
|
+
$stdout.string.should be == "debug\ninfo\n"
|
41
|
+
$stderr.string.should be == "warn\nerror\nfatal\n"
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
test_that "when both stderr and stdin are ttys, setting the level higher than WARN should affect the error logger" do
|
46
|
+
Given {
|
47
|
+
class << $stderr
|
48
|
+
def tty?; true; end
|
49
|
+
end
|
50
|
+
class << $stdout
|
51
|
+
def tty?; true; end
|
52
|
+
end
|
53
|
+
|
54
|
+
@logger = CLILogger.new
|
55
|
+
@logger.level = Logger::ERROR
|
56
|
+
}
|
57
|
+
|
58
|
+
When log_all_levels
|
59
|
+
|
60
|
+
Then {
|
61
|
+
$stdout.string.should be == ""
|
62
|
+
$stderr.string.should be == "error\nfatal\n"
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
test_that "logger sends debug and info to stdout, and warns, errors, and fatals to stderr" do
|
67
|
+
Given a_logger_with_blank_format
|
68
|
+
When log_all_levels
|
69
|
+
|
70
|
+
Then stdout_should_have_everything
|
71
|
+
And {
|
72
|
+
$stderr.string.should be == "warn\nerror\nfatal\n"
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
test_that "we can control what goes to stderr" do
|
77
|
+
Given a_logger_with_blank_format :at_error_level => Logger::Severity::FATAL
|
78
|
+
|
79
|
+
When log_all_levels
|
80
|
+
|
81
|
+
Then stdout_should_have_everything
|
82
|
+
And {
|
83
|
+
$stderr.string.should be == "fatal\n"
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
test_that "we can log to alternate devices easily" do
|
88
|
+
Given {
|
89
|
+
@out = StringIO.new
|
90
|
+
@err = StringIO.new
|
91
|
+
|
92
|
+
@logger = CLILogger.new(@out,@err)
|
93
|
+
@logger.level = Logger::DEBUG
|
94
|
+
@logger.formatter = @blank_format
|
95
|
+
}
|
96
|
+
|
97
|
+
When log_all_levels
|
98
|
+
|
99
|
+
Then {
|
100
|
+
@out.string.should be == "debug\ninfo\nwarn\nerror\nfatal\n"
|
101
|
+
@err.string.should be == "warn\nerror\nfatal\n"
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
test_that "error logger ignores the log level" do
|
107
|
+
Given a_logger_with_blank_format :at_level => Logger::Severity::FATAL
|
108
|
+
When log_all_levels
|
109
|
+
|
110
|
+
Then {
|
111
|
+
$stdout.string.should be == "fatal\n"
|
112
|
+
$stderr.string.should be == "warn\nerror\nfatal\n"
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
test_that "both loggers use the same date format" do
|
117
|
+
Given {
|
118
|
+
@logger = CLILogger.new
|
119
|
+
@logger.level = Logger::DEBUG
|
120
|
+
@logger.datetime_format = "the time"
|
121
|
+
}
|
122
|
+
|
123
|
+
When {
|
124
|
+
@logger.debug("debug")
|
125
|
+
@logger.error("error")
|
126
|
+
}
|
127
|
+
|
128
|
+
Then {
|
129
|
+
$stdout.string.should match(/the time.*DEBUG.*debug/)
|
130
|
+
$stderr.string.should match(/the time.*ERROR.*error/)
|
131
|
+
}
|
132
|
+
end
|
133
|
+
|
134
|
+
test_that "error logger does not get <<" do
|
135
|
+
Given a_logger_with_blank_format
|
136
|
+
When {
|
137
|
+
@logger << "foo"
|
138
|
+
}
|
139
|
+
Then {
|
140
|
+
$stdout.string.should be == "foo"
|
141
|
+
$stderr.string.should be == ""
|
142
|
+
}
|
143
|
+
end
|
144
|
+
|
145
|
+
test_that "error logger can have a different format" do
|
146
|
+
Given {
|
147
|
+
@logger = logger_with_blank_format
|
148
|
+
@logger.error_formatter = proc do |severity,datetime,progname,msg|
|
149
|
+
"ERROR_LOGGER: #{msg}\n"
|
150
|
+
end
|
151
|
+
}
|
152
|
+
When {
|
153
|
+
@logger.debug("debug")
|
154
|
+
@logger.error("error")
|
155
|
+
}
|
156
|
+
Then {
|
157
|
+
$stdout.string.should be == "debug\nerror\n"
|
158
|
+
$stderr.string.should be == "ERROR_LOGGER: error\n"
|
159
|
+
}
|
160
|
+
end
|
161
|
+
|
162
|
+
test_that "we can use filenames as log devices" do
|
163
|
+
Given {
|
164
|
+
tempfile = Tempfile.new("stderr_log")
|
165
|
+
@stdout_file = tempfile.path
|
166
|
+
tempfile.close
|
167
|
+
|
168
|
+
tempfile = Tempfile.new("stdout_log")
|
169
|
+
@stderr_file = tempfile.path
|
170
|
+
tempfile.close
|
171
|
+
}
|
172
|
+
When {
|
173
|
+
@logger = CLILogger.new(@stdout_file,@stderr_file)
|
174
|
+
@logger.info("some info")
|
175
|
+
@logger.error("some error")
|
176
|
+
}
|
177
|
+
Then {
|
178
|
+
File.read(@stdout_file).should =~ /some info/
|
179
|
+
File.read(@stderr_file).should =~ /some error/
|
180
|
+
}
|
181
|
+
end
|
182
|
+
|
183
|
+
private
|
184
|
+
|
185
|
+
def log_all_levels
|
186
|
+
proc do
|
187
|
+
@logger.debug("debug")
|
188
|
+
@logger.info("info")
|
189
|
+
@logger.warn("warn")
|
190
|
+
@logger.error("error")
|
191
|
+
@logger.fatal("fatal")
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
def logger_with_blank_format
|
197
|
+
logger = CLILogger.new
|
198
|
+
logger.formatter = @blank_format
|
199
|
+
logger.level = Logger::Severity::DEBUG
|
200
|
+
logger
|
201
|
+
end
|
202
|
+
|
203
|
+
# options - :at_level - level to set the logger
|
204
|
+
def a_logger_with_blank_format(options = {})
|
205
|
+
proc do
|
206
|
+
@logger = logger_with_blank_format
|
207
|
+
@logger.level = options[:at_level] if options[:at_level]
|
208
|
+
@logger.error_level = options[:at_error_level] if options[:at_error_level]
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def stdout_should_have_everything
|
213
|
+
proc do
|
214
|
+
$stdout.string.should be == "debug\ninfo\nwarn\nerror\nfatal\n"
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
|
219
|
+
end
|