benry-cmdopt 2.3.0 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +6 -0
- data/README.md +50 -6
- data/benry-cmdopt.gemspec +1 -1
- data/doc/benry-cmdopt.html +45 -6
- data/lib/benry/cmdopt.rb +31 -11
- data/test/cmdopt_test.rb +1 -1574
- data/test/facade_test.rb +197 -0
- data/test/item_test.rb +463 -0
- data/test/parser_test.rb +294 -0
- data/test/run_all.rb +6 -0
- data/test/schema_test.rb +727 -0
- data/test/shared.rb +6 -0
- metadata +12 -2
data/test/parser_test.rb
ADDED
@@ -0,0 +1,294 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative './shared'
|
5
|
+
|
6
|
+
|
7
|
+
Oktest.scope do
|
8
|
+
|
9
|
+
|
10
|
+
def new_sample_schema()
|
11
|
+
sc = Benry::CmdOpt::Schema.new
|
12
|
+
sc.add(:help , "-h, --help" , "show help message.")
|
13
|
+
sc.add(:version, "--version" , "print version")
|
14
|
+
sc.add(:file , "-f, --file=<FILE>" , "filename")
|
15
|
+
sc.add(:indent , "-i, --indent[=<WIDTH>]", "enable indent", type: Integer)
|
16
|
+
sc.add(:mode , "-m, --mode=<MODE>" , "mode", enum: ['verbose', 'quiet'])
|
17
|
+
sc.add(:include, "-I, --include=<PATH>" , "include path (multiple ok)", multiple: true)
|
18
|
+
sc.add(:libpath, "-L, --path=<PATH>" , "library path (multiple ok)") do |optdef, key, val|
|
19
|
+
File.directory?(val) or raise "Directory not exist."
|
20
|
+
arr = optdef[key] || []
|
21
|
+
arr << val
|
22
|
+
arr
|
23
|
+
end
|
24
|
+
sc
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
topic Benry::CmdOpt::Parser do
|
29
|
+
|
30
|
+
|
31
|
+
topic '#parse_options()' do
|
32
|
+
|
33
|
+
before do
|
34
|
+
@parser = Benry::CmdOpt::Parser.new(new_sample_schema())
|
35
|
+
end
|
36
|
+
|
37
|
+
spec "[!3wmsy] returns command option values as a dict." do
|
38
|
+
argv = ["-h", "--version"]
|
39
|
+
d = @parser.parse(argv)
|
40
|
+
ok {d} == {help: true, version: true}
|
41
|
+
end
|
42
|
+
|
43
|
+
spec "[!uh7j8] parses long options." do
|
44
|
+
argv = ["--help", "--file=foo.png", "--indent=10"]
|
45
|
+
d = @parser.parse(argv)
|
46
|
+
ok {d} == {help: true, file: "foo.png", indent: 10}
|
47
|
+
end
|
48
|
+
|
49
|
+
spec "[!nwnjc] parses short options." do
|
50
|
+
argv = ["-h", "-f", "foo.png", "-i10"]
|
51
|
+
d = @parser.parse(argv)
|
52
|
+
ok {d} == {help: true, file: "foo.png", indent: 10}
|
53
|
+
end
|
54
|
+
|
55
|
+
spec "[!5s5b6] treats '-' as an argument, not an option." do
|
56
|
+
argv = ["-h", "-", "xxx", "yyy"]
|
57
|
+
d = @parser.parse(argv)
|
58
|
+
ok {d} == {help: true}
|
59
|
+
ok {argv} == ["-", "xxx", "yyy"]
|
60
|
+
end
|
61
|
+
|
62
|
+
spec "[!q8356] parses options even after arguments when `all: true`." do
|
63
|
+
argv = ["-h", "arg1", "-f", "foo.png", "arg2", "-i10", "arg3"]
|
64
|
+
d = @parser.parse(argv, all: true)
|
65
|
+
ok {d} == {help: true, file: "foo.png", indent: 10}
|
66
|
+
ok {argv} == ["arg1", "arg2", "arg3"]
|
67
|
+
#
|
68
|
+
argv = ["-h", "arg1", "-f", "foo.png", "arg2", "-i10", "arg3"]
|
69
|
+
d = @parser.parse(argv)
|
70
|
+
ok {d} == {help: true, file: "foo.png", indent: 10}
|
71
|
+
ok {argv} == ["arg1", "arg2", "arg3"]
|
72
|
+
end
|
73
|
+
|
74
|
+
spec "[!ryra3] doesn't parse options after arguments when `all: false`." do
|
75
|
+
argv = ["-h", "arg1", "-f", "foo.png", "arg2", "-i10", "arg3"]
|
76
|
+
d = @parser.parse(argv, all: false)
|
77
|
+
ok {d} == {help: true}
|
78
|
+
ok {argv} == ["arg1", "-f", "foo.png", "arg2", "-i10", "arg3"]
|
79
|
+
end
|
80
|
+
|
81
|
+
spec "[!y04um] skips rest options when '--' found in argv." do
|
82
|
+
argv = ["-h", "--", "-f", "foo.png", "-i10"]
|
83
|
+
d = @parser.parse(argv)
|
84
|
+
ok {d} == {help: true}
|
85
|
+
ok {argv} == ["-f", "foo.png", "-i10"]
|
86
|
+
end
|
87
|
+
|
88
|
+
spec "[!qpuxh] handles only OptionError when block given." do
|
89
|
+
errmsg = nil
|
90
|
+
errcls = nil
|
91
|
+
@parser.parse(["-ix"]) {|err|
|
92
|
+
errmsg = err.message
|
93
|
+
errcls = err.class
|
94
|
+
}
|
95
|
+
ok {errmsg} == "-ix: Integer expected."
|
96
|
+
ok {errcls} == Benry::CmdOpt::OptionError
|
97
|
+
#
|
98
|
+
sc = Benry::CmdOpt::Schema.new
|
99
|
+
sc.add(:file, "--file=<FILE>", "file") do |val|
|
100
|
+
File.open(val) {|f| f.read }
|
101
|
+
end
|
102
|
+
parser = Benry::CmdOpt::Parser.new(sc)
|
103
|
+
pr = proc { parser.parse(["--file=/foo/bar/baz.png"]) }
|
104
|
+
ok {pr}.raise?(Errno::ENOENT, /No such file or directory/)
|
105
|
+
end
|
106
|
+
|
107
|
+
spec "[!dhpw1] returns nil when OptionError handled." do
|
108
|
+
ret = @parser.parse(["-dx"]) {|err| 1 }
|
109
|
+
ok {ret} == nil
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
topic '#parse_long_option()' do
|
116
|
+
|
117
|
+
before do
|
118
|
+
@parser = Benry::CmdOpt::Parser.new(new_sample_schema())
|
119
|
+
end
|
120
|
+
|
121
|
+
spec "[!3i994] raises OptionError when invalid long option format." do
|
122
|
+
argv = ["--f/o/o"]
|
123
|
+
pr = proc { @parser.parse(argv) }
|
124
|
+
ok {pr}.raise?(Benry::CmdOpt::OptionError, "--f/o/o: Invalid long option.")
|
125
|
+
end
|
126
|
+
|
127
|
+
spec "[!1ab42] invokes error handler method when unknown long option." do
|
128
|
+
def @parser.handle_unknown_long_option(optstr, name, val)
|
129
|
+
(@_called_ ||= []) << [optstr, name, val]
|
130
|
+
end
|
131
|
+
ret = @parser.parse(["--xx=XX", "--yy=YY", "--zz"])
|
132
|
+
ok {ret} == {}
|
133
|
+
ok {@parser.instance_variable_get('@_called_')} == [
|
134
|
+
["--xx=XX", "xx", "XX"],
|
135
|
+
["--yy=YY", "yy", "YY"],
|
136
|
+
["--zz" , "zz", nil],
|
137
|
+
]
|
138
|
+
end
|
139
|
+
|
140
|
+
spec "[!er7h4] default behavior is to raise OptionError when unknown long option." do
|
141
|
+
argv = ["--foo"]
|
142
|
+
pr = proc { @parser.parse(argv) }
|
143
|
+
ok {pr}.raise?(Benry::CmdOpt::OptionError, "--foo: Unknown long option.")
|
144
|
+
end
|
145
|
+
|
146
|
+
spec "[!2jd9w] raises OptionError when no arguments specified for arg required long option." do
|
147
|
+
argv = ["--file"]
|
148
|
+
pr = proc { @parser.parse(argv) }
|
149
|
+
ok {pr}.raise?(Benry::CmdOpt::OptionError, "--file: Argument required.")
|
150
|
+
end
|
151
|
+
|
152
|
+
spec "[!qyq8n] raises optionError when an argument specified for no arg long option." do
|
153
|
+
argv = ["--version=1.0.0"]
|
154
|
+
pr = proc { @parser.parse(argv) }
|
155
|
+
ok {pr}.raise?(Benry::CmdOpt::OptionError, "--version=1.0.0: Unexpected argument.")
|
156
|
+
end
|
157
|
+
|
158
|
+
spec "[!o596x] validates argument value." do
|
159
|
+
argv = ["--indent=abc"]
|
160
|
+
pr = proc { @parser.parse(argv) }
|
161
|
+
ok {pr}.raise?(Benry::CmdOpt::OptionError, "--indent=abc: Integer expected.")
|
162
|
+
#
|
163
|
+
argv = ["--path=/foo/bar"]
|
164
|
+
pr = proc { @parser.parse(argv) }
|
165
|
+
ok {pr}.raise?(Benry::CmdOpt::OptionError, "--path=/foo/bar: Directory not exist.")
|
166
|
+
end
|
167
|
+
|
168
|
+
spec "[!1m87b] supports multiple option." do
|
169
|
+
argv = ["--include=/foo", "--include=/bar"]
|
170
|
+
opts = @parser.parse(argv)
|
171
|
+
ok {opts} == {:include=>["/foo", "/bar"]}
|
172
|
+
ok {argv} == []
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
|
177
|
+
|
178
|
+
topic '#parse_short_option()' do
|
179
|
+
|
180
|
+
before do
|
181
|
+
@parser = Benry::CmdOpt::Parser.new(new_sample_schema())
|
182
|
+
end
|
183
|
+
|
184
|
+
spec "[!4eh49] raises OptionError when unknown short option specified." do
|
185
|
+
argv = ["-hxf", "foo.png"]
|
186
|
+
pr = proc { @parser.parse(argv) }
|
187
|
+
ok {pr}.raise?(Benry::CmdOpt::OptionError, "-x: Unknown option.")
|
188
|
+
end
|
189
|
+
|
190
|
+
spec "[!utdbf] raises OptionError when argument required but not specified." do
|
191
|
+
argv = ["-hf"]
|
192
|
+
pr = proc { @parser.parse(argv) }
|
193
|
+
ok {pr}.raise?(Benry::CmdOpt::OptionError, "-f: Argument required.")
|
194
|
+
end
|
195
|
+
|
196
|
+
spec "[!f63hf] short option arg can be specified without space separator." do
|
197
|
+
argv = ["-hfabc.png", "xx"]
|
198
|
+
d = @parser.parse(argv)
|
199
|
+
ok {d} == {help: true, file: "abc.png"}
|
200
|
+
ok {argv} == ["xx"]
|
201
|
+
end
|
202
|
+
|
203
|
+
spec "[!yjq6b] optional arg should be specified without space separator." do
|
204
|
+
argv = ["-hi123", "xx"]
|
205
|
+
d = @parser.parse(argv)
|
206
|
+
ok {d} == {help: true, indent: 123}
|
207
|
+
ok {argv} == ['xx']
|
208
|
+
end
|
209
|
+
|
210
|
+
spec "[!wape4] otpional arg can be omit." do
|
211
|
+
argv = ["-hi", "xx"]
|
212
|
+
d = @parser.parse(argv)
|
213
|
+
ok {d} == {help: true, indent: true}
|
214
|
+
ok {argv} == ['xx']
|
215
|
+
end
|
216
|
+
|
217
|
+
spec "[!yu0kc] validates short option argument." do
|
218
|
+
argv = ["-iaaa"]
|
219
|
+
pr = proc { @parser.parse(argv) }
|
220
|
+
ok {pr}.raise?(Benry::CmdOpt::OptionError, "-iaaa: Integer expected.")
|
221
|
+
#
|
222
|
+
argv = ["-L", "/foo/bar"]
|
223
|
+
pr = proc { @parser.parse(argv) }
|
224
|
+
ok {pr}.raise?(Benry::CmdOpt::OptionError, "-L /foo/bar: Directory not exist.")
|
225
|
+
end
|
226
|
+
|
227
|
+
spec "[!187r2] supports multiple option." do
|
228
|
+
argv = ["-I", "/foo", "-I/bar"]
|
229
|
+
opts = @parser.parse(argv)
|
230
|
+
ok {opts} == {:include=>["/foo", "/bar"]}
|
231
|
+
ok {argv} == []
|
232
|
+
end
|
233
|
+
|
234
|
+
end
|
235
|
+
|
236
|
+
|
237
|
+
topic '#new_options_dict()' do
|
238
|
+
|
239
|
+
spec "[!vm6h0] returns new hash object." do
|
240
|
+
parser = Benry::CmdOpt::Parser.new(new_sample_schema())
|
241
|
+
ret = parser.__send__(:new_options_dict)
|
242
|
+
ok {ret}.is_a?(Hash)
|
243
|
+
ok {ret} == {}
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
247
|
+
|
248
|
+
|
249
|
+
topic '#store_option_value()' do
|
250
|
+
|
251
|
+
spec "[!my86j] stores multiple values if multiple option item." do
|
252
|
+
schema = Benry::CmdOpt::Schema.new()
|
253
|
+
item = schema.add(:includes, "-I <path>", "include path", multiple: true)
|
254
|
+
parser = Benry::CmdOpt::Parser.new(schema)
|
255
|
+
optdict = {}
|
256
|
+
parser.instance_eval do
|
257
|
+
store_option_value(optdict, item, "/usr/include")
|
258
|
+
store_option_value(optdict, item, "/usr/local/include")
|
259
|
+
end
|
260
|
+
ok {optdict} == {:includes => ["/usr/include", "/usr/local/include"]}
|
261
|
+
end
|
262
|
+
|
263
|
+
spec "[!tm7xw] stores singile value if not multiple option item." do
|
264
|
+
schema = Benry::CmdOpt::Schema.new()
|
265
|
+
item = schema.add(:include, "-I <path>", "include path")
|
266
|
+
parser = Benry::CmdOpt::Parser.new(schema)
|
267
|
+
optdict = {}
|
268
|
+
parser.instance_eval do
|
269
|
+
store_option_value(optdict, item, "/usr/include")
|
270
|
+
store_option_value(optdict, item, "/usr/local/include")
|
271
|
+
end
|
272
|
+
ok {optdict} == {:include => "/usr/local/include"}
|
273
|
+
end
|
274
|
+
|
275
|
+
end
|
276
|
+
|
277
|
+
|
278
|
+
topic '#handle_unknown_long_option()' do
|
279
|
+
|
280
|
+
spec "[!0q78a] raises OptionError." do
|
281
|
+
parser = Benry::CmdOpt::Parser.new(new_sample_schema())
|
282
|
+
pr = proc {
|
283
|
+
parser.__send__(:handle_unknown_long_option, "--xx=XX", "xx", "XX")
|
284
|
+
}
|
285
|
+
ok {pr}.raise?(Benry::CmdOpt::OptionError, "--xx=XX: Unknown long option.")
|
286
|
+
end
|
287
|
+
|
288
|
+
end
|
289
|
+
|
290
|
+
|
291
|
+
end
|
292
|
+
|
293
|
+
|
294
|
+
end
|