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.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +7 -0
  6. data/CHANGES.md +66 -0
  7. data/Gemfile +5 -0
  8. data/LICENSE.txt +201 -0
  9. data/README.rdoc +173 -0
  10. data/Rakefile +94 -0
  11. data/bin/optparse_plus +130 -0
  12. data/fix.rb +29 -0
  13. data/lib/optparse-plus.rb +1 -0
  14. data/lib/optparse_plus.rb +15 -0
  15. data/lib/optparse_plus/argv_parser.rb +50 -0
  16. data/lib/optparse_plus/cli.rb +116 -0
  17. data/lib/optparse_plus/cli_logger.rb +133 -0
  18. data/lib/optparse_plus/cli_logging.rb +138 -0
  19. data/lib/optparse_plus/cucumber.rb +119 -0
  20. data/lib/optparse_plus/error.rb +32 -0
  21. data/lib/optparse_plus/execution_strategy/base.rb +34 -0
  22. data/lib/optparse_plus/execution_strategy/jvm.rb +37 -0
  23. data/lib/optparse_plus/execution_strategy/mri.rb +16 -0
  24. data/lib/optparse_plus/execution_strategy/open_3.rb +16 -0
  25. data/lib/optparse_plus/execution_strategy/open_4.rb +22 -0
  26. data/lib/optparse_plus/execution_strategy/rbx_open_4.rb +12 -0
  27. data/lib/optparse_plus/exit_now.rb +40 -0
  28. data/lib/optparse_plus/main.rb +603 -0
  29. data/lib/optparse_plus/process_status.rb +45 -0
  30. data/lib/optparse_plus/sh.rb +223 -0
  31. data/lib/optparse_plus/test/base_integration_test.rb +31 -0
  32. data/lib/optparse_plus/test/integration_test_assertions.rb +65 -0
  33. data/lib/optparse_plus/version.rb +3 -0
  34. data/optparse_plus.gemspec +28 -0
  35. data/templates/full/.gitignore.erb +4 -0
  36. data/templates/full/README.rdoc.erb +24 -0
  37. data/templates/full/Rakefile.erb +71 -0
  38. data/templates/full/_license_head.txt.erb +2 -0
  39. data/templates/full/apache_LICENSE.txt.erb +203 -0
  40. data/templates/full/bin/executable.erb +45 -0
  41. data/templates/full/custom_LICENSE.txt.erb +0 -0
  42. data/templates/full/gplv2_LICENSE.txt.erb +14 -0
  43. data/templates/full/gplv3_LICENSE.txt.erb +14 -0
  44. data/templates/full/mit_LICENSE.txt.erb +7 -0
  45. data/templates/rspec/spec/something_spec.rb.erb +5 -0
  46. data/templates/test_unit/test/integration/test_cli.rb.erb +11 -0
  47. data/templates/test_unit/test/unit/test_something.rb.erb +7 -0
  48. data/test/integration/base_integration_test.rb +60 -0
  49. data/test/integration/test_bootstrap.rb +150 -0
  50. data/test/integration/test_cli.rb +21 -0
  51. data/test/integration/test_license.rb +56 -0
  52. data/test/integration/test_readme.rb +53 -0
  53. data/test/integration/test_rspec.rb +28 -0
  54. data/test/integration/test_version.rb +21 -0
  55. data/test/unit/base_test.rb +19 -0
  56. data/test/unit/command_for_tests.sh +7 -0
  57. data/test/unit/execution_strategy/test_base.rb +24 -0
  58. data/test/unit/execution_strategy/test_jvm.rb +77 -0
  59. data/test/unit/execution_strategy/test_mri.rb +32 -0
  60. data/test/unit/execution_strategy/test_open_3.rb +70 -0
  61. data/test/unit/execution_strategy/test_open_4.rb +86 -0
  62. data/test/unit/execution_strategy/test_rbx_open_4.rb +25 -0
  63. data/test/unit/test/test_integration_test_assertions.rb +211 -0
  64. data/test/unit/test_cli_logger.rb +219 -0
  65. data/test/unit/test_cli_logging.rb +243 -0
  66. data/test/unit/test_exit_now.rb +37 -0
  67. data/test/unit/test_main.rb +840 -0
  68. data/test/unit/test_sh.rb +404 -0
  69. 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