optimist 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require 'optimist'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "optimist"
9
+ spec.version = Optimist::VERSION
10
+ spec.authors = ["William Morgan", "Keenan Brock", "Jason Frey"]
11
+ spec.email = "keenan@thebrocks.net"
12
+ spec.summary = "Optimist is a commandline option parser for Ruby that just gets out of your way."
13
+ spec.description = "Optimist is a commandline option parser for Ruby that just
14
+ gets out of your way. One line of code per option is all you need to write.
15
+ For that, you get a nice automatically-generated help page, robust option
16
+ parsing, command subcompletion, and sensible defaults for everything you don't
17
+ specify."
18
+ spec.homepage = "http://manageiq.github.io/optimist/"
19
+ spec.license = "MIT"
20
+
21
+ spec.files = `git ls-files -z`.split("\x0")
22
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
23
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
24
+ spec.metadata = {
25
+ "changelog_uri" => "https://github.com/ManageIQ/optimist/blob/master/History.txt",
26
+ "source_code_uri" => "https://github.com/ManageIQ/optimist/",
27
+ "bug_tracker_uri" => "https://github.com/ManageIQ/optimist/issues",
28
+ }
29
+
30
+ spec.require_paths = ["lib"]
31
+
32
+ spec.add_development_dependency "minitest", "~> 5.4.3"
33
+ spec.add_development_dependency "rake", "~> 10.0"
34
+ spec.add_development_dependency "chronic"
35
+ end
@@ -0,0 +1,27 @@
1
+ require 'test_helper'
2
+
3
+ module Optimist
4
+ class CommandlineErrorTest < ::MiniTest::Test
5
+ def test_class
6
+ assert_kind_of Exception, cle("message")
7
+ end
8
+
9
+ def test_message
10
+ assert "message", cle("message").message
11
+ end
12
+
13
+ def test_error_code_default
14
+ assert_nil cle("message").error_code
15
+ end
16
+
17
+ def test_error_code_custom
18
+ assert_equal(-3, cle("message", -3).error_code)
19
+ end
20
+
21
+ private
22
+
23
+ def cle(*args)
24
+ CommandlineError.new(*args)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ require 'test_helper'
2
+
3
+ module Optimist
4
+ class HelpNeededTest < ::MiniTest::Test
5
+ def test_class
6
+ assert_kind_of Exception, hn("message")
7
+ end
8
+
9
+ def test_message
10
+ assert "message", hn("message").message
11
+ end
12
+
13
+ private
14
+
15
+ def hn(*args)
16
+ HelpNeeded.new(*args)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,175 @@
1
+ require 'stringio'
2
+ require 'test_helper'
3
+
4
+ module Optimist
5
+ class ParserEduateTest < ::MiniTest::Test
6
+ def setup
7
+ end
8
+
9
+ def test_no_arguments_to_stdout
10
+ assert_stdout(/Options:/) do
11
+ parser.educate
12
+ end
13
+ end
14
+
15
+ def test_argument_to_stringio
16
+ assert_educates(/Options:/)
17
+ end
18
+
19
+ def test_no_headers
20
+ assert_educates(/^Options:/)
21
+ end
22
+
23
+ def test_usage
24
+ parser.usage("usage string")
25
+ assert_educates(/^Usage: \w* usage string\n\nOptions:/)
26
+ end
27
+
28
+ def test_usage_synopsis_version
29
+ end
30
+
31
+ # def test_banner
32
+ # def test_text
33
+
34
+ # width, legacy_width
35
+ # wrap
36
+ # wrap_lines
37
+
38
+ ############
39
+ # convert these into multiple tests
40
+ # pulled out of optimist_test for now
41
+ def test_help_has_default_banner
42
+ @p = Parser.new
43
+ sio = StringIO.new "w"
44
+ @p.parse []
45
+ @p.educate sio
46
+ help = sio.string.split "\n"
47
+ assert help[0] =~ /options/i
48
+ assert_equal 2, help.length # options, then -h
49
+
50
+ @p = Parser.new
51
+ @p.version "my version"
52
+ sio = StringIO.new "w"
53
+ @p.parse []
54
+ @p.educate sio
55
+ help = sio.string.split "\n"
56
+ assert help[0] =~ /my version/i
57
+ assert_equal 4, help.length # version, options, -h, -v
58
+
59
+ @p = Parser.new
60
+ @p.banner "my own banner"
61
+ sio = StringIO.new "w"
62
+ @p.parse []
63
+ @p.educate sio
64
+ help = sio.string.split "\n"
65
+ assert help[0] =~ /my own banner/i
66
+ assert_equal 2, help.length # banner, -h
67
+
68
+ @p = Parser.new
69
+ @p.text "my own text banner"
70
+ sio = StringIO.new "w"
71
+ @p.parse []
72
+ @p.educate sio
73
+ help = sio.string.split "\n"
74
+ assert help[0] =~ /my own text banner/i
75
+ assert_equal 2, help.length # banner, -h
76
+ end
77
+
78
+ def test_help_has_optional_usage
79
+ @p = Parser.new
80
+ @p.usage "OPTIONS FILES"
81
+ sio = StringIO.new "w"
82
+ @p.parse []
83
+ @p.educate sio
84
+ help = sio.string.split "\n"
85
+ assert help[0] =~ /OPTIONS FILES/i
86
+ assert_equal 4, help.length # line break, options, then -h
87
+ end
88
+
89
+ def test_help_has_optional_synopsis
90
+ @p = Parser.new
91
+ @p.synopsis "About this program"
92
+ sio = StringIO.new "w"
93
+ @p.parse []
94
+ @p.educate sio
95
+ help = sio.string.split "\n"
96
+ assert help[0] =~ /About this program/i
97
+ assert_equal 4, help.length # line break, options, then -h
98
+ end
99
+
100
+ def test_help_has_specific_order_for_usage_and_synopsis
101
+ @p = Parser.new
102
+ @p.usage "OPTIONS FILES"
103
+ @p.synopsis "About this program"
104
+ sio = StringIO.new "w"
105
+ @p.parse []
106
+ @p.educate sio
107
+ help = sio.string.split "\n"
108
+ assert help[0] =~ /OPTIONS FILES/i
109
+ assert help[1] =~ /About this program/i
110
+ assert_equal 5, help.length # line break, options, then -h
111
+ end
112
+
113
+ def test_help_preserves_positions
114
+ parser.opt :zzz, "zzz"
115
+ parser.opt :aaa, "aaa"
116
+ sio = StringIO.new "w"
117
+ parser.educate sio
118
+
119
+ help = sio.string.split "\n"
120
+ assert help[1] =~ /zzz/
121
+ assert help[2] =~ /aaa/
122
+ end
123
+
124
+ def test_help_includes_option_types
125
+ parser.opt :arg1, 'arg', :type => :int
126
+ parser.opt :arg2, 'arg', :type => :ints
127
+ parser.opt :arg3, 'arg', :type => :string
128
+ parser.opt :arg4, 'arg', :type => :strings
129
+ parser.opt :arg5, 'arg', :type => :float
130
+ parser.opt :arg6, 'arg', :type => :floats
131
+ parser.opt :arg7, 'arg', :type => :io
132
+ parser.opt :arg8, 'arg', :type => :ios
133
+ parser.opt :arg9, 'arg', :type => :date
134
+ parser.opt :arg10, 'arg', :type => :dates
135
+ sio = StringIO.new "w"
136
+ parser.educate sio
137
+
138
+ help = sio.string.split "\n"
139
+ assert help[1] =~ /<i>/
140
+ assert help[2] =~ /<i\+>/
141
+ assert help[3] =~ /<s>/
142
+ assert help[4] =~ /<s\+>/
143
+ assert help[5] =~ /<f>/
144
+ assert help[6] =~ /<f\+>/
145
+ assert help[7] =~ /<filename\/uri>/
146
+ assert help[8] =~ /<filename\/uri\+>/
147
+ assert help[9] =~ /<date>/
148
+ assert help[10] =~ /<date\+>/
149
+ end
150
+
151
+ def test_help_has_grammatical_default_text
152
+ parser.opt :arg1, 'description with period.', :default => 'hello'
153
+ parser.opt :arg2, 'description without period', :default => 'world'
154
+ sio = StringIO.new 'w'
155
+ parser.educate sio
156
+
157
+ help = sio.string.split "\n"
158
+ assert help[1] =~ /Default/
159
+ assert help[2] =~ /default/
160
+ end
161
+ ############
162
+
163
+ private
164
+
165
+ def parser
166
+ @p ||= Parser.new
167
+ end
168
+
169
+ def assert_educates(output)
170
+ str = StringIO.new
171
+ parser.educate str
172
+ assert_match output, str.string
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,14 @@
1
+ require 'stringio'
2
+ require 'test_helper'
3
+
4
+ module Optimist
5
+
6
+ class ParserOptTest < ::MiniTest::Test
7
+
8
+ private
9
+
10
+ def parser
11
+ @p ||= Parser.new
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,79 @@
1
+ require 'stringio'
2
+ require 'test_helper'
3
+
4
+ module Optimist
5
+ class ParserParseTest < ::MiniTest::Test
6
+
7
+ # TODO: parse
8
+ # resolve_default_short_options!
9
+ # parse_date_parameter
10
+ # parse_integer_parameter(param, arg)
11
+ # parse_float_parameter(param, arg)
12
+ # parse_io_parameter(param, arg)
13
+ # each_arg
14
+ # collect_argument_parameters
15
+
16
+ def test_help_needed
17
+ parser.opt "arg"
18
+ assert_raises(HelpNeeded) { parser.parse %w(-h) }
19
+ assert_raises(HelpNeeded) { parser.parse %w(--help) }
20
+ end
21
+
22
+ def test_help_overridden
23
+ parser.opt :arg1, "desc", :long => "help"
24
+ assert parser.parse(%w(-h))[:arg1]
25
+ assert parser.parse(%w(--help))[:arg1]
26
+ end
27
+
28
+ def test_help_with_other_args
29
+ parser.opt :arg1
30
+ assert_raises(HelpNeeded) { @p.parse %w(--arg1 --help) }
31
+ end
32
+
33
+ def test_help_with_arg_error
34
+ parser.opt :arg1, :type => String
35
+ assert_raises(HelpNeeded) { @p.parse %w(--arg1 --help) }
36
+ end
37
+
38
+ def test_version_needed_unset
39
+ parser.opt "arg"
40
+ assert_raises(CommandlineError) { parser.parse %w(-v) }
41
+ end
42
+
43
+ def test_version_needed
44
+ parser.version "optimist 5.2.3"
45
+ assert_raises(VersionNeeded) { parser.parse %w(-v) }
46
+ assert_raises(VersionNeeded) { parser.parse %w(--version) }
47
+ end
48
+
49
+ def test_version_overridden
50
+ parser.opt "version"
51
+ assert parser.parse(%w(-v))["version"]
52
+ assert parser.parse(%w(-v))[:version_given]
53
+ end
54
+
55
+ def test_version_only_appears_if_set
56
+ parser.opt "arg"
57
+ assert_raises(CommandlineError) { parser.parse %w(-v) }
58
+ end
59
+
60
+ def test_version_with_other_args
61
+ parser.opt :arg1
62
+ parser.version "1.1"
63
+ assert_raises(VersionNeeded) { parser.parse %w(--arg1 --version) }
64
+ end
65
+
66
+ def test_version_with_arg_error
67
+ parser.opt :arg1, :type => String
68
+ parser.version "1.1"
69
+ assert_raises(VersionNeeded) { parser.parse %w(--arg1 --version) }
70
+ end
71
+
72
+
73
+ private
74
+
75
+ def parser
76
+ @p ||= Parser.new
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,1220 @@
1
+ require 'stringio'
2
+ require 'test_helper'
3
+
4
+ module Optimist
5
+
6
+ class ParserTest < ::MiniTest::Test
7
+ def setup
8
+ @p = Parser.new
9
+ end
10
+
11
+ def parser
12
+ @p ||= Parser.new
13
+ end
14
+
15
+ # initialize
16
+ # cloaker
17
+
18
+ def test_version
19
+ assert_nil parser.version
20
+ assert_equal "optimist 5.2.3", parser.version("optimist 5.2.3")
21
+ assert_equal "optimist 5.2.3", parser.version
22
+ end
23
+
24
+ def test_usage
25
+ assert_nil parser.usage
26
+
27
+ assert_equal "usage string", parser.usage("usage string")
28
+ assert_equal "usage string", parser.usage
29
+ end
30
+
31
+ def test_synopsis
32
+ assert_nil parser.synopsis
33
+
34
+ assert_equal "synopsis string", parser.synopsis("synopsis string")
35
+ assert_equal "synopsis string", parser.synopsis
36
+ end
37
+
38
+ # def test_depends
39
+ # def test_conflicts
40
+ # def test_stop_on
41
+ # def test_stop_on_unknown
42
+
43
+ # die
44
+ # def test_die_educate_on_error
45
+
46
+
47
+ def test_unknown_arguments
48
+ assert_raises(CommandlineError) { @p.parse(%w(--arg)) }
49
+ @p.opt "arg"
50
+ @p.parse(%w(--arg))
51
+ assert_raises(CommandlineError) { @p.parse(%w(--arg2)) }
52
+ end
53
+
54
+ def test_syntax_check
55
+ @p.opt "arg"
56
+
57
+ @p.parse(%w(--arg))
58
+ @p.parse(%w(arg))
59
+ assert_raises(CommandlineError) { @p.parse(%w(---arg)) }
60
+ assert_raises(CommandlineError) { @p.parse(%w(-arg)) }
61
+ end
62
+
63
+ def test_required_flags_are_required
64
+ @p.opt "arg", "desc", :required => true
65
+ @p.opt "arg2", "desc", :required => false
66
+ @p.opt "arg3", "desc", :required => false
67
+
68
+ @p.parse(%w(--arg))
69
+ @p.parse(%w(--arg --arg2))
70
+ assert_raises(CommandlineError) { @p.parse(%w(--arg2)) }
71
+ assert_raises(CommandlineError) { @p.parse(%w(--arg2 --arg3)) }
72
+ end
73
+
74
+ ## flags that take an argument error unless given one
75
+ def test_argflags_demand_args
76
+ @p.opt "goodarg", "desc", :type => String
77
+ @p.opt "goodarg2", "desc", :type => String
78
+
79
+ @p.parse(%w(--goodarg goat))
80
+ assert_raises(CommandlineError) { @p.parse(%w(--goodarg --goodarg2 goat)) }
81
+ assert_raises(CommandlineError) { @p.parse(%w(--goodarg)) }
82
+ end
83
+
84
+ ## flags that don't take arguments ignore them
85
+ def test_arglessflags_refuse_args
86
+ @p.opt "goodarg"
87
+ @p.opt "goodarg2"
88
+ @p.parse(%w(--goodarg))
89
+ @p.parse(%w(--goodarg --goodarg2))
90
+ opts = @p.parse %w(--goodarg a)
91
+ assert_equal true, opts["goodarg"]
92
+ assert_equal ["a"], @p.leftovers
93
+ end
94
+
95
+ ## flags that require args of a specific type refuse args of other
96
+ ## types
97
+ def test_typed_args_refuse_args_of_other_types
98
+ @p.opt "goodarg", "desc", :type => :int
99
+ assert_raises(ArgumentError) { @p.opt "badarg", "desc", :type => :asdf }
100
+
101
+ @p.parse(%w(--goodarg 3))
102
+ assert_raises(CommandlineError) { @p.parse(%w(--goodarg 4.2)) }
103
+ assert_raises(CommandlineError) { @p.parse(%w(--goodarg hello)) }
104
+ end
105
+
106
+ ## type is correctly derived from :default
107
+ def test_type_correctly_derived_from_default
108
+ assert_raises(ArgumentError) { @p.opt "badarg", "desc", :default => [] }
109
+ assert_raises(ArgumentError) { @p.opt "badarg3", "desc", :default => [{1 => 2}] }
110
+ assert_raises(ArgumentError) { @p.opt "badarg4", "desc", :default => Hash.new }
111
+
112
+ # single arg: int
113
+ @p.opt "argsi", "desc", :default => 0
114
+ opts = @p.parse(%w(--))
115
+ assert_equal 0, opts["argsi"]
116
+ opts = @p.parse(%w(--argsi 4))
117
+ assert_equal 4, opts["argsi"]
118
+ opts = @p.parse(%w(--argsi=4))
119
+ assert_equal 4, opts["argsi"]
120
+ opts = @p.parse(%w(--argsi=-4))
121
+ assert_equal( -4, opts["argsi"])
122
+
123
+ assert_raises(CommandlineError) { @p.parse(%w(--argsi 4.2)) }
124
+ assert_raises(CommandlineError) { @p.parse(%w(--argsi hello)) }
125
+
126
+ # single arg: float
127
+ @p.opt "argsf", "desc", :default => 3.14
128
+ opts = @p.parse(%w(--))
129
+ assert_equal 3.14, opts["argsf"]
130
+ opts = @p.parse(%w(--argsf 2.41))
131
+ assert_equal 2.41, opts["argsf"]
132
+ opts = @p.parse(%w(--argsf 2))
133
+ assert_equal 2, opts["argsf"]
134
+ opts = @p.parse(%w(--argsf 1.0e-2))
135
+ assert_equal 1.0e-2, opts["argsf"]
136
+ assert_raises(CommandlineError) { @p.parse(%w(--argsf hello)) }
137
+
138
+ # single arg: date
139
+ date = Date.today
140
+ @p.opt "argsd", "desc", :default => date
141
+ opts = @p.parse(%w(--))
142
+ assert_equal Date.today, opts["argsd"]
143
+ opts = @p.parse(['--argsd', 'Jan 4, 2007'])
144
+ assert_equal Date.civil(2007, 1, 4), opts["argsd"]
145
+ assert_raises(CommandlineError) { @p.parse(%w(--argsd hello)) }
146
+
147
+ # single arg: string
148
+ @p.opt "argss", "desc", :default => "foobar"
149
+ opts = @p.parse(%w(--))
150
+ assert_equal "foobar", opts["argss"]
151
+ opts = @p.parse(%w(--argss 2.41))
152
+ assert_equal "2.41", opts["argss"]
153
+ opts = @p.parse(%w(--argss hello))
154
+ assert_equal "hello", opts["argss"]
155
+
156
+ # multi args: ints
157
+ @p.opt "argmi", "desc", :default => [3, 5]
158
+ opts = @p.parse(%w(--))
159
+ assert_equal [3, 5], opts["argmi"]
160
+ opts = @p.parse(%w(--argmi 4))
161
+ assert_equal [4], opts["argmi"]
162
+ assert_raises(CommandlineError) { @p.parse(%w(--argmi 4.2)) }
163
+ assert_raises(CommandlineError) { @p.parse(%w(--argmi hello)) }
164
+
165
+ # multi args: floats
166
+ @p.opt "argmf", "desc", :default => [3.34, 5.21]
167
+ opts = @p.parse(%w(--))
168
+ assert_equal [3.34, 5.21], opts["argmf"]
169
+ opts = @p.parse(%w(--argmf 2))
170
+ assert_equal [2], opts["argmf"]
171
+ opts = @p.parse(%w(--argmf 4.0))
172
+ assert_equal [4.0], opts["argmf"]
173
+ assert_raises(CommandlineError) { @p.parse(%w(--argmf hello)) }
174
+
175
+ # multi args: dates
176
+ dates = [Date.today, Date.civil(2007, 1, 4)]
177
+ @p.opt "argmd", "desc", :default => dates
178
+ opts = @p.parse(%w(--))
179
+ assert_equal dates, opts["argmd"]
180
+ opts = @p.parse(['--argmd', 'Jan 4, 2007'])
181
+ assert_equal [Date.civil(2007, 1, 4)], opts["argmd"]
182
+ assert_raises(CommandlineError) { @p.parse(%w(--argmd hello)) }
183
+
184
+ # multi args: strings
185
+ @p.opt "argmst", "desc", :default => %w(hello world)
186
+ opts = @p.parse(%w(--))
187
+ assert_equal %w(hello world), opts["argmst"]
188
+ opts = @p.parse(%w(--argmst 3.4))
189
+ assert_equal ["3.4"], opts["argmst"]
190
+ opts = @p.parse(%w(--argmst goodbye))
191
+ assert_equal ["goodbye"], opts["argmst"]
192
+ end
193
+
194
+ ## :type and :default must match if both are specified
195
+ def test_type_and_default_must_match
196
+ assert_raises(ArgumentError) { @p.opt "badarg", "desc", :type => :int, :default => "hello" }
197
+ assert_raises(ArgumentError) { @p.opt "badarg2", "desc", :type => :String, :default => 4 }
198
+ assert_raises(ArgumentError) { @p.opt "badarg2", "desc", :type => :String, :default => ["hi"] }
199
+ assert_raises(ArgumentError) { @p.opt "badarg2", "desc", :type => :ints, :default => [3.14] }
200
+
201
+ @p.opt "argsi", "desc", :type => :int, :default => 4
202
+ @p.opt "argsf", "desc", :type => :float, :default => 3.14
203
+ @p.opt "argsd", "desc", :type => :date, :default => Date.today
204
+ @p.opt "argss", "desc", :type => :string, :default => "yo"
205
+ @p.opt "argmi", "desc", :type => :ints, :default => [4]
206
+ @p.opt "argmf", "desc", :type => :floats, :default => [3.14]
207
+ @p.opt "argmd", "desc", :type => :dates, :default => [Date.today]
208
+ @p.opt "argmst", "desc", :type => :strings, :default => ["yo"]
209
+ end
210
+
211
+ ##
212
+ def test_flags_with_defaults_and_no_args_act_as_switches
213
+ @p.opt :argd, "desc", :default => "default_string"
214
+
215
+ opts = @p.parse(%w(--))
216
+ assert !opts[:argd_given]
217
+ assert_equal "default_string", opts[:argd]
218
+
219
+ opts = @p.parse(%w( --argd ))
220
+ assert opts[:argd_given]
221
+ assert_equal "default_string", opts[:argd]
222
+
223
+ opts = @p.parse(%w(--argd different_string))
224
+ assert opts[:argd_given]
225
+ assert_equal "different_string", opts[:argd]
226
+ end
227
+
228
+ def test_flag_with_no_defaults_and_no_args_act_as_switches_array
229
+ opts = nil
230
+
231
+ @p.opt :argd, "desc", :type => :strings, :default => ["default_string"]
232
+
233
+ opts = @p.parse(%w(--argd))
234
+ assert_equal ["default_string"], opts[:argd]
235
+ end
236
+
237
+ def test_type_and_empty_array
238
+ @p.opt "argmi", "desc", :type => :ints, :default => []
239
+ @p.opt "argmf", "desc", :type => :floats, :default => []
240
+ @p.opt "argmd", "desc", :type => :dates, :default => []
241
+ @p.opt "argms", "desc", :type => :strings, :default => []
242
+ assert_raises(ArgumentError) { @p.opt "badi", "desc", :type => :int, :default => [] }
243
+ assert_raises(ArgumentError) { @p.opt "badf", "desc", :type => :float, :default => [] }
244
+ assert_raises(ArgumentError) { @p.opt "badd", "desc", :type => :date, :default => [] }
245
+ assert_raises(ArgumentError) { @p.opt "bads", "desc", :type => :string, :default => [] }
246
+ opts = @p.parse([])
247
+ assert_equal(opts["argmi"], [])
248
+ assert_equal(opts["argmf"], [])
249
+ assert_equal(opts["argmd"], [])
250
+ assert_equal(opts["argms"], [])
251
+ end
252
+
253
+ def test_long_detects_bad_names
254
+ @p.opt "goodarg", "desc", :long => "none"
255
+ @p.opt "goodarg2", "desc", :long => "--two"
256
+ assert_raises(ArgumentError) { @p.opt "badarg", "desc", :long => "" }
257
+ assert_raises(ArgumentError) { @p.opt "badarg2", "desc", :long => "--" }
258
+ assert_raises(ArgumentError) { @p.opt "badarg3", "desc", :long => "-one" }
259
+ assert_raises(ArgumentError) { @p.opt "badarg4", "desc", :long => "---toomany" }
260
+ end
261
+
262
+ def test_short_detects_bad_names
263
+ @p.opt "goodarg", "desc", :short => "a"
264
+ @p.opt "goodarg2", "desc", :short => "-b"
265
+ assert_raises(ArgumentError) { @p.opt "badarg", "desc", :short => "" }
266
+ assert_raises(ArgumentError) { @p.opt "badarg2", "desc", :short => "-ab" }
267
+ assert_raises(ArgumentError) { @p.opt "badarg3", "desc", :short => "--t" }
268
+ end
269
+
270
+ def test_short_names_created_automatically
271
+ @p.opt "arg"
272
+ @p.opt "arg2"
273
+ @p.opt "arg3"
274
+ opts = @p.parse %w(-a -g)
275
+ assert_equal true, opts["arg"]
276
+ assert_equal false, opts["arg2"]
277
+ assert_equal true, opts["arg3"]
278
+ end
279
+
280
+ def test_short_autocreation_skips_dashes_and_numbers
281
+ @p.opt :arg # auto: a
282
+ @p.opt :arg_potato # auto: r
283
+ @p.opt :arg_muffin # auto: g
284
+ @p.opt :arg_daisy # auto: d (not _)!
285
+ @p.opt :arg_r2d2f # auto: f (not 2)!
286
+
287
+ opts = @p.parse %w(-f -d)
288
+ assert_equal true, opts[:arg_daisy]
289
+ assert_equal true, opts[:arg_r2d2f]
290
+ assert_equal false, opts[:arg]
291
+ assert_equal false, opts[:arg_potato]
292
+ assert_equal false, opts[:arg_muffin]
293
+ end
294
+
295
+ def test_short_autocreation_is_ok_with_running_out_of_chars
296
+ @p.opt :arg1 # auto: a
297
+ @p.opt :arg2 # auto: r
298
+ @p.opt :arg3 # auto: g
299
+ @p.opt :arg4 # auto: uh oh!
300
+ @p.parse []
301
+ end
302
+
303
+ def test_short_can_be_nothing
304
+ @p.opt "arg", "desc", :short => :none
305
+ @p.parse []
306
+
307
+ sio = StringIO.new "w"
308
+ @p.educate sio
309
+ assert sio.string =~ /--arg\s+desc/
310
+
311
+ assert_raises(CommandlineError) { @p.parse %w(-a) }
312
+ end
313
+
314
+ ## two args can't have the same name
315
+ def test_conflicting_names_are_detected
316
+ @p.opt "goodarg"
317
+ assert_raises(ArgumentError) { @p.opt "goodarg" }
318
+ end
319
+
320
+ ## two args can't have the same :long
321
+ def test_conflicting_longs_detected
322
+ @p.opt "goodarg", "desc", :long => "--goodarg"
323
+ assert_raises(ArgumentError) { @p.opt "badarg", "desc", :long => "--goodarg" }
324
+ end
325
+
326
+ ## two args can't have the same :short
327
+ def test_conflicting_shorts_detected
328
+ @p.opt "goodarg", "desc", :short => "-g"
329
+ assert_raises(ArgumentError) { @p.opt "badarg", "desc", :short => "-g" }
330
+ end
331
+
332
+ ## note: this behavior has changed in optimist 2.0!
333
+ def test_flag_parameters
334
+ @p.opt :defaultnone, "desc"
335
+ @p.opt :defaultfalse, "desc", :default => false
336
+ @p.opt :defaulttrue, "desc", :default => true
337
+
338
+ ## default state
339
+ opts = @p.parse []
340
+ assert_equal false, opts[:defaultnone]
341
+ assert_equal false, opts[:defaultfalse]
342
+ assert_equal true, opts[:defaulttrue]
343
+
344
+ ## specifying turns them on, regardless of default
345
+ opts = @p.parse %w(--defaultfalse --defaulttrue --defaultnone)
346
+ assert_equal true, opts[:defaultnone]
347
+ assert_equal true, opts[:defaultfalse]
348
+ assert_equal true, opts[:defaulttrue]
349
+
350
+ ## using --no- form turns them off, regardless of default
351
+ opts = @p.parse %w(--no-defaultfalse --no-defaulttrue --no-defaultnone)
352
+ assert_equal false, opts[:defaultnone]
353
+ assert_equal false, opts[:defaultfalse]
354
+ assert_equal false, opts[:defaulttrue]
355
+ end
356
+
357
+ ## note: this behavior has changed in optimist 2.0!
358
+ def test_flag_parameters_for_inverted_flags
359
+ @p.opt :no_default_none, "desc"
360
+ @p.opt :no_default_false, "desc", :default => false
361
+ @p.opt :no_default_true, "desc", :default => true
362
+
363
+ ## default state
364
+ opts = @p.parse []
365
+ assert_equal false, opts[:no_default_none]
366
+ assert_equal false, opts[:no_default_false]
367
+ assert_equal true, opts[:no_default_true]
368
+
369
+ ## specifying turns them all on, regardless of default
370
+ opts = @p.parse %w(--no-default-false --no-default-true --no-default-none)
371
+ assert_equal true, opts[:no_default_none]
372
+ assert_equal true, opts[:no_default_false]
373
+ assert_equal true, opts[:no_default_true]
374
+
375
+ ## using dropped-no form turns them all off, regardless of default
376
+ opts = @p.parse %w(--default-false --default-true --default-none)
377
+ assert_equal false, opts[:no_default_none]
378
+ assert_equal false, opts[:no_default_false]
379
+ assert_equal false, opts[:no_default_true]
380
+
381
+ ## disallow double negatives for reasons of sanity preservation
382
+ assert_raises(CommandlineError) { @p.parse %w(--no-no-default-true) }
383
+ end
384
+
385
+ def test_short_options_combine
386
+ @p.opt :arg1, "desc", :short => "a"
387
+ @p.opt :arg2, "desc", :short => "b"
388
+ @p.opt :arg3, "desc", :short => "c", :type => :int
389
+
390
+ opts = @p.parse %w(-a -b)
391
+ assert_equal true, opts[:arg1]
392
+ assert_equal true, opts[:arg2]
393
+ assert_equal nil, opts[:arg3]
394
+
395
+ opts = @p.parse %w(-ab)
396
+ assert_equal true, opts[:arg1]
397
+ assert_equal true, opts[:arg2]
398
+ assert_equal nil, opts[:arg3]
399
+
400
+ opts = @p.parse %w(-ac 4 -b)
401
+ assert_equal true, opts[:arg1]
402
+ assert_equal true, opts[:arg2]
403
+ assert_equal 4, opts[:arg3]
404
+
405
+ assert_raises(CommandlineError) { @p.parse %w(-cab 4) }
406
+ assert_raises(CommandlineError) { @p.parse %w(-cba 4) }
407
+ end
408
+
409
+ def test_doubledash_ends_option_processing
410
+ @p.opt :arg1, "desc", :short => "a", :default => 0
411
+ @p.opt :arg2, "desc", :short => "b", :default => 0
412
+ opts = @p.parse %w(-- -a 3 -b 2)
413
+ assert_equal opts[:arg1], 0
414
+ assert_equal opts[:arg2], 0
415
+ assert_equal %w(-a 3 -b 2), @p.leftovers
416
+ opts = @p.parse %w(-a 3 -- -b 2)
417
+ assert_equal opts[:arg1], 3
418
+ assert_equal opts[:arg2], 0
419
+ assert_equal %w(-b 2), @p.leftovers
420
+ opts = @p.parse %w(-a 3 -b 2 --)
421
+ assert_equal opts[:arg1], 3
422
+ assert_equal opts[:arg2], 2
423
+ assert_equal %w(), @p.leftovers
424
+ end
425
+
426
+ def test_wrap
427
+ assert_equal [""], @p.wrap("")
428
+ assert_equal ["a"], @p.wrap("a")
429
+ assert_equal ["one two", "three"], @p.wrap("one two three", :width => 8)
430
+ assert_equal ["one two three"], @p.wrap("one two three", :width => 80)
431
+ assert_equal ["one", "two", "three"], @p.wrap("one two three", :width => 3)
432
+ assert_equal ["onetwothree"], @p.wrap("onetwothree", :width => 3)
433
+ assert_equal [
434
+ "Test is an awesome program that does something very, very important.",
435
+ "",
436
+ "Usage:",
437
+ " test [options] <filenames>+",
438
+ "where [options] are:"], @p.wrap(<<EOM, :width => 100)
439
+ Test is an awesome program that does something very, very important.
440
+
441
+ Usage:
442
+ test [options] <filenames>+
443
+ where [options] are:
444
+ EOM
445
+ end
446
+
447
+ def test_multi_line_description
448
+ out = StringIO.new
449
+ @p.opt :arg, <<-EOM, :type => :int
450
+ This is an arg
451
+ with a multi-line description
452
+ EOM
453
+ @p.educate(out)
454
+ assert_equal <<-EOM, out.string
455
+ Options:
456
+ --arg=<i> This is an arg
457
+ with a multi-line description
458
+ EOM
459
+ end
460
+
461
+ def test_integer_formatting
462
+ @p.opt :arg, "desc", :type => :integer, :short => "i"
463
+ opts = @p.parse %w(-i 5)
464
+ assert_equal 5, opts[:arg]
465
+ end
466
+
467
+ def test_integer_formatting
468
+ @p.opt :arg, "desc", :type => :integer, :short => "i", :default => 3
469
+ opts = @p.parse %w(-i)
470
+ assert_equal 3, opts[:arg]
471
+ end
472
+
473
+ def test_floating_point_formatting
474
+ @p.opt :arg, "desc", :type => :float, :short => "f"
475
+ opts = @p.parse %w(-f 1)
476
+ assert_equal 1.0, opts[:arg]
477
+ opts = @p.parse %w(-f 1.0)
478
+ assert_equal 1.0, opts[:arg]
479
+ opts = @p.parse %w(-f 0.1)
480
+ assert_equal 0.1, opts[:arg]
481
+ opts = @p.parse %w(-f .1)
482
+ assert_equal 0.1, opts[:arg]
483
+ opts = @p.parse %w(-f .99999999999999999999)
484
+ assert_equal 1.0, opts[:arg]
485
+ opts = @p.parse %w(-f -1)
486
+ assert_equal(-1.0, opts[:arg])
487
+ opts = @p.parse %w(-f -1.0)
488
+ assert_equal(-1.0, opts[:arg])
489
+ opts = @p.parse %w(-f -0.1)
490
+ assert_equal(-0.1, opts[:arg])
491
+ opts = @p.parse %w(-f -.1)
492
+ assert_equal(-0.1, opts[:arg])
493
+ assert_raises(CommandlineError) { @p.parse %w(-f a) }
494
+ assert_raises(CommandlineError) { @p.parse %w(-f 1a) }
495
+ assert_raises(CommandlineError) { @p.parse %w(-f 1.a) }
496
+ assert_raises(CommandlineError) { @p.parse %w(-f a.1) }
497
+ assert_raises(CommandlineError) { @p.parse %w(-f 1.0.0) }
498
+ assert_raises(CommandlineError) { @p.parse %w(-f .) }
499
+ assert_raises(CommandlineError) { @p.parse %w(-f -.) }
500
+ end
501
+
502
+ def test_floating_point_formatting_default
503
+ @p.opt :arg, "desc", :type => :float, :short => "f", :default => 5.5
504
+ opts = @p.parse %w(-f)
505
+ assert_equal 5.5, opts[:arg]
506
+ end
507
+
508
+ def test_date_formatting
509
+ @p.opt :arg, "desc", :type => :date, :short => 'd'
510
+ opts = @p.parse(['-d', 'Jan 4, 2007'])
511
+ assert_equal Date.civil(2007, 1, 4), opts[:arg]
512
+ opts = @p.parse(['-d', 'today'])
513
+ assert_equal Date.today, opts[:arg]
514
+ end
515
+
516
+ def test_short_options_cant_be_numeric
517
+ assert_raises(ArgumentError) { @p.opt :arg, "desc", :short => "-1" }
518
+ @p.opt :a1b, "desc"
519
+ @p.opt :a2b, "desc"
520
+ assert @p.specs[:a2b].short.to_i == 0
521
+ end
522
+
523
+ def test_short_options_can_be_weird
524
+ @p.opt :arg1, "desc", :short => "#"
525
+ @p.opt :arg2, "desc", :short => "."
526
+ assert_raises(ArgumentError) { @p.opt :arg3, "desc", :short => "-" }
527
+ end
528
+
529
+ def test_options_cant_be_set_multiple_times_if_not_specified
530
+ @p.opt :arg, "desc", :short => "-x"
531
+ @p.parse %w(-x)
532
+ assert_raises(CommandlineError) { @p.parse %w(-x -x) }
533
+ assert_raises(CommandlineError) { @p.parse %w(-xx) }
534
+ end
535
+
536
+ def test_options_can_be_set_multiple_times_if_specified
537
+ @p.opt :arg, "desc", :short => "-x", :multi => true
538
+ @p.parse %w(-x)
539
+ @p.parse %w(-x -x)
540
+ @p.parse %w(-xx)
541
+ end
542
+
543
+ def test_short_options_with_multiple_options
544
+ @p.opt :xarg, "desc", :short => "-x", :type => String, :multi => true
545
+ opts = @p.parse %w(-x a -x b)
546
+ assert_equal %w(a b), opts[:xarg]
547
+ assert_equal [], @p.leftovers
548
+ end
549
+
550
+ def test_short_options_with_multiple_options_does_not_affect_flags_type
551
+ @p.opt :xarg, "desc", :short => "-x", :type => :flag, :multi => true
552
+
553
+ opts = @p.parse %w(-x a)
554
+ assert_equal true, opts[:xarg]
555
+ assert_equal %w(a), @p.leftovers
556
+
557
+ opts = @p.parse %w(-x a -x b)
558
+ assert_equal true, opts[:xarg]
559
+ assert_equal %w(a b), @p.leftovers
560
+
561
+ opts = @p.parse %w(-xx a -x b)
562
+ assert_equal true, opts[:xarg]
563
+ assert_equal %w(a b), @p.leftovers
564
+ end
565
+
566
+ def test_short_options_with_multiple_arguments
567
+ @p.opt :xarg, "desc", :type => :ints
568
+ opts = @p.parse %w(-x 3 4 0)
569
+ assert_equal [3, 4, 0], opts[:xarg]
570
+ assert_equal [], @p.leftovers
571
+
572
+ @p.opt :yarg, "desc", :type => :floats
573
+ opts = @p.parse %w(-y 3.14 4.21 0.66)
574
+ assert_equal [3.14, 4.21, 0.66], opts[:yarg]
575
+ assert_equal [], @p.leftovers
576
+
577
+ @p.opt :zarg, "desc", :type => :strings
578
+ opts = @p.parse %w(-z a b c)
579
+ assert_equal %w(a b c), opts[:zarg]
580
+ assert_equal [], @p.leftovers
581
+ end
582
+
583
+ def test_short_options_with_multiple_options_and_arguments
584
+ @p.opt :xarg, "desc", :type => :ints, :multi => true
585
+ opts = @p.parse %w(-x 3 4 5 -x 6 7)
586
+ assert_equal [[3, 4, 5], [6, 7]], opts[:xarg]
587
+ assert_equal [], @p.leftovers
588
+
589
+ @p.opt :yarg, "desc", :type => :floats, :multi => true
590
+ opts = @p.parse %w(-y 3.14 4.21 5.66 -y 6.99 7.01)
591
+ assert_equal [[3.14, 4.21, 5.66], [6.99, 7.01]], opts[:yarg]
592
+ assert_equal [], @p.leftovers
593
+
594
+ @p.opt :zarg, "desc", :type => :strings, :multi => true
595
+ opts = @p.parse %w(-z a b c -z d e)
596
+ assert_equal [%w(a b c), %w(d e)], opts[:zarg]
597
+ assert_equal [], @p.leftovers
598
+ end
599
+
600
+ def test_combined_short_options_with_multiple_arguments
601
+ @p.opt :arg1, "desc", :short => "a"
602
+ @p.opt :arg2, "desc", :short => "b"
603
+ @p.opt :arg3, "desc", :short => "c", :type => :ints
604
+ @p.opt :arg4, "desc", :short => "d", :type => :floats
605
+
606
+ opts = @p.parse %w(-abc 4 6 9)
607
+ assert_equal true, opts[:arg1]
608
+ assert_equal true, opts[:arg2]
609
+ assert_equal [4, 6, 9], opts[:arg3]
610
+
611
+ opts = @p.parse %w(-ac 4 6 9 -bd 3.14 2.41)
612
+ assert_equal true, opts[:arg1]
613
+ assert_equal true, opts[:arg2]
614
+ assert_equal [4, 6, 9], opts[:arg3]
615
+ assert_equal [3.14, 2.41], opts[:arg4]
616
+
617
+ assert_raises(CommandlineError) { opts = @p.parse %w(-abcd 3.14 2.41) }
618
+ end
619
+
620
+ def test_long_options_with_multiple_options
621
+ @p.opt :xarg, "desc", :type => String, :multi => true
622
+ opts = @p.parse %w(--xarg=a --xarg=b)
623
+ assert_equal %w(a b), opts[:xarg]
624
+ assert_equal [], @p.leftovers
625
+ opts = @p.parse %w(--xarg a --xarg b)
626
+ assert_equal %w(a b), opts[:xarg]
627
+ assert_equal [], @p.leftovers
628
+ end
629
+
630
+ def test_long_options_with_multiple_arguments
631
+ @p.opt :xarg, "desc", :type => :ints
632
+ opts = @p.parse %w(--xarg 3 2 5)
633
+ assert_equal [3, 2, 5], opts[:xarg]
634
+ assert_equal [], @p.leftovers
635
+ opts = @p.parse %w(--xarg=3)
636
+ assert_equal [3], opts[:xarg]
637
+ assert_equal [], @p.leftovers
638
+
639
+ @p.opt :yarg, "desc", :type => :floats
640
+ opts = @p.parse %w(--yarg 3.14 2.41 5.66)
641
+ assert_equal [3.14, 2.41, 5.66], opts[:yarg]
642
+ assert_equal [], @p.leftovers
643
+ opts = @p.parse %w(--yarg=3.14)
644
+ assert_equal [3.14], opts[:yarg]
645
+ assert_equal [], @p.leftovers
646
+
647
+ @p.opt :zarg, "desc", :type => :strings
648
+ opts = @p.parse %w(--zarg a b c)
649
+ assert_equal %w(a b c), opts[:zarg]
650
+ assert_equal [], @p.leftovers
651
+ opts = @p.parse %w(--zarg=a)
652
+ assert_equal %w(a), opts[:zarg]
653
+ assert_equal [], @p.leftovers
654
+ end
655
+
656
+ def test_long_options_with_multiple_options_and_arguments
657
+ @p.opt :xarg, "desc", :type => :ints, :multi => true
658
+ opts = @p.parse %w(--xarg 3 2 5 --xarg 2 1)
659
+ assert_equal [[3, 2, 5], [2, 1]], opts[:xarg]
660
+ assert_equal [], @p.leftovers
661
+ opts = @p.parse %w(--xarg=3 --xarg=2)
662
+ assert_equal [[3], [2]], opts[:xarg]
663
+ assert_equal [], @p.leftovers
664
+
665
+ @p.opt :yarg, "desc", :type => :floats, :multi => true
666
+ opts = @p.parse %w(--yarg 3.14 2.72 5 --yarg 2.41 1.41)
667
+ assert_equal [[3.14, 2.72, 5], [2.41, 1.41]], opts[:yarg]
668
+ assert_equal [], @p.leftovers
669
+ opts = @p.parse %w(--yarg=3.14 --yarg=2.41)
670
+ assert_equal [[3.14], [2.41]], opts[:yarg]
671
+ assert_equal [], @p.leftovers
672
+
673
+ @p.opt :zarg, "desc", :type => :strings, :multi => true
674
+ opts = @p.parse %w(--zarg a b c --zarg d e)
675
+ assert_equal [%w(a b c), %w(d e)], opts[:zarg]
676
+ assert_equal [], @p.leftovers
677
+ opts = @p.parse %w(--zarg=a --zarg=d)
678
+ assert_equal [%w(a), %w(d)], opts[:zarg]
679
+ assert_equal [], @p.leftovers
680
+ end
681
+
682
+ def test_long_options_also_take_equals
683
+ @p.opt :arg, "desc", :long => "arg", :type => String, :default => "hello"
684
+ opts = @p.parse %w()
685
+ assert_equal "hello", opts[:arg]
686
+ opts = @p.parse %w(--arg goat)
687
+ assert_equal "goat", opts[:arg]
688
+ opts = @p.parse %w(--arg=goat)
689
+ assert_equal "goat", opts[:arg]
690
+ ## actually, this next one is valid. empty string for --arg, and goat as a
691
+ ## leftover.
692
+ ## assert_raises(CommandlineError) { opts = @p.parse %w(--arg= goat) }
693
+ end
694
+
695
+ def test_auto_generated_long_names_convert_underscores_to_hyphens
696
+ @p.opt :hello_there
697
+ assert_equal "hello-there", @p.specs[:hello_there].long
698
+ end
699
+
700
+ def test_arguments_passed_through_block
701
+ @goat = 3
702
+ boat = 4
703
+ Parser.new(@goat) do |goat|
704
+ boat = goat
705
+ end
706
+ assert_equal @goat, boat
707
+ end
708
+
709
+ def test_version_and_help_override_errors
710
+ @p.opt :asdf, "desc", :type => String
711
+ @p.version "version"
712
+ @p.parse %w(--asdf goat)
713
+ assert_raises(CommandlineError) { @p.parse %w(--asdf) }
714
+ assert_raises(HelpNeeded) { @p.parse %w(--asdf --help) }
715
+ assert_raises(VersionNeeded) { @p.parse %w(--asdf --version) }
716
+ end
717
+
718
+ def test_conflicts
719
+ @p.opt :one
720
+ assert_raises(ArgumentError) { @p.conflicts :one, :two }
721
+ @p.opt :two
722
+ @p.conflicts :one, :two
723
+ @p.parse %w(--one)
724
+ @p.parse %w(--two)
725
+ assert_raises(CommandlineError) { @p.parse %w(--one --two) }
726
+
727
+ @p.opt :hello
728
+ @p.opt :yellow
729
+ @p.opt :mellow
730
+ @p.opt :jello
731
+ @p.conflicts :hello, :yellow, :mellow, :jello
732
+ assert_raises(CommandlineError) { @p.parse %w(--hello --yellow --mellow --jello) }
733
+ assert_raises(CommandlineError) { @p.parse %w(--hello --mellow --jello) }
734
+ assert_raises(CommandlineError) { @p.parse %w(--hello --jello) }
735
+
736
+ @p.parse %w(--hello)
737
+ @p.parse %w(--jello)
738
+ @p.parse %w(--yellow)
739
+ @p.parse %w(--mellow)
740
+
741
+ @p.parse %w(--mellow --one)
742
+ @p.parse %w(--mellow --two)
743
+
744
+ assert_raises(CommandlineError) { @p.parse %w(--mellow --two --jello) }
745
+ assert_raises(CommandlineError) { @p.parse %w(--one --mellow --two --jello) }
746
+ end
747
+
748
+ def test_conflict_error_messages
749
+ @p.opt :one
750
+ @p.opt "two"
751
+ @p.conflicts :one, "two"
752
+
753
+ assert_raises(CommandlineError, /--one.*--two/) { @p.parse %w(--one --two) }
754
+ end
755
+
756
+ def test_depends
757
+ @p.opt :one
758
+ assert_raises(ArgumentError) { @p.depends :one, :two }
759
+ @p.opt :two
760
+ @p.depends :one, :two
761
+ @p.parse %w(--one --two)
762
+ assert_raises(CommandlineError) { @p.parse %w(--one) }
763
+ assert_raises(CommandlineError) { @p.parse %w(--two) }
764
+
765
+ @p.opt :hello
766
+ @p.opt :yellow
767
+ @p.opt :mellow
768
+ @p.opt :jello
769
+ @p.depends :hello, :yellow, :mellow, :jello
770
+ @p.parse %w(--hello --yellow --mellow --jello)
771
+ assert_raises(CommandlineError) { @p.parse %w(--hello --mellow --jello) }
772
+ assert_raises(CommandlineError) { @p.parse %w(--hello --jello) }
773
+
774
+ assert_raises(CommandlineError) { @p.parse %w(--hello) }
775
+ assert_raises(CommandlineError) { @p.parse %w(--mellow) }
776
+
777
+ @p.parse %w(--hello --yellow --mellow --jello --one --two)
778
+ @p.parse %w(--hello --yellow --mellow --jello --one --two a b c)
779
+
780
+ assert_raises(CommandlineError) { @p.parse %w(--mellow --two --jello --one) }
781
+ end
782
+
783
+ def test_depend_error_messages
784
+ @p.opt :one
785
+ @p.opt "two"
786
+ @p.depends :one, "two"
787
+
788
+ @p.parse %w(--one --two)
789
+
790
+ assert_raises(CommandlineError, /--one.*--two/) { @p.parse %w(--one) }
791
+ assert_raises(CommandlineError, /--one.*--two/) { @p.parse %w(--two) }
792
+ end
793
+
794
+ ## courtesy neill zero
795
+ def test_two_required_one_missing_accuses_correctly
796
+ @p.opt "arg1", "desc1", :required => true
797
+ @p.opt "arg2", "desc2", :required => true
798
+
799
+ assert_raises(CommandlineError, /arg2/) { @p.parse(%w(--arg1)) }
800
+ assert_raises(CommandlineError, /arg1/) { @p.parse(%w(--arg2)) }
801
+ @p.parse(%w(--arg1 --arg2))
802
+ end
803
+
804
+ def test_stopwords_mixed
805
+ @p.opt "arg1", :default => false
806
+ @p.opt "arg2", :default => false
807
+ @p.stop_on %w(happy sad)
808
+
809
+ opts = @p.parse %w(--arg1 happy --arg2)
810
+ assert_equal true, opts["arg1"]
811
+ assert_equal false, opts["arg2"]
812
+
813
+ ## restart parsing
814
+ @p.leftovers.shift
815
+ opts = @p.parse @p.leftovers
816
+ assert_equal false, opts["arg1"]
817
+ assert_equal true, opts["arg2"]
818
+ end
819
+
820
+ def test_stopwords_no_stopwords
821
+ @p.opt "arg1", :default => false
822
+ @p.opt "arg2", :default => false
823
+ @p.stop_on %w(happy sad)
824
+
825
+ opts = @p.parse %w(--arg1 --arg2)
826
+ assert_equal true, opts["arg1"]
827
+ assert_equal true, opts["arg2"]
828
+
829
+ ## restart parsing
830
+ @p.leftovers.shift
831
+ opts = @p.parse @p.leftovers
832
+ assert_equal false, opts["arg1"]
833
+ assert_equal false, opts["arg2"]
834
+ end
835
+
836
+ def test_stopwords_multiple_stopwords
837
+ @p.opt "arg1", :default => false
838
+ @p.opt "arg2", :default => false
839
+ @p.stop_on %w(happy sad)
840
+
841
+ opts = @p.parse %w(happy sad --arg1 --arg2)
842
+ assert_equal false, opts["arg1"]
843
+ assert_equal false, opts["arg2"]
844
+
845
+ ## restart parsing
846
+ @p.leftovers.shift
847
+ opts = @p.parse @p.leftovers
848
+ assert_equal false, opts["arg1"]
849
+ assert_equal false, opts["arg2"]
850
+
851
+ ## restart parsing again
852
+ @p.leftovers.shift
853
+ opts = @p.parse @p.leftovers
854
+ assert_equal true, opts["arg1"]
855
+ assert_equal true, opts["arg2"]
856
+ end
857
+
858
+ def test_stopwords_with_short_args
859
+ @p.opt :global_option, "This is a global option", :short => "-g"
860
+ @p.stop_on %w(sub-command-1 sub-command-2)
861
+
862
+ global_opts = @p.parse %w(-g sub-command-1 -c)
863
+ cmd = @p.leftovers.shift
864
+
865
+ @q = Parser.new
866
+ @q.opt :cmd_option, "This is an option only for the subcommand", :short => "-c"
867
+ cmd_opts = @q.parse @p.leftovers
868
+
869
+ assert_equal true, global_opts[:global_option]
870
+ assert_nil global_opts[:cmd_option]
871
+
872
+ assert_equal true, cmd_opts[:cmd_option]
873
+ assert_nil cmd_opts[:global_option]
874
+
875
+ assert_equal cmd, "sub-command-1"
876
+ assert_equal @q.leftovers, []
877
+ end
878
+
879
+ def test_unknown_subcommand
880
+ @p.opt :global_flag, "Global flag", :short => "-g", :type => :flag
881
+ @p.opt :global_param, "Global parameter", :short => "-p", :default => 5
882
+ @p.stop_on_unknown
883
+
884
+ expected_opts = { :global_flag => true, :help => false, :global_param => 5, :global_flag_given => true }
885
+ expected_leftovers = [ "my_subcommand", "-c" ]
886
+
887
+ assert_parses_correctly @p, %w(--global-flag my_subcommand -c), \
888
+ expected_opts, expected_leftovers
889
+ assert_parses_correctly @p, %w(-g my_subcommand -c), \
890
+ expected_opts, expected_leftovers
891
+
892
+ expected_opts = { :global_flag => false, :help => false, :global_param => 5, :global_param_given => true }
893
+ expected_leftovers = [ "my_subcommand", "-c" ]
894
+
895
+ assert_parses_correctly @p, %w(-p 5 my_subcommand -c), \
896
+ expected_opts, expected_leftovers
897
+ assert_parses_correctly @p, %w(--global-param 5 my_subcommand -c), \
898
+ expected_opts, expected_leftovers
899
+ end
900
+
901
+ def test_alternate_args
902
+ args = %w(-a -b -c)
903
+
904
+ opts = ::Optimist.options(args) do
905
+ opt :alpher, "Ralph Alpher", :short => "-a"
906
+ opt :bethe, "Hans Bethe", :short => "-b"
907
+ opt :gamow, "George Gamow", :short => "-c"
908
+ end
909
+
910
+ physicists_with_humor = [:alpher, :bethe, :gamow]
911
+ physicists_with_humor.each do |physicist|
912
+ assert_equal true, opts[physicist]
913
+ end
914
+ end
915
+
916
+ def test_date_arg_type
917
+ temp = Date.new
918
+ @p.opt :arg, 'desc', :type => :date
919
+ @p.opt :arg2, 'desc', :type => Date
920
+ @p.opt :arg3, 'desc', :default => temp
921
+
922
+ opts = @p.parse []
923
+ assert_equal temp, opts[:arg3]
924
+
925
+ opts = @p.parse %w(--arg 5/1/2010)
926
+ assert_kind_of Date, opts[:arg]
927
+ assert_equal Date.new(2010, 5, 1), opts[:arg]
928
+
929
+ opts = @p.parse %w(--arg2 5/1/2010)
930
+ assert_kind_of Date, opts[:arg2]
931
+ assert_equal Date.new(2010, 5, 1), opts[:arg2]
932
+
933
+ opts = @p.parse %w(--arg3)
934
+ assert_equal temp, opts[:arg3]
935
+ end
936
+
937
+ def test_unknown_arg_class_type
938
+ assert_raises ArgumentError do
939
+ @p.opt :arg, 'desc', :type => Hash
940
+ end
941
+ end
942
+
943
+ def test_io_arg_type
944
+ @p.opt :arg, "desc", :type => :io
945
+ @p.opt :arg2, "desc", :type => IO
946
+ @p.opt :arg3, "desc", :default => $stdout
947
+
948
+ opts = @p.parse []
949
+ assert_equal $stdout, opts[:arg3]
950
+
951
+ opts = @p.parse %w(--arg /dev/null)
952
+ assert_kind_of File, opts[:arg]
953
+ assert_equal "/dev/null", opts[:arg].path
954
+
955
+ #TODO: move to mocks
956
+ #opts = @p.parse %w(--arg2 http://google.com/)
957
+ #assert_kind_of StringIO, opts[:arg2]
958
+
959
+ opts = @p.parse %w(--arg3 stdin)
960
+ assert_equal $stdin, opts[:arg3]
961
+
962
+ assert_raises(CommandlineError) { opts = @p.parse %w(--arg /fdasfasef/fessafef/asdfasdfa/fesasf) }
963
+ end
964
+
965
+ def test_openstruct_style_access
966
+ @p.opt "arg1", "desc", :type => :int
967
+ @p.opt :arg2, "desc", :type => :int
968
+
969
+ opts = @p.parse(%w(--arg1 3 --arg2 4))
970
+
971
+ opts.arg1
972
+ opts.arg2
973
+ assert_equal 3, opts.arg1
974
+ assert_equal 4, opts.arg2
975
+ end
976
+
977
+ def test_multi_args_autobox_defaults
978
+ @p.opt :arg1, "desc", :default => "hello", :multi => true
979
+ @p.opt :arg2, "desc", :default => ["hello"], :multi => true
980
+
981
+ opts = @p.parse []
982
+ assert_equal ["hello"], opts[:arg1]
983
+ assert_equal ["hello"], opts[:arg2]
984
+
985
+ opts = @p.parse %w(--arg1 hello)
986
+ assert_equal ["hello"], opts[:arg1]
987
+ assert_equal ["hello"], opts[:arg2]
988
+
989
+ opts = @p.parse %w(--arg1 hello --arg1 there)
990
+ assert_equal ["hello", "there"], opts[:arg1]
991
+ end
992
+
993
+ def test_ambigious_multi_plus_array_default_resolved_as_specified_by_documentation
994
+ @p.opt :arg1, "desc", :default => ["potato"], :multi => true
995
+ @p.opt :arg2, "desc", :default => ["potato"], :multi => true, :type => :strings
996
+ @p.opt :arg3, "desc", :default => ["potato"]
997
+ @p.opt :arg4, "desc", :default => ["potato", "rhubarb"], :short => :none, :multi => true
998
+
999
+ ## arg1 should be multi-occurring but not multi-valued
1000
+ opts = @p.parse %w(--arg1 one two)
1001
+ assert_equal ["one"], opts[:arg1]
1002
+ assert_equal ["two"], @p.leftovers
1003
+
1004
+ opts = @p.parse %w(--arg1 one --arg1 two)
1005
+ assert_equal ["one", "two"], opts[:arg1]
1006
+ assert_equal [], @p.leftovers
1007
+
1008
+ ## arg2 should be multi-valued and multi-occurring
1009
+ opts = @p.parse %w(--arg2 one two)
1010
+ assert_equal [["one", "two"]], opts[:arg2]
1011
+ assert_equal [], @p.leftovers
1012
+
1013
+ ## arg3 should be multi-valued but not multi-occurring
1014
+ opts = @p.parse %w(--arg3 one two)
1015
+ assert_equal ["one", "two"], opts[:arg3]
1016
+ assert_equal [], @p.leftovers
1017
+
1018
+ ## arg4 should be multi-valued but not multi-occurring
1019
+ opts = @p.parse %w()
1020
+ assert_equal ["potato", "rhubarb"], opts[:arg4]
1021
+ end
1022
+
1023
+ def test_given_keys
1024
+ @p.opt :arg1
1025
+ @p.opt :arg2
1026
+
1027
+ opts = @p.parse %w(--arg1)
1028
+ assert opts[:arg1_given]
1029
+ assert !opts[:arg2_given]
1030
+
1031
+ opts = @p.parse %w(--arg2)
1032
+ assert !opts[:arg1_given]
1033
+ assert opts[:arg2_given]
1034
+
1035
+ opts = @p.parse []
1036
+ assert !opts[:arg1_given]
1037
+ assert !opts[:arg2_given]
1038
+
1039
+ opts = @p.parse %w(--arg1 --arg2)
1040
+ assert opts[:arg1_given]
1041
+ assert opts[:arg2_given]
1042
+ end
1043
+
1044
+ def test_default_shorts_assigned_only_after_user_shorts
1045
+ @p.opt :aab, "aaa" # should be assigned to -b
1046
+ @p.opt :ccd, "bbb" # should be assigned to -d
1047
+ @p.opt :user1, "user1", :short => 'a'
1048
+ @p.opt :user2, "user2", :short => 'c'
1049
+
1050
+ opts = @p.parse %w(-a -b)
1051
+ assert opts[:user1]
1052
+ assert !opts[:user2]
1053
+ assert opts[:aab]
1054
+ assert !opts[:ccd]
1055
+
1056
+ opts = @p.parse %w(-c -d)
1057
+ assert !opts[:user1]
1058
+ assert opts[:user2]
1059
+ assert !opts[:aab]
1060
+ assert opts[:ccd]
1061
+ end
1062
+
1063
+ def test_accepts_arguments_with_spaces
1064
+ @p.opt :arg1, "arg", :type => String
1065
+ @p.opt :arg2, "arg2", :type => String
1066
+
1067
+ opts = @p.parse ["--arg1", "hello there", "--arg2=hello there"]
1068
+ assert_equal "hello there", opts[:arg1]
1069
+ assert_equal "hello there", opts[:arg2]
1070
+ assert_equal 0, @p.leftovers.size
1071
+ end
1072
+
1073
+ def test_multi_args_default_to_empty_array
1074
+ @p.opt :arg1, "arg", :multi => true
1075
+ opts = @p.parse []
1076
+ assert_equal [], opts[:arg1]
1077
+ end
1078
+
1079
+ def test_simple_interface_handles_help
1080
+ assert_stdout(/Options:/) do
1081
+ assert_raises(SystemExit) do
1082
+ ::Optimist::options(%w(-h)) do
1083
+ opt :potato
1084
+ end
1085
+ end
1086
+ end
1087
+
1088
+ # ensure regular status is returned
1089
+
1090
+ assert_stdout do
1091
+ begin
1092
+ ::Optimist::options(%w(-h)) do
1093
+ opt :potato
1094
+ end
1095
+ rescue SystemExit => e
1096
+ assert_equal 0, e.status
1097
+ end
1098
+ end
1099
+ end
1100
+
1101
+ def test_simple_interface_handles_version
1102
+ assert_stdout(/1.2/) do
1103
+ assert_raises(SystemExit) do
1104
+ ::Optimist::options(%w(-v)) do
1105
+ version "1.2"
1106
+ opt :potato
1107
+ end
1108
+ end
1109
+ end
1110
+ end
1111
+
1112
+ def test_simple_interface_handles_regular_usage
1113
+ opts = ::Optimist::options(%w(--potato)) do
1114
+ opt :potato
1115
+ end
1116
+ assert opts[:potato]
1117
+ end
1118
+
1119
+ def test_simple_interface_handles_die
1120
+ assert_stderr do
1121
+ ::Optimist::options(%w(--potato)) do
1122
+ opt :potato
1123
+ end
1124
+ assert_raises(SystemExit) { ::Optimist::die :potato, "is invalid" }
1125
+ end
1126
+ end
1127
+
1128
+ def test_simple_interface_handles_die_without_message
1129
+ assert_stderr(/Error:/) do
1130
+ ::Optimist::options(%w(--potato)) do
1131
+ opt :potato
1132
+ end
1133
+ assert_raises(SystemExit) { ::Optimist::die :potato }
1134
+ end
1135
+ end
1136
+
1137
+ def test_invalid_option_with_simple_interface
1138
+ assert_stderr do
1139
+ assert_raises(SystemExit) do
1140
+ ::Optimist.options(%w(--potato))
1141
+ end
1142
+ end
1143
+
1144
+ assert_stderr do
1145
+ begin
1146
+ ::Optimist.options(%w(--potato))
1147
+ rescue SystemExit => e
1148
+ assert_equal(-1, e.status)
1149
+ end
1150
+ end
1151
+ end
1152
+
1153
+ def test_supports_callback_inline
1154
+ assert_raises(RuntimeError, "good") do
1155
+ @p.opt :cb1 do |vals|
1156
+ raise "good"
1157
+ end
1158
+ @p.parse(%w(--cb1))
1159
+ end
1160
+ end
1161
+
1162
+ def test_supports_callback_param
1163
+ assert_raises(RuntimeError, "good") do
1164
+ @p.opt :cb1, "with callback", :callback => lambda { |vals| raise "good" }
1165
+ @p.parse(%w(--cb1))
1166
+ end
1167
+ end
1168
+
1169
+ def test_ignore_invalid_options
1170
+ @p.opt :arg1, "desc", :type => String
1171
+ @p.opt :b, "desc", :type => String
1172
+ @p.opt :c, "desc", :type => :flag
1173
+ @p.opt :d, "desc", :type => :flag
1174
+ @p.ignore_invalid_options = true
1175
+ opts = @p.parse %w{unknown -S param --arg1 potato -fb daisy --foo -ecg --bar baz -z}
1176
+ assert_equal "potato", opts[:arg1]
1177
+ assert_equal "daisy", opts[:b]
1178
+ assert opts[:c]
1179
+ refute opts[:d]
1180
+ assert_equal %w{unknown -S param -f --foo -eg --bar baz -z}, @p.leftovers
1181
+ end
1182
+
1183
+ def test_ignore_invalid_options_stop_on_unknown_long
1184
+ @p.opt :arg1, "desc", :type => String
1185
+ @p.ignore_invalid_options = true
1186
+ @p.stop_on_unknown
1187
+ opts = @p.parse %w{--unk --arg1 potato}
1188
+ refute opts[:arg1]
1189
+ assert_equal %w{--unk --arg1 potato}, @p.leftovers
1190
+ end
1191
+
1192
+ def test_ignore_invalid_options_stop_on_unknown_short
1193
+ @p.opt :arg1, "desc", :type => String
1194
+ @p.ignore_invalid_options = true
1195
+ @p.stop_on_unknown
1196
+ opts = @p.parse %w{-ua potato}
1197
+ refute opts[:arg1]
1198
+ assert_equal %w{-ua potato}, @p.leftovers
1199
+ end
1200
+
1201
+ def test_ignore_invalid_options_stop_on_unknown_partial_end_short
1202
+ @p.opt :arg1, "desc", :type => :flag
1203
+ @p.ignore_invalid_options = true
1204
+ @p.stop_on_unknown
1205
+ opts = @p.parse %w{-au potato}
1206
+ assert opts[:arg1]
1207
+ assert_equal %w{-u potato}, @p.leftovers
1208
+ end
1209
+
1210
+ def test_ignore_invalid_options_stop_on_unknown_partial_mid_short
1211
+ @p.opt :arg1, "desc", :type => :flag
1212
+ @p.ignore_invalid_options = true
1213
+ @p.stop_on_unknown
1214
+ opts = @p.parse %w{-abu potato}
1215
+ assert opts[:arg1]
1216
+ assert_equal %w{-bu potato}, @p.leftovers
1217
+ end
1218
+ end
1219
+
1220
+ end