CommandLine 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +31 -0
- data/README +380 -0
- data/docs/index.html +1005 -0
- data/lib/commandline.rb +15 -0
- data/lib/commandline/application.rb +320 -0
- data/lib/commandline/optionparser.rb +16 -0
- data/lib/commandline/optionparser/option.rb +180 -0
- data/lib/commandline/optionparser/optiondata.rb +54 -0
- data/lib/commandline/optionparser/optionparser.rb +521 -0
- data/lib/commandline/text/format.rb +1451 -0
- data/lib/commandline/utils.rb +12 -0
- data/lib/open4.rb +79 -0
- data/lib/test/unit/systemtest.rb +58 -0
- metadata +57 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
# $Id$
|
2
|
+
# $Source$
|
3
|
+
#
|
4
|
+
# Author: Jim Freeze
|
5
|
+
# Copyright (c) 2005 Jim Freeze
|
6
|
+
#
|
7
|
+
# =DESCRIPTION
|
8
|
+
# A very flexible commandline parser
|
9
|
+
#
|
10
|
+
# =Revision History
|
11
|
+
# Jim.Freeze 04/01/2005 Birthday
|
12
|
+
#
|
13
|
+
#
|
14
|
+
|
15
|
+
module CommandLine
|
16
|
+
|
17
|
+
#
|
18
|
+
# Data resulting from parsing a command line (Array)
|
19
|
+
# using a particular OptionParser object
|
20
|
+
#
|
21
|
+
class OptionData
|
22
|
+
attr_reader :argv, :unknown_options, :args, :not_parsed, :cmd
|
23
|
+
|
24
|
+
class OptionDataError < StandardError; end
|
25
|
+
class UnknownOptionError < OptionDataError; end
|
26
|
+
|
27
|
+
def initialize(argv, opts, unknown_options, args, not_parsed, cmd)
|
28
|
+
@opts = {}
|
29
|
+
opts.each { |k,v|
|
30
|
+
@opts[k] =
|
31
|
+
begin
|
32
|
+
Marshal.load(Marshal.dump(v))
|
33
|
+
rescue
|
34
|
+
v
|
35
|
+
end
|
36
|
+
}
|
37
|
+
@unknown_options = Marshal.load(Marshal.dump(unknown_options))
|
38
|
+
@not_parsed = Marshal.load(Marshal.dump(not_parsed))
|
39
|
+
@argv = Marshal.load(Marshal.dump(argv))
|
40
|
+
@args = Marshal.load(Marshal.dump(args))
|
41
|
+
@cmd = Marshal.load(Marshal.dump(cmd))
|
42
|
+
end
|
43
|
+
|
44
|
+
def [](key)
|
45
|
+
if @opts.has_key?(key)
|
46
|
+
@opts[key]
|
47
|
+
else
|
48
|
+
raise(UnknownOptionError, "Unknown option '#{key}'.")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end#class OptionData
|
53
|
+
|
54
|
+
end#module CommandLine
|
@@ -0,0 +1,521 @@
|
|
1
|
+
# $Id$
|
2
|
+
# $Source$
|
3
|
+
#
|
4
|
+
# Author: Jim Freeze
|
5
|
+
# Copyright (c) 2005 Jim Freeze
|
6
|
+
#
|
7
|
+
# =DESCRIPTION
|
8
|
+
# A very flexible commandline parser
|
9
|
+
#
|
10
|
+
# =Revision History
|
11
|
+
# Jim.Freeze 04/01/2005 Birthday
|
12
|
+
#
|
13
|
+
# :include: README
|
14
|
+
#
|
15
|
+
|
16
|
+
module CommandLine
|
17
|
+
|
18
|
+
class OptionParser
|
19
|
+
attr_reader :posix, :unknown_options_action,
|
20
|
+
:options
|
21
|
+
|
22
|
+
attr_accessor :columns, :body_indent, :tag_paragraph
|
23
|
+
|
24
|
+
DEFAULT_CONSOLE_WIDTH = 70
|
25
|
+
MIN_CONSOLE_WIDTH = 10
|
26
|
+
DEFAULT_BODY_INDENT = 4
|
27
|
+
|
28
|
+
#
|
29
|
+
# These helper lambdas are here because OptionParser is the object
|
30
|
+
# that calls them and hence knows the parameter order.
|
31
|
+
#
|
32
|
+
|
33
|
+
OPT_NOT_FOUND_BUT_REQUIRED = lambda { |opt|
|
34
|
+
raise(MissingRequiredOptionError,
|
35
|
+
"Missing required parameter '#{opt.names[0]}'.")
|
36
|
+
}
|
37
|
+
|
38
|
+
GET_ARG_ARRAY = lambda { |opt, user_opt, args| args }
|
39
|
+
|
40
|
+
GET_ARGS = lambda { |opt, user_opt, args|
|
41
|
+
return true if args.empty?
|
42
|
+
return args[0] if 1 == args.size
|
43
|
+
args
|
44
|
+
}
|
45
|
+
|
46
|
+
#
|
47
|
+
# Option Errors. Not the oxymoron below for MissingRequiredOptionError.
|
48
|
+
# The user can make an option required by adding the OPT_NOT_FOUND_BUT_REQUIRED
|
49
|
+
# lambda for the #opt_not_found action.
|
50
|
+
#
|
51
|
+
class OptionParserError < StandardError; end
|
52
|
+
class DuplicateOptionNameError < OptionParserError; end
|
53
|
+
class MissingRequiredOptionError < OptionParserError; end
|
54
|
+
class MissingRequiredOptionArgumentError < OptionParserError; end
|
55
|
+
class UnknownOptionError < OptionParserError; end
|
56
|
+
class UnknownPropertyError < OptionParserError; end
|
57
|
+
class PosixMismatchError < OptionParserError; end
|
58
|
+
|
59
|
+
def initialize(*opts_and_props)
|
60
|
+
@posix = false
|
61
|
+
@unknown_options_action = :raise
|
62
|
+
@unknown_options = []
|
63
|
+
@opt_lookup_by_any_name = {}
|
64
|
+
@command_options = nil
|
65
|
+
|
66
|
+
#
|
67
|
+
# Formatting defaults
|
68
|
+
#
|
69
|
+
console_width = ENV["COLUMNS"]
|
70
|
+
@columns =
|
71
|
+
if console_width.nil?
|
72
|
+
DEFAULT_CONSOLE_WIDTH
|
73
|
+
elsif console_width < MIN_CONSOLE_WIDTH
|
74
|
+
console_width
|
75
|
+
else
|
76
|
+
console_width - DEFAULT_BODY_INDENT
|
77
|
+
end
|
78
|
+
@body_indent = DEFAULT_BODY_INDENT
|
79
|
+
@tag_paragraph = false
|
80
|
+
@order = :index # | :alpha
|
81
|
+
|
82
|
+
props = []
|
83
|
+
keys = {}
|
84
|
+
opts_and_props.flatten!
|
85
|
+
opts_and_props.delete_if { |op|
|
86
|
+
if Symbol === op
|
87
|
+
props << op; true
|
88
|
+
elsif Hash === op
|
89
|
+
keys.update(op); true
|
90
|
+
else
|
91
|
+
false
|
92
|
+
end
|
93
|
+
}
|
94
|
+
|
95
|
+
props.each { |p|
|
96
|
+
case p
|
97
|
+
when :posix then @posix = true
|
98
|
+
else
|
99
|
+
raise(UnknownPropertyError, "Unknown property '#{p.inspect}'.")
|
100
|
+
end
|
101
|
+
}
|
102
|
+
|
103
|
+
keys.each { |k,v|
|
104
|
+
case k
|
105
|
+
when :unknown_options_action
|
106
|
+
if [:collect, :ignore, :raise].include?(v)
|
107
|
+
@unknown_options_action = v
|
108
|
+
else
|
109
|
+
raise(UnknownPropertyError, "Unknown value '#{v}' for "+
|
110
|
+
":unknown_options property.")
|
111
|
+
end
|
112
|
+
when :command_options
|
113
|
+
@command_options = v
|
114
|
+
@commands = v.keys
|
115
|
+
else
|
116
|
+
raise(UnknownPropertyError, "Unknown property '#{k.inspect}'.")
|
117
|
+
end
|
118
|
+
}
|
119
|
+
# :unknown_options => :collect
|
120
|
+
# :unknown_options => :ignore
|
121
|
+
# :unknown_options => :raise
|
122
|
+
|
123
|
+
opts = opts_and_props
|
124
|
+
|
125
|
+
@options = []
|
126
|
+
opts.each { |opt|
|
127
|
+
# If user wants to parse posix, then ensure all options are posix
|
128
|
+
raise(PosixMismatchError,
|
129
|
+
"Posix types do not match. #{opt.inspect}") if @posix && !opt.posix
|
130
|
+
@options << opt
|
131
|
+
}
|
132
|
+
|
133
|
+
#p "options-"*5
|
134
|
+
#p @options
|
135
|
+
add_names(@options)
|
136
|
+
|
137
|
+
yield self if block_given?
|
138
|
+
end
|
139
|
+
|
140
|
+
#
|
141
|
+
# add_option :names => %w{--file --use-this-file -f},
|
142
|
+
# :
|
143
|
+
#
|
144
|
+
# add_option :names => %w(--version -v),
|
145
|
+
# :arg_arity => [0,0], # default
|
146
|
+
# :option_description => "Returns Version"
|
147
|
+
# add_option :names => %w(--file -f),
|
148
|
+
# :arg_arity => [1,:unlimited],
|
149
|
+
# :opt_description => "Define the output filename.",
|
150
|
+
# :arg_description => "Output file"
|
151
|
+
# :opt_exists => lambda {}
|
152
|
+
# :opt_not_exists => lambda {}
|
153
|
+
# :option_found
|
154
|
+
# :no_option_found
|
155
|
+
# :opt_found => lambda {}
|
156
|
+
# :no_opt_found => lambda {}
|
157
|
+
#
|
158
|
+
|
159
|
+
#
|
160
|
+
# Add an option
|
161
|
+
#
|
162
|
+
def <<(option)
|
163
|
+
@options << option
|
164
|
+
add_names(option)
|
165
|
+
self
|
166
|
+
end
|
167
|
+
|
168
|
+
def add_option(*h)
|
169
|
+
opt = Option.new(*h)
|
170
|
+
@options << opt
|
171
|
+
add_names(opt)
|
172
|
+
end
|
173
|
+
|
174
|
+
def add_names(*options)
|
175
|
+
options.flatten.each { |option|
|
176
|
+
raise "Wrong data type '#{option.name}." unless Option === option
|
177
|
+
option.names.each { |name|
|
178
|
+
raise(DuplicateOptionNameError,
|
179
|
+
"Duplicate option name '#{name}'.") if
|
180
|
+
@opt_lookup_by_any_name.has_key?(name)
|
181
|
+
@opt_lookup_by_any_name[name] = option
|
182
|
+
}
|
183
|
+
}
|
184
|
+
end
|
185
|
+
|
186
|
+
def validate_parse_options(h)
|
187
|
+
h[:names].each { |name| check_option_name(name) }
|
188
|
+
|
189
|
+
#if @posix
|
190
|
+
# all are single-dash:single-char OR double-dash:multi-char
|
191
|
+
#else if unix compliant
|
192
|
+
# single-dash only
|
193
|
+
#else any - does not support combination - try to on single/single
|
194
|
+
#end
|
195
|
+
end
|
196
|
+
|
197
|
+
# def [](opt)
|
198
|
+
# @options[@opt_lookup_by_any_name[opt][0]]
|
199
|
+
# end
|
200
|
+
|
201
|
+
#
|
202
|
+
# Parse the command line
|
203
|
+
#
|
204
|
+
def parse(argv=ARGV)
|
205
|
+
argv = [argv] unless Array === argv
|
206
|
+
|
207
|
+
#
|
208
|
+
# Holds the results of each option. The key used is
|
209
|
+
# the first in the :names Array.
|
210
|
+
#
|
211
|
+
opts = Hash.new( :not_found )
|
212
|
+
|
213
|
+
#
|
214
|
+
# A command is the first non-option free argument on the command line.
|
215
|
+
# This is a user selection and is the first argument in args.
|
216
|
+
# cmd = args.shift
|
217
|
+
# Example:
|
218
|
+
# cvs -v cmd --cmd-option arg
|
219
|
+
#
|
220
|
+
cmd = nil
|
221
|
+
cmd_options = {}
|
222
|
+
|
223
|
+
#
|
224
|
+
# #parse_argv yields an array containing the option and its arguments.
|
225
|
+
# [opts, array_args]
|
226
|
+
# How do we collect all the arguments when OptionParser deal with an
|
227
|
+
# empty option list
|
228
|
+
#
|
229
|
+
parse_argv(argv) { |optarg|
|
230
|
+
user_option = optarg[0]
|
231
|
+
args = optarg[1]
|
232
|
+
|
233
|
+
m = nil
|
234
|
+
if @opt_lookup_by_any_name.has_key?(user_option) ||
|
235
|
+
1 == (m = @opt_lookup_by_any_name.keys.grep(/^#{user_option}/)).size
|
236
|
+
user_option = m[0] if m
|
237
|
+
opt = @opt_lookup_by_any_name[user_option]
|
238
|
+
opt_key = opt.names[0]
|
239
|
+
|
240
|
+
opts[opt_key] =
|
241
|
+
if Proc === opt.opt_found
|
242
|
+
# Take the arguments depending upon arity
|
243
|
+
opt_args = get_opt_args(opt, user_option, args)
|
244
|
+
opt.opt_found.call(opt, user_option, opt_args)
|
245
|
+
else
|
246
|
+
opt.opt_found
|
247
|
+
end
|
248
|
+
# Collect any remaining args
|
249
|
+
@args += args
|
250
|
+
|
251
|
+
elsif :collect == @unknown_options_action
|
252
|
+
@unknown_options << user_option
|
253
|
+
elsif :ignore == @unknown_options_action
|
254
|
+
else
|
255
|
+
raise(UnknownOptionError, "Unknown option '#{user_option}' in "+
|
256
|
+
"#{@opt_lookup_by_any_name.inspect}.")
|
257
|
+
end
|
258
|
+
}
|
259
|
+
|
260
|
+
#
|
261
|
+
# Call :not_found for all the options not on the command line.
|
262
|
+
#
|
263
|
+
@options.each { |opt|
|
264
|
+
name = opt.names[0]
|
265
|
+
if :not_found == opts[name]
|
266
|
+
opts[name] =
|
267
|
+
if Proc === opt.opt_not_found
|
268
|
+
opt.opt_not_found.call(opt)
|
269
|
+
else
|
270
|
+
opt.opt_not_found
|
271
|
+
end
|
272
|
+
end
|
273
|
+
}
|
274
|
+
|
275
|
+
OptionData.new(argv, opts, @unknown_options, @args, @not_parsed, cmd)
|
276
|
+
end
|
277
|
+
|
278
|
+
def get_opt_args(opt, user_option, args)
|
279
|
+
min, max = *opt.arg_arity
|
280
|
+
size = args.size
|
281
|
+
|
282
|
+
if (min == max && max > 0 && size < max) || (size < min)
|
283
|
+
raise(MissingRequiredOptionArgumentError,
|
284
|
+
"Insufficient arguments #{args.inspect}for option '#{user_option}' "+
|
285
|
+
"with :arg_arity #{opt.arg_arity.inspect}")
|
286
|
+
end
|
287
|
+
|
288
|
+
if 0 == min && 0 == max
|
289
|
+
[]
|
290
|
+
else
|
291
|
+
max = size if -1 == max
|
292
|
+
args.slice!(0..[min, [max, size].min].max - 1)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
def get_posix_re
|
297
|
+
flags = []
|
298
|
+
nflags = []
|
299
|
+
@options.each { |o|
|
300
|
+
if [0,0] == o.arg_arity
|
301
|
+
flags << o.names[0][1..1]
|
302
|
+
else
|
303
|
+
nflags << o.names[0][1..1]
|
304
|
+
end
|
305
|
+
}
|
306
|
+
flags = flags.join
|
307
|
+
flags = flags.empty? ? "" : "[#{flags}\]+"
|
308
|
+
nflags = nflags.join
|
309
|
+
nflags = nflags.empty? ? "" : "[#{nflags}\]"
|
310
|
+
Regexp.new("^-(#{flags})(#{nflags})(.*)\$")
|
311
|
+
end
|
312
|
+
|
313
|
+
#######################################################################
|
314
|
+
def parse_posix_argv(argv)
|
315
|
+
re = @posix ? get_posix_re : Option::GENERAL_OPT_EQ_ARG_RE
|
316
|
+
p re if $DEBUG
|
317
|
+
tagged = []
|
318
|
+
|
319
|
+
#
|
320
|
+
# A Posix command line must have all the options precede
|
321
|
+
# non option arguments. For example
|
322
|
+
# :names => -h -e -l -p -s
|
323
|
+
# where -p can take an argument
|
324
|
+
# Command line can read:
|
325
|
+
# -helps => -h -e -l -p s
|
326
|
+
# -p fred non-opt-arg
|
327
|
+
# -p fred non-opt-arg -h # not ok
|
328
|
+
# -he -popt-arg1 -popt-arg2 non-opt-arg
|
329
|
+
# -p=fred # this is not legal?
|
330
|
+
# -pfred === -p fred
|
331
|
+
#
|
332
|
+
|
333
|
+
#"-helps" "-pfred" "-p" "fred"
|
334
|
+
#-h -e -l -p [s] -p [fred] -p [fred]
|
335
|
+
#[-h, []], [-e []], [-l, []], [-p, [s]], -p
|
336
|
+
|
337
|
+
argv.each { |e|
|
338
|
+
m = re.match(e)
|
339
|
+
if m.nil?
|
340
|
+
tagged << [:arg, e]
|
341
|
+
else
|
342
|
+
raise "houston, we have a problem" if m.nil?
|
343
|
+
unless m[1].empty?
|
344
|
+
m[1].split(//).each { |e| tagged << [:opt, "-#{e}"] }
|
345
|
+
end
|
346
|
+
|
347
|
+
unless m[2].empty?
|
348
|
+
tagged << [:opt, "-#{m[2]}"]
|
349
|
+
tagged << [:arg, m[3]] unless m[3].empty?
|
350
|
+
end
|
351
|
+
end
|
352
|
+
}
|
353
|
+
|
354
|
+
if $DEBUG
|
355
|
+
print "Tagged:"
|
356
|
+
p tagged
|
357
|
+
end
|
358
|
+
#
|
359
|
+
# Now, combine any adjacent args such that
|
360
|
+
# [[:arg, "arg1"], [:arg, "arg2"]]
|
361
|
+
# becomes
|
362
|
+
# [[:args, ["arg1", "arg2"]]]
|
363
|
+
# and the final result should be
|
364
|
+
# [ "--file", ["arg1", "arg2"]]
|
365
|
+
#
|
366
|
+
|
367
|
+
parsed = []
|
368
|
+
@args = []
|
369
|
+
tagged.each { |e|
|
370
|
+
if :opt == e[0]
|
371
|
+
parsed << [e[1], []]
|
372
|
+
else
|
373
|
+
if Array === parsed[-1]
|
374
|
+
parsed[-1][-1] += [e[1]]
|
375
|
+
else
|
376
|
+
@args << e[1]
|
377
|
+
end
|
378
|
+
end
|
379
|
+
}
|
380
|
+
parsed.each { |e| yield e }
|
381
|
+
end
|
382
|
+
|
383
|
+
#
|
384
|
+
# Seperates options from arguments
|
385
|
+
# Does not look for valid options ( or should it? )
|
386
|
+
#
|
387
|
+
# %w(-fred file1 file2) => ["-fred", ["file1", "file2"]]
|
388
|
+
# %w(--fred -t -h xyz) => ["--fred", []] ["-t", []] ["-h", ["xyz"]]
|
389
|
+
# %w(-f=file) => ["-f", ["file"]]
|
390
|
+
# %w(--file=fred) => ["--file", ["fred"]]
|
391
|
+
# %w(-file=fred) => ["-file", ["fred"]]
|
392
|
+
# ['-file="fred1 fred2"'] => ["-file", ["fred1", "fred2"]]
|
393
|
+
#
|
394
|
+
def parse_argv(argv, &block)
|
395
|
+
return parse_posix_argv(argv, &block) if @posix
|
396
|
+
|
397
|
+
@not_parsed = []
|
398
|
+
tagged = []
|
399
|
+
argv.each_with_index { |e,i|
|
400
|
+
if "--" == e
|
401
|
+
@not_parsed = argv[(i+1)..(argv.size+1)]
|
402
|
+
break
|
403
|
+
elsif "-" == e
|
404
|
+
tagged << [:arg, e]
|
405
|
+
elsif ?- == e[0]
|
406
|
+
m = Option::GENERAL_OPT_EQ_ARG_RE.match(e)
|
407
|
+
if m.nil?
|
408
|
+
tagged << [:opt, e]
|
409
|
+
else
|
410
|
+
tagged << [:opt, m[1]]
|
411
|
+
tagged << [:arg, m[2]]
|
412
|
+
end
|
413
|
+
else
|
414
|
+
tagged << [:arg, e]
|
415
|
+
end
|
416
|
+
}
|
417
|
+
|
418
|
+
#
|
419
|
+
# The tagged array has the form:
|
420
|
+
# [
|
421
|
+
# [:opt, "-a"], [:arg, "filea"],
|
422
|
+
# [:opt, "-b"], [:arg, "fileb"],
|
423
|
+
# #[:not_parsed, ["-z", "-y", "file", "file2", "-a", "-b"]]
|
424
|
+
# ]
|
425
|
+
|
426
|
+
#
|
427
|
+
# Now, combine any adjacent args such that
|
428
|
+
# [[:arg, "arg1"], [:arg, "arg2"]]
|
429
|
+
# becomes
|
430
|
+
# [[:args, ["arg1", "arg2"]]]
|
431
|
+
# and the final result should be
|
432
|
+
# [ "--file", ["arg1", "arg2"]]
|
433
|
+
#
|
434
|
+
|
435
|
+
parsed = []
|
436
|
+
@args = []
|
437
|
+
tagged.each { |e|
|
438
|
+
if :opt == e[0]
|
439
|
+
parsed << [e[1], []]
|
440
|
+
elsif :arg == e[0]
|
441
|
+
if Array === parsed[-1]
|
442
|
+
parsed[-1][-1] += [e[1]]
|
443
|
+
else
|
444
|
+
@args << e[1]
|
445
|
+
end
|
446
|
+
else
|
447
|
+
raise "How did we get here?"
|
448
|
+
end
|
449
|
+
}
|
450
|
+
parsed.each { |e| block.call(e) }
|
451
|
+
end
|
452
|
+
|
453
|
+
def to_str
|
454
|
+
to_s
|
455
|
+
end
|
456
|
+
|
457
|
+
def to_s(sep="\n")
|
458
|
+
return "" if @options.empty?
|
459
|
+
|
460
|
+
require 'commandline/text/format'
|
461
|
+
@f = Text::Format.new
|
462
|
+
@f.columns = @columns
|
463
|
+
@f.first_indent = 4
|
464
|
+
@f.body_indent = 8
|
465
|
+
@f.tag_paragraph = false
|
466
|
+
|
467
|
+
header = ["OPTIONS\n"]
|
468
|
+
s = []
|
469
|
+
@options.each { |opt|
|
470
|
+
opt_str = []
|
471
|
+
if block_given?
|
472
|
+
result = yield(opt.names, opt.opt_description, opt.arg_description)
|
473
|
+
if result.kind_of?(String)
|
474
|
+
opt_str << result unless result.empty?
|
475
|
+
elsif result.nil?
|
476
|
+
opt_str << format_option(opt.names, opt.opt_description, opt.arg_description)
|
477
|
+
elsif result.kind_of?(Array) && 3 == result.size
|
478
|
+
opt_str << format_option(*result)
|
479
|
+
else
|
480
|
+
raise "Invalid return value #{result.inspect} from yield block "+
|
481
|
+
"attached to #to_s."
|
482
|
+
end
|
483
|
+
else
|
484
|
+
opt_str << format_option(opt.names, opt.opt_description, opt.arg_description)
|
485
|
+
end
|
486
|
+
s << opt_str.join unless opt_str.empty?
|
487
|
+
}
|
488
|
+
#s.collect! { |i| i.kind_of?(Array) && /\n+/ =~ i[0] ? i.join : f.paragraphs(i) }
|
489
|
+
[header, s].flatten.join(sep)
|
490
|
+
end
|
491
|
+
|
492
|
+
def format_option(names, opt_desc, arg_desc)
|
493
|
+
# TODO: Clean up the magic numbers
|
494
|
+
|
495
|
+
f = Text::Format.new
|
496
|
+
f.columns = @columns
|
497
|
+
f.first_indent = 4
|
498
|
+
f.body_indent = 8
|
499
|
+
f.tabstop = 4
|
500
|
+
s = ""
|
501
|
+
s << f.format("#{names.join(",")} #{arg_desc}")
|
502
|
+
#if 7 == s.last.size
|
503
|
+
if 7 == s.size
|
504
|
+
f.first_indent = f.first_indent - 2
|
505
|
+
s.rstrip!
|
506
|
+
s << f.format(opt_desc)
|
507
|
+
#elsif 8 == s.last.size
|
508
|
+
elsif 8 == s.size
|
509
|
+
f.first_indent = f.first_indent - 3
|
510
|
+
s.rstrip!
|
511
|
+
s << f.format(opt_desc)
|
512
|
+
else
|
513
|
+
f.first_indent = 2 * f.first_indent
|
514
|
+
s << f.format(opt_desc)
|
515
|
+
end
|
516
|
+
end
|
517
|
+
private :format_option
|
518
|
+
|
519
|
+
end#class OptionParser
|
520
|
+
|
521
|
+
end#module CommandLine
|