main 0.0.1
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.
- data/README +343 -0
- data/README.tmpl +154 -0
- data/a.rb +33 -0
- data/gemspec.rb +27 -0
- data/gen_readme.rb +38 -0
- data/install.rb +210 -0
- data/lib/main.rb +25 -0
- data/lib/main/base.rb +150 -0
- data/lib/main/cast.rb +74 -0
- data/lib/main/factories.rb +15 -0
- data/lib/main/getoptlong.rb +470 -0
- data/lib/main/parameter.rb +496 -0
- data/lib/main/usage.rb +138 -0
- data/lib/main/util.rb +91 -0
- data/main-0.0.1.gem +0 -0
- data/samples/a.rb +17 -0
- data/samples/b.rb +17 -0
- data/samples/c.rb +21 -0
- data/samples/d.rb +26 -0
- data/test/main.rb +523 -0
- metadata +69 -0
data/lib/main/cast.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
module Main
|
2
|
+
module Cast
|
3
|
+
def self.export m
|
4
|
+
module_function m
|
5
|
+
public m
|
6
|
+
end
|
7
|
+
|
8
|
+
List = []
|
9
|
+
|
10
|
+
def self.cast m, &b
|
11
|
+
define_method m, &b
|
12
|
+
export m
|
13
|
+
List << m.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
cast :boolean do |obj|
|
17
|
+
case obj.to_s
|
18
|
+
when 'true'
|
19
|
+
true
|
20
|
+
when 'false'
|
21
|
+
false
|
22
|
+
else
|
23
|
+
!!obj
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
cast :integer do |obj|
|
28
|
+
Integer obj
|
29
|
+
end
|
30
|
+
|
31
|
+
cast :float do |obj|
|
32
|
+
Float obj
|
33
|
+
end
|
34
|
+
|
35
|
+
cast :number do |obj|
|
36
|
+
Float obj rescue Integer obj
|
37
|
+
end
|
38
|
+
|
39
|
+
cast :string do |obj|
|
40
|
+
String obj
|
41
|
+
end
|
42
|
+
|
43
|
+
cast :uri do |obj|
|
44
|
+
require 'uri'
|
45
|
+
::URI.parse obj.to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
cast :list do |*objs|
|
49
|
+
[*objs].flatten.join(',').split(/,/)
|
50
|
+
end
|
51
|
+
|
52
|
+
List.dup.each do |type|
|
53
|
+
next if type.to_s == 'list'
|
54
|
+
m = "list_of_#{ type }"
|
55
|
+
define_method m do |*objs|
|
56
|
+
list(*objs).map{|obj| send type, obj}
|
57
|
+
end
|
58
|
+
export m
|
59
|
+
List << m
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.[] sym
|
63
|
+
prefix = sym.to_s.downcase.to_sym
|
64
|
+
candidates = List.select{|m| m =~ %r/^#{ prefix }/i}
|
65
|
+
m = candidates.shift
|
66
|
+
raise ArgumentError, "unsupported cast: #{ sym.inspect } (#{ List.join ',' })" unless
|
67
|
+
m
|
68
|
+
raise ArgumentError, "ambiguous cast: #{ sym.inspect } (#{ List.join ',' })" unless
|
69
|
+
candidates.empty? or m.to_s == sym.to_s
|
70
|
+
this = self
|
71
|
+
lambda{|obj| method(m).call obj}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,470 @@
|
|
1
|
+
# -*- Ruby -*-
|
2
|
+
# Copyright (C) 1998, 1999, 2000 Motoyuki Kasahara
|
3
|
+
#
|
4
|
+
# You may redistribute it and/or modify it under the same license
|
5
|
+
# terms as Ruby.
|
6
|
+
#
|
7
|
+
|
8
|
+
#
|
9
|
+
# Documents and latest version of `getoptlong.rb' are found at:
|
10
|
+
# http://www.sra.co.jp/people/m-kasahr/ruby/getoptlong/
|
11
|
+
#
|
12
|
+
|
13
|
+
#
|
14
|
+
# Parse command line options just like GNU getopt_long().
|
15
|
+
#
|
16
|
+
module Main
|
17
|
+
class GetoptLong
|
18
|
+
#
|
19
|
+
# Orderings.
|
20
|
+
#
|
21
|
+
ORDERINGS = [REQUIRE_ORDER = 0, PERMUTE = 1, RETURN_IN_ORDER = 2]
|
22
|
+
|
23
|
+
#
|
24
|
+
# Argument flags.
|
25
|
+
#
|
26
|
+
ARGUMENT_FLAGS = [NO_ARGUMENT = 0, REQUIRED_ARGUMENT = 1,
|
27
|
+
OPTIONAL_ARGUMENT = 2]
|
28
|
+
|
29
|
+
#
|
30
|
+
# Status codes.
|
31
|
+
#
|
32
|
+
STATUS_YET, STATUS_STARTED, STATUS_TERMINATED = 0, 1, 2
|
33
|
+
|
34
|
+
#
|
35
|
+
# Error types.
|
36
|
+
#
|
37
|
+
class AmbigousOption < StandardError; end
|
38
|
+
class NeedlessArgument < StandardError; end
|
39
|
+
class MissingArgument < StandardError; end
|
40
|
+
class InvalidOption < StandardError; end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Initializer.
|
44
|
+
#
|
45
|
+
def initialize(argv, *arguments)
|
46
|
+
@argv = argv
|
47
|
+
#
|
48
|
+
# Current ordering.
|
49
|
+
#
|
50
|
+
if ENV.include?('POSIXLY_CORRECT')
|
51
|
+
@ordering = REQUIRE_ORDER
|
52
|
+
else
|
53
|
+
@ordering = PERMUTE
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# Hash table of option names.
|
58
|
+
# Keyes of the table are option names, and their values are canonical
|
59
|
+
# names of the options.
|
60
|
+
#
|
61
|
+
@canonical_names = Hash.new
|
62
|
+
|
63
|
+
#
|
64
|
+
# Hash table of argument flags.
|
65
|
+
# Keyes of the table are option names, and their values are argument
|
66
|
+
# flags of the options.
|
67
|
+
#
|
68
|
+
@argument_flags = Hash.new
|
69
|
+
|
70
|
+
#
|
71
|
+
# Whether error messages are output to stderr.
|
72
|
+
#
|
73
|
+
@quiet = FALSE
|
74
|
+
|
75
|
+
#
|
76
|
+
# Status code.
|
77
|
+
#
|
78
|
+
@status = STATUS_YET
|
79
|
+
|
80
|
+
#
|
81
|
+
# Error code.
|
82
|
+
#
|
83
|
+
@error = nil
|
84
|
+
|
85
|
+
#
|
86
|
+
# Error message.
|
87
|
+
#
|
88
|
+
@error_message = nil
|
89
|
+
|
90
|
+
#
|
91
|
+
# Rest of catinated short options.
|
92
|
+
#
|
93
|
+
@rest_singles = ''
|
94
|
+
|
95
|
+
#
|
96
|
+
# List of non-option-arguments.
|
97
|
+
# Append them to @argv when option processing is terminated.
|
98
|
+
#
|
99
|
+
@non_option_arguments = Array.new
|
100
|
+
|
101
|
+
if 0 < arguments.length
|
102
|
+
set_options(*arguments)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
#
|
107
|
+
# Set ordering.
|
108
|
+
#
|
109
|
+
def ordering=(ordering)
|
110
|
+
#
|
111
|
+
# The method is failed if option processing has already started.
|
112
|
+
#
|
113
|
+
if @status != STATUS_YET
|
114
|
+
set_error(ArgumentError, "argument error")
|
115
|
+
raise RuntimeError,
|
116
|
+
"invoke ordering=, but option processing has already started"
|
117
|
+
end
|
118
|
+
|
119
|
+
#
|
120
|
+
# Check ordering.
|
121
|
+
#
|
122
|
+
if !ORDERINGS.include?(ordering)
|
123
|
+
raise ArgumentError, "invalid ordering `#{ordering}'"
|
124
|
+
end
|
125
|
+
if ordering == PERMUTE && ENV.include?('POSIXLY_CORRECT')
|
126
|
+
@ordering = REQUIRE_ORDER
|
127
|
+
else
|
128
|
+
@ordering = ordering
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
#
|
133
|
+
# Return ordering.
|
134
|
+
#
|
135
|
+
attr_reader :ordering
|
136
|
+
|
137
|
+
#
|
138
|
+
# Set options
|
139
|
+
#
|
140
|
+
def set_options(*arguments)
|
141
|
+
#
|
142
|
+
# The method is failed if option processing has already started.
|
143
|
+
#
|
144
|
+
if @status != STATUS_YET
|
145
|
+
raise RuntimeError,
|
146
|
+
"invoke set_options, but option processing has already started"
|
147
|
+
end
|
148
|
+
|
149
|
+
#
|
150
|
+
# Clear tables of option names and argument flags.
|
151
|
+
#
|
152
|
+
@canonical_names.clear
|
153
|
+
@argument_flags.clear
|
154
|
+
|
155
|
+
arguments.each do |arg|
|
156
|
+
#
|
157
|
+
# Each argument must be an Array.
|
158
|
+
#
|
159
|
+
if !arg.is_a?(Array)
|
160
|
+
raise ArgumentError, "the option list contains non-Array argument"
|
161
|
+
end
|
162
|
+
|
163
|
+
#
|
164
|
+
# Find an argument flag and it set to `argument_flag'.
|
165
|
+
#
|
166
|
+
argument_flag = nil
|
167
|
+
arg.each do |i|
|
168
|
+
if ARGUMENT_FLAGS.include?(i)
|
169
|
+
if argument_flag != nil
|
170
|
+
raise ArgumentError, "too many argument-flags"
|
171
|
+
end
|
172
|
+
argument_flag = i
|
173
|
+
end
|
174
|
+
end
|
175
|
+
raise ArgumentError, "no argument-flag" if argument_flag == nil
|
176
|
+
|
177
|
+
canonical_name = nil
|
178
|
+
arg.each do |i|
|
179
|
+
#
|
180
|
+
# Check an option name.
|
181
|
+
#
|
182
|
+
next if i == argument_flag
|
183
|
+
begin
|
184
|
+
if !i.is_a?(String) || i !~ /^-([^-]|-.+)$/
|
185
|
+
raise ArgumentError, "an invalid option `#{i}'"
|
186
|
+
end
|
187
|
+
if (@canonical_names.include?(i))
|
188
|
+
raise ArgumentError, "option redefined `#{i}'"
|
189
|
+
end
|
190
|
+
rescue
|
191
|
+
@canonical_names.clear
|
192
|
+
@argument_flags.clear
|
193
|
+
raise
|
194
|
+
end
|
195
|
+
|
196
|
+
#
|
197
|
+
# Register the option (`i') to the `@canonical_names' and
|
198
|
+
# `@canonical_names' Hashes.
|
199
|
+
#
|
200
|
+
if canonical_name == nil
|
201
|
+
canonical_name = i
|
202
|
+
end
|
203
|
+
@canonical_names[i] = canonical_name
|
204
|
+
@argument_flags[i] = argument_flag
|
205
|
+
end
|
206
|
+
raise ArgumentError, "no option name" if canonical_name == nil
|
207
|
+
end
|
208
|
+
return self
|
209
|
+
end
|
210
|
+
|
211
|
+
#
|
212
|
+
# Set/Unset `quit' mode.
|
213
|
+
#
|
214
|
+
attr_writer :quiet
|
215
|
+
|
216
|
+
#
|
217
|
+
# Return the flag of `quiet' mode.
|
218
|
+
#
|
219
|
+
attr_reader :quiet
|
220
|
+
|
221
|
+
#
|
222
|
+
# `quiet?' is an alias of `quiet'.
|
223
|
+
#
|
224
|
+
alias quiet? quiet
|
225
|
+
|
226
|
+
#
|
227
|
+
# Termintate option processing.
|
228
|
+
#
|
229
|
+
def terminate
|
230
|
+
return nil if @status == STATUS_TERMINATED
|
231
|
+
raise RuntimeError, "an error has occured" if @error != nil
|
232
|
+
|
233
|
+
@status = STATUS_TERMINATED
|
234
|
+
@non_option_arguments.reverse_each do |argument|
|
235
|
+
@argv.unshift(argument)
|
236
|
+
end
|
237
|
+
|
238
|
+
@canonical_names = nil
|
239
|
+
@argument_flags = nil
|
240
|
+
@rest_singles = nil
|
241
|
+
@non_option_arguments = nil
|
242
|
+
|
243
|
+
return self
|
244
|
+
end
|
245
|
+
|
246
|
+
#
|
247
|
+
# Examine whether option processing is termintated or not.
|
248
|
+
#
|
249
|
+
def terminated?
|
250
|
+
return @status == STATUS_TERMINATED
|
251
|
+
end
|
252
|
+
|
253
|
+
#
|
254
|
+
# Set an error (protected).
|
255
|
+
#
|
256
|
+
def set_error(type, message)
|
257
|
+
#$stderr.print("#{$0}: #{message}\n") if !@quiet
|
258
|
+
|
259
|
+
@error = type
|
260
|
+
@error_message = message
|
261
|
+
@canonical_names = nil
|
262
|
+
@argument_flags = nil
|
263
|
+
@rest_singles = nil
|
264
|
+
@non_option_arguments = nil
|
265
|
+
|
266
|
+
raise type, message
|
267
|
+
end
|
268
|
+
protected :set_error
|
269
|
+
|
270
|
+
#
|
271
|
+
# Examine whether an option processing is failed.
|
272
|
+
#
|
273
|
+
attr_reader :error
|
274
|
+
|
275
|
+
#
|
276
|
+
# `error?' is an alias of `error'.
|
277
|
+
#
|
278
|
+
alias error? error
|
279
|
+
|
280
|
+
#
|
281
|
+
# Return an error message.
|
282
|
+
#
|
283
|
+
def error_message
|
284
|
+
return @error_message
|
285
|
+
end
|
286
|
+
|
287
|
+
#
|
288
|
+
# Get next option name and its argument as an array.
|
289
|
+
#
|
290
|
+
def get
|
291
|
+
option_name, option_argument = nil, ''
|
292
|
+
|
293
|
+
#
|
294
|
+
# Check status.
|
295
|
+
#
|
296
|
+
return nil if @error != nil
|
297
|
+
case @status
|
298
|
+
when STATUS_YET
|
299
|
+
@status = STATUS_STARTED
|
300
|
+
when STATUS_TERMINATED
|
301
|
+
return nil
|
302
|
+
end
|
303
|
+
|
304
|
+
#
|
305
|
+
# Get next option argument.
|
306
|
+
#
|
307
|
+
if 0 < @rest_singles.length
|
308
|
+
argument = '-' + @rest_singles
|
309
|
+
elsif (@argv.length == 0)
|
310
|
+
terminate
|
311
|
+
return nil
|
312
|
+
elsif @ordering == PERMUTE
|
313
|
+
while 0 < @argv.length && @argv[0] !~ /^-./
|
314
|
+
@non_option_arguments.push(@argv.shift)
|
315
|
+
end
|
316
|
+
if @argv.length == 0
|
317
|
+
terminate
|
318
|
+
return nil
|
319
|
+
end
|
320
|
+
argument = @argv.shift
|
321
|
+
elsif @ordering == REQUIRE_ORDER
|
322
|
+
if (@argv[0] !~ /^-./)
|
323
|
+
terminate
|
324
|
+
return nil
|
325
|
+
end
|
326
|
+
argument = @argv.shift
|
327
|
+
else
|
328
|
+
argument = @argv.shift
|
329
|
+
end
|
330
|
+
|
331
|
+
#
|
332
|
+
# Check the special argument `--'.
|
333
|
+
# `--' indicates the end of the option list.
|
334
|
+
#
|
335
|
+
if argument == '--' && @rest_singles.length == 0
|
336
|
+
terminate
|
337
|
+
return nil
|
338
|
+
end
|
339
|
+
|
340
|
+
#
|
341
|
+
# Check for long and short options.
|
342
|
+
#
|
343
|
+
if argument =~ /^(--[^=]+)/ && @rest_singles.length == 0
|
344
|
+
#
|
345
|
+
# This is a long style option, which start with `--'.
|
346
|
+
#
|
347
|
+
pattern = $1
|
348
|
+
if @canonical_names.include?(pattern)
|
349
|
+
option_name = pattern
|
350
|
+
else
|
351
|
+
#
|
352
|
+
# The option `option_name' is not registered in `@canonical_names'.
|
353
|
+
# It may be an abbreviated.
|
354
|
+
#
|
355
|
+
match_count = 0
|
356
|
+
@canonical_names.each_key do |key|
|
357
|
+
if key.index(pattern) == 0
|
358
|
+
option_name = key
|
359
|
+
match_count += 1
|
360
|
+
end
|
361
|
+
end
|
362
|
+
if 2 <= match_count
|
363
|
+
set_error(AmbigousOption, "option `#{argument}' is ambiguous")
|
364
|
+
elsif match_count == 0
|
365
|
+
set_error(InvalidOption, "unrecognized option `#{argument}'")
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
#
|
370
|
+
# Check an argument to the option.
|
371
|
+
#
|
372
|
+
if @argument_flags[option_name] == REQUIRED_ARGUMENT
|
373
|
+
if argument =~ /=(.*)$/
|
374
|
+
option_argument = $1
|
375
|
+
elsif 0 < @argv.length
|
376
|
+
option_argument = @argv.shift
|
377
|
+
else
|
378
|
+
set_error(MissingArgument,
|
379
|
+
"option `#{argument}' requires an argument")
|
380
|
+
end
|
381
|
+
elsif @argument_flags[option_name] == OPTIONAL_ARGUMENT
|
382
|
+
if argument =~ /=(.*)$/
|
383
|
+
option_argument = $1
|
384
|
+
elsif 0 < @argv.length && @argv[0] !~ /^-./
|
385
|
+
option_argument = @argv.shift
|
386
|
+
else
|
387
|
+
option_argument = ''
|
388
|
+
end
|
389
|
+
elsif argument =~ /=(.*)$/
|
390
|
+
set_error(NeedlessArgument,
|
391
|
+
"option `#{option_name}' doesn't allow an argument")
|
392
|
+
end
|
393
|
+
|
394
|
+
elsif argument =~ /^(-(.))(.*)/
|
395
|
+
#
|
396
|
+
# This is a short style option, which start with `-' (not `--').
|
397
|
+
# Short options may be catinated (e.g. `-l -g' is equivalent to
|
398
|
+
# `-lg').
|
399
|
+
#
|
400
|
+
option_name, ch, @rest_singles = $1, $2, $3
|
401
|
+
|
402
|
+
if @canonical_names.include?(option_name)
|
403
|
+
#
|
404
|
+
# The option `option_name' is found in `@canonical_names'.
|
405
|
+
# Check its argument.
|
406
|
+
#
|
407
|
+
if @argument_flags[option_name] == REQUIRED_ARGUMENT
|
408
|
+
if 0 < @rest_singles.length
|
409
|
+
option_argument = @rest_singles
|
410
|
+
@rest_singles = ''
|
411
|
+
elsif 0 < @argv.length
|
412
|
+
option_argument = @argv.shift
|
413
|
+
else
|
414
|
+
# 1003.2 specifies the format of this message.
|
415
|
+
set_error(MissingArgument, "option requires an argument -- #{ch}")
|
416
|
+
end
|
417
|
+
elsif @argument_flags[option_name] == OPTIONAL_ARGUMENT
|
418
|
+
if 0 < @rest_singles.length
|
419
|
+
option_argument = @rest_singles
|
420
|
+
@rest_singles = ''
|
421
|
+
elsif 0 < @argv.length && @argv[0] !~ /^-./
|
422
|
+
option_argument = @argv.shift
|
423
|
+
else
|
424
|
+
option_argument = ''
|
425
|
+
end
|
426
|
+
end
|
427
|
+
else
|
428
|
+
#
|
429
|
+
# This is an invalid option.
|
430
|
+
# 1003.2 specifies the format of this message.
|
431
|
+
#
|
432
|
+
if ENV.include?('POSIXLY_CORRECT')
|
433
|
+
set_error(InvalidOption, "illegal option -- #{ch}")
|
434
|
+
else
|
435
|
+
set_error(InvalidOption, "invalid option -- #{ch}")
|
436
|
+
end
|
437
|
+
end
|
438
|
+
else
|
439
|
+
#
|
440
|
+
# This is a non-option argument.
|
441
|
+
# Only RETURN_IN_ORDER falled into here.
|
442
|
+
#
|
443
|
+
return '', argument
|
444
|
+
end
|
445
|
+
|
446
|
+
return @canonical_names[option_name], option_argument
|
447
|
+
end
|
448
|
+
|
449
|
+
#
|
450
|
+
# `get_option' is an alias of `get'.
|
451
|
+
#
|
452
|
+
alias get_option get
|
453
|
+
|
454
|
+
#
|
455
|
+
# Iterator version of `get'.
|
456
|
+
#
|
457
|
+
def each
|
458
|
+
loop do
|
459
|
+
option_name, option_argument = get_option
|
460
|
+
break if option_name == nil
|
461
|
+
yield option_name, option_argument
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
#
|
466
|
+
# `each_option' is an alias of `each'.
|
467
|
+
#
|
468
|
+
alias each_option each
|
469
|
+
end
|
470
|
+
end
|