optimist 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.
@@ -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