benry-cmdopt 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES.md +13 -1
- data/README.md +67 -6
- data/benry-cmdopt.gemspec +1 -1
- data/doc/benry-cmdopt.html +62 -6
- data/doc/css/style.css +2 -2
- data/lib/benry/cmdopt.rb +53 -12
- data/test/cmdopt_test.rb +1 -1526
- 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
|