optiflag 0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,12 @@
1
+ require 'optiflag'
2
+
3
+ # Example 4: Disallowing warnings to proceed
4
+ module Example extend OptiFlag::Flagset
5
+ flag "dir"
6
+ flag "username"
7
+ handle_errors_and_help :with_no_warnings
8
+ end
9
+
10
+ #h# ruby example_4.rb -garbage -dir c:/temp -username daniel -this-is-garbage that.is.left.over
11
+
12
+
@@ -0,0 +1,26 @@
1
+ require 'optiflag'
2
+
3
+ # Example 5: Using keyword
4
+ module Example extend OptiFlag::Flagset
5
+ keyword "checkin" do
6
+ alternate_forms "ci"
7
+ end
8
+ keyword "checkout" do
9
+ alternate_forms "co"
10
+ end
11
+ flag "file"
12
+ flag "m" do
13
+ alternate_forms "message"
14
+ end
15
+
16
+ handle_errors_and_help
17
+ end
18
+
19
+ puts "User has chosen to checkin #{ARGV.flag_value.file } " if ARGV.flag_value.ci?
20
+ puts "User has chosen to check out #{ARGV.flag_value.file }" if ARGV.flag_value.checkout?
21
+
22
+ #h# ruby example_5.rb ci -file c:/StronglyTyped.java -m done
23
+ #h# ruby example_5.rb co -file c:/StronglyTyped.java -m done
24
+
25
+
26
+
@@ -0,0 +1,17 @@
1
+ require 'optiflag'
2
+
3
+ # Example 6: Using Hash Access
4
+ module HashAcess extend OptiFlag::Flagset
5
+ flag "dir"
6
+ flag "log_level"
7
+
8
+ handle_errors_and_help
9
+ end
10
+
11
+ puts "Dir is: #{ ARGV.flag_value[:dir] }"
12
+ puts "Log Level is: #{ ARGV.flag_value[:log_level] }"
13
+
14
+ #h# ruby example_6.rb -dir "c:/Program Files/Apache Software Foundation/Tomcat 5/" -log_level 3
15
+
16
+
17
+
@@ -0,0 +1,39 @@
1
+ require 'optiflag'
2
+
3
+ # Example 7: Character Flags
4
+ module HashAcess extend OptiFlag::Flagset
5
+
6
+ character_flag :l, :list_group
7
+ character_flag :s, :list_group
8
+ character_flag :a, :list_group
9
+
10
+ character_flag :x do
11
+ description "Extract"
12
+ end
13
+ character_flag :v do
14
+ description "Verbose"
15
+ end
16
+ character_flag :f do
17
+ description "Archive File"
18
+ end
19
+
20
+ handle_errors_and_help
21
+ end
22
+
23
+ f = ARGV.flag_value
24
+ puts "'l' flag set?: #{ f.l? }"
25
+ puts "'s' flag set?: #{ f.s? }"
26
+ puts "'a' flag set?: #{ f.a? }"
27
+ puts "'x' flag set?: #{ f.x? }"
28
+ puts "'f' flag set?: #{ f.f? }"
29
+ puts "'v' flag set?: #{ f.v? }"
30
+
31
+ #h# ruby example_7.rb -lsa
32
+ #h# ruby example_7.rb -ls -a
33
+ #h# ruby example_7.rb -a -s -l
34
+ #h# ruby example_7.rb -als -x -vf
35
+ #h# ruby example_7.rb -s -xvf
36
+ #h# ruby example_7.rb -lsaxvf
37
+
38
+
39
+
data/lib/optiflag.rb ADDED
@@ -0,0 +1,860 @@
1
+ #
2
+ # http://optiflag.rubyforge.org/
3
+ #
4
+ # Author:: Daniel O. Eklund
5
+ # Copyright:: Copyright (c) 2006 Daniel O. Eklund. All rights reserved.
6
+ # License:: Ruby license.
7
+
8
+ module OptiFlag
9
+ VERSION = "0.6"
10
+ end
11
+
12
+ #------------------------------------------------------------------------------------------
13
+ #------------------------------------------------------------------------------------------
14
+ #------------------------------------------------------------------------------------------
15
+ #------------- Clause-Level Flag-Modifiers via the EachFlag class -----------------------
16
+ #------------------------------------------------------------------------------------------
17
+ #------------------------------------------------------------------------------------------
18
+ #------------------------------------------------------------------------------------------
19
+ module OptiFlag
20
+ module Flagset
21
+ @dash_symbol = "-"
22
+ attr_reader :dash_symbol
23
+ module_function :dash_symbol
24
+ def self.flag_symbol(val)
25
+ @dash_symbol = val
26
+ end
27
+ def self.increment_order_counter()
28
+ @counter ||= 0
29
+ @counter = @counter + 1
30
+ return @counter -1
31
+ end
32
+ class EachFlag
33
+ attr_reader :name, :flag, :ordered_added,
34
+ :position_validator,:validation_error,
35
+ :position_enumerated_values_validator,:the_pretranslate,:the_posttranslate,
36
+ :the_posttranslate_all,:the_pretranslate_all,:enclosing_module,
37
+ :the_description,:the_long_dash_symbol,:the_dash_symbol,
38
+ :the_arity,:the_long_form,:the_alternate_forms,:the_is_required
39
+ attr_writer :the_form_that_is_actually_used
40
+ attr_accessor :value,:for_help,:for_extended_help,:proxied_bound_method
41
+ def initialize(name,flag,enclosing_module)
42
+ # these next two lines are a highly complicated hack needed to make
43
+ # the use of two module definitions in one file, one with a flag_symbol
44
+ # and one without.. See tc_change_symbols.rb for the two tests that used to
45
+ # cause the problem... also see the changes as part of the definition of
46
+ # OptiFlag.Flagset().... -- D.O.E 5/30/06
47
+ # Search for 'def OptiFlag.Flagset(hash)' in this file
48
+ singleton_class_of_enclosing_module = class << enclosing_module; self; end;
49
+ x = singleton_class_of_enclosing_module.included_modules.select do |x|
50
+ (x.to_s =~ /OptiF/) or (x.to_s =~ /#<Modu/)
51
+ end[0]
52
+
53
+ @the_compresses,@enclosing_module = false,enclosing_module
54
+ @position_validator,@validation_error = [],[]
55
+ @position_enumerated_values_validator = []
56
+ @ordered_added = OptiFlag::Flagset::increment_order_counter()
57
+ @name,@flag,@the_long_form = name,flag,flag
58
+ @the_dash_symbol, @the_arity, @the_alternate_forms,
59
+ @the_is_required, @the_long_dash_symbol = x.dash_symbol, 1, [], true, "--"
60
+ end
61
+ # clause-level flag-modifier
62
+ def translate(position=0,&theblock)
63
+ pretranslate(position,&theblock)
64
+ end
65
+ # clause-level flag-modifier
66
+ def translate_all(&theblock)
67
+ pretranslate_all(&theblock)
68
+ end
69
+ # clause-level flag-modifier
70
+ def pretranslate(position=0,&theblock)
71
+ @the_pretranslate ||= []
72
+ @the_pretranslate[position] = theblock
73
+ end
74
+ # clause-level flag-modifier
75
+ def posttranslate(position=0,&theblock)
76
+ @the_posttranslate ||= []
77
+ @the_posttranslate[position] = theblock
78
+ end
79
+ # clause-level flag-modifier
80
+ def pretranslate_all(&theblock)
81
+ @the_pretranslate_all = theblock
82
+ end
83
+ # clause-level flag-modifier
84
+ def posttranslate_all(&theblock)
85
+ @the_posttranslate_all = theblock
86
+ end
87
+ # clause-level flag-modifier
88
+ def is_required(yes_or_no)
89
+ @the_is_required = yes_or_no
90
+ end
91
+ # clause-level flag-modifier
92
+ def value_matches(desc_regexp_pair,arg_position=0)
93
+ if desc_regexp_pair.class == Regexp
94
+ desc_regexp_pair = ["This value does not match the pattern: #{ desc_regexp_pair.source }",
95
+ desc_regexp_pair]
96
+ end
97
+ @position_validator[arg_position] = desc_regexp_pair
98
+ end
99
+ # clause-level flag-modifier
100
+ def value_in_set(array_of_acceptable_values,arg_position=0)
101
+ @position_enumerated_values_validator[arg_position] =
102
+ array_of_acceptable_values
103
+ end
104
+ # clause-level flag-modifier
105
+ def required
106
+ is_required(true)
107
+ end
108
+ # clause-level flag-modifier
109
+ def optional
110
+ is_required(false)
111
+ end
112
+ # clause-level flag-modifier
113
+ def no_arg
114
+ no_args
115
+ end
116
+ # clause-level flag-modifier
117
+ def no_args
118
+ arity 0
119
+ end
120
+ # clause-level flag-modifier
121
+ def one_arg
122
+ arity 1
123
+ end
124
+ # clause-level flag-modifier
125
+ def two_args
126
+ arity 2
127
+ end
128
+ # clause-level flag-modifier
129
+ def alternate_forms(*args)
130
+ @the_alternate_forms = *args
131
+ end
132
+ # clause-level flag-modifier
133
+ def long_form(form)
134
+ @the_long_form = form
135
+ end
136
+ # clause-level flag-modifier
137
+ def arity(num)
138
+ @the_arity = num
139
+ end
140
+ # clause-level flag-modifier
141
+ def dash_symbol(symb)
142
+ @the_dash_symbol = symb
143
+ end
144
+ # clause-level flag-modifier
145
+ def long_dash_symbol(symb)
146
+ @the_long_dash_symbol = symb
147
+ end
148
+ # clause-level flag-modifier
149
+ def description(desc)
150
+ @the_description = desc
151
+ end
152
+ # clause-level flag-modifier
153
+ def compresses(val=true)
154
+ @the_compresses = val
155
+ end
156
+ def as_string_basic
157
+ "#{ self.the_dash_symbol }#{ self.flag }"
158
+ end
159
+ def as_alternate_forms
160
+ ret = @the_alternate_forms.collect do |x|
161
+ "#{ self.the_dash_symbol }#{ x }"
162
+ end
163
+ end
164
+ def as_string_extended
165
+ "#{ self.the_long_dash_symbol }#{self.the_long_form }"
166
+ end
167
+ def as_the_form_that_is_actually_used
168
+ @the_form_that_is_actually_used
169
+ end
170
+ def value=(val)
171
+ @value = val
172
+ if pbMeth = self.proxied_bound_method
173
+ pbMeth.call val
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end
179
+
180
+ #----------------------------------------------------------------------------------
181
+ #--------------------------------------- -------------------
182
+ #--------------------------------------- A clause is the -------------------
183
+ #------------- Clause Definitions ----- main statement -------------------
184
+ #------------ top-level flag-declarer -- within the module -------------------
185
+ #--------------------------------------- -------------------
186
+ #----------------------------------------------------------------------------------
187
+ module OptiFlag
188
+ module Flagset
189
+ # top-level flag-declarer
190
+ def flag(flag_name_pair,hash={},&the_block)
191
+ if flag_name_pair.class == String or flag_name_pair.class == Symbol
192
+ flag_name_pair = [flag_name_pair.to_s,flag_name_pair.to_sym]
193
+ end
194
+ flag = flag_name_pair[0]
195
+ if flag_name_pair[1]
196
+ name = flag_name_pair[1]
197
+ else
198
+ name = flag.to_sym
199
+ end
200
+ @all_flags ||= {}
201
+ obj = @all_flags[name]
202
+ obj ||= EachFlag.new(name,flag,self)
203
+ obj.instance_eval &the_block if block_given?
204
+ hash.each_pair do |fxn,val|
205
+ obj.send(fxn,val)
206
+ end
207
+ @all_flags[name] = obj
208
+ end
209
+ # top-level flag-declarer
210
+ def optional_flag(flag_name_pair,hash={},&the_block)
211
+ flag(flag_name_pair,hash,&the_block)
212
+ flag_name_pair = [flag_name_pair] if flag_name_pair.class == String
213
+ name = flag_name_pair[1] || flag_name_pair[0]
214
+ flag_properties name.to_sym do
215
+ optional
216
+ end
217
+ end
218
+ # top-level flag-declarer
219
+ def optional_switch_flag(flag_name_pair,hash={},&the_block)
220
+ flag(flag_name_pair,hash,&the_block)
221
+ flag_name_pair = [flag_name_pair] if flag_name_pair.class == String
222
+ name = flag_name_pair[1] || flag_name_pair[0]
223
+ flag_properties name.to_sym do
224
+ optional
225
+ arity 0
226
+ end
227
+ end
228
+ # top-level flag-declarer
229
+ def keyword(flag_name_pair,hash={},&the_block)
230
+ @all_keywords ||= []
231
+ @all_keywords << name
232
+ flag(flag_name_pair,hash,&the_block)
233
+ flag_name_pair = [flag_name_pair] if flag_name_pair.class == String
234
+ name = flag_name_pair[1] || flag_name_pair[0]
235
+ flag_properties name.to_sym do
236
+ dash_symbol ""
237
+ long_dash_symbol ""
238
+ arity 0
239
+ optional
240
+ end
241
+ end
242
+ # top-level flag-declarer
243
+ def using_object(a_single_object)
244
+ potential_methods = (a_single_object.methods - Object.methods)
245
+ require 'enumerator'
246
+ valid_instance_var = []
247
+ potential_opt_switch_flags, potential_methods =
248
+ potential_methods.partition {|x| x =~ /\?$/ }
249
+ potential_methods.each_slice(2) do |getter,setter|
250
+ if setter == (getter + "=")
251
+ valid_instance_var << [getter,setter];
252
+ end
253
+ end
254
+ valid_instance_var.each do |getter,setter|
255
+ bound_method = a_single_object.method(setter)
256
+ flag getter do
257
+ self.proxied_bound_method = bound_method
258
+ end
259
+ end
260
+ end
261
+ # top-level flag-declarer
262
+ def usage_flag(*args)
263
+ first,*rest = args
264
+ optional_flag [first] do
265
+ self.for_help = true
266
+ description "Help"
267
+ no_args
268
+ alternate_forms *rest if rest.length > 0
269
+ end
270
+ end
271
+ # top-level flag-declarer
272
+ def extended_help_flag(*args)
273
+ first,*rest = args
274
+ optional_flag [first] do
275
+ self.for_extended_help = true
276
+ description "Extended Help"
277
+ no_args
278
+ alternate_forms *rest if rest.length > 0
279
+ end
280
+ end
281
+ # top-level flag-declarer
282
+ def character_flag(switch,group="default",&the_block)
283
+ throw "Character switches can only be 1 character long" if switch.to_s.length > 1
284
+ flag(switch.to_sym,&the_block)
285
+ @group ||= {}
286
+ the_flag_we_just_added = @all_flags[switch.to_sym]
287
+
288
+ key = [group.to_sym,the_flag_we_just_added.the_dash_symbol]
289
+ # puts "#{ key.join(',') }"
290
+ @group[key] ||= []
291
+ @group[key] << the_flag_we_just_added
292
+ # re-assert ourselves
293
+ flag [switch.to_s, switch] do
294
+ optional
295
+ arity 0
296
+ compresses
297
+ end
298
+ end
299
+ # top-level flag-declarer
300
+ def flag_properties(symb,&the_block)
301
+ raise "Block needed for flag_properties" if not block_given?
302
+ @all_flags ||= {}
303
+ obj = @all_flags[symb.to_sym]
304
+ return if obj==nil
305
+ obj.instance_eval &the_block if block_given?
306
+ end
307
+ alias :properties :flag_properties
308
+ def argument_order(*args)
309
+ puts "You want the arguments in this order: #{ args }"
310
+ end
311
+ end
312
+ end
313
+
314
+ # defining the callable client-interface
315
+ module OptiFlag
316
+ module Flagset
317
+ module NewInterface
318
+ attr_accessor :errors,:flag_value,:specification_errors,:help_requested_on,:warnings
319
+ attr_writer :help_requested,:extended_help_requested
320
+ def errors?
321
+ self.errors != nil
322
+ end
323
+ def warnings?
324
+ self.warnings != nil
325
+ end
326
+ def help_requested?
327
+ @help_requested != nil
328
+ end
329
+ def extended_help_requested?
330
+ @extended_help_requested !=nil
331
+ end
332
+ end
333
+ class Errors
334
+ attr_accessor :missing_flags,:other_errors,:validation_errors
335
+ def initialize
336
+ @missing_flags,@other_errors,@validation_errors = [],[],[]
337
+ end
338
+ def any_errors?
339
+ @missing_flags.length >0 or @other_errors.length >0 or
340
+ @validation_errors.length > 0
341
+ end
342
+ def divulge_problems(output=$stdout)
343
+ output.puts "Errors found:"
344
+ if @missing_flags.length >0
345
+ output.puts "Missing Flags:"
346
+ @missing_flags.each do |x|
347
+ output.puts " #{ x }"
348
+ end
349
+ end
350
+ if @other_errors.length >0
351
+ output.puts "Other Errors:"
352
+ @other_errors.each do |x|
353
+ output.puts " #{ x }"
354
+ end
355
+ end
356
+ if @validation_errors.length >0
357
+ output.puts "Validation Errors:"
358
+ @validation_errors.each do |x|
359
+ output.puts " #{ x }"
360
+ end
361
+ end
362
+ end
363
+ end
364
+ def create_new_value_class()
365
+ klass = Hash.new
366
+ klass.instance_eval do
367
+ def init_with_these(all_objs)
368
+ @all_flags = all_objs
369
+ end
370
+ end
371
+ klass.init_with_these(@all_flags)
372
+ @all_flags.each_value do |y|
373
+ # only allow alphabetic symbols to create methods
374
+ if (y.name.to_s =~ /^[a-zA-Z]+/)
375
+ klass.instance_eval %{
376
+ def #{y.name}()
377
+ @all_flags[:#{ y.name }].value if @all_flags[:#{ y.name }]
378
+ end
379
+ def #{y.name}_details()
380
+ @all_flags[:#{ y.name }] if @all_flags[:#{ y.name }]
381
+ end}
382
+ end
383
+ all_names = [y.name]
384
+ all_names << y.the_alternate_forms if y.the_alternate_forms.length > 0
385
+ all_names.flatten!
386
+ all_names = all_names.select{|x| x.to_s =~ /^[a-zA-Z]+/}
387
+ all_names.each do |x|
388
+ klass.instance_eval %{
389
+ def #{x}?()
390
+ ret = @all_flags[:#{ y.name }].value
391
+ return false if ret == nil
392
+ return @all_flags[:#{ y.name }].value if @all_flags[:#{ y.name }]
393
+ end}
394
+ end
395
+ end
396
+ return klass
397
+ end
398
+
399
+ end # end of Flagset module
400
+ end # end of OptiFlag module
401
+
402
+
403
+ #------------------------------------------------------------------------------------------
404
+ #------------------------------------------------------------------------------------------
405
+ #------------------------------------------------------------------------------------------
406
+ #------------- The actual Parsing and Error Finding Code -----------------------
407
+ #------------------------------------------------------------------------------------------
408
+ #------------------------------------------------------------------------------------------
409
+ #------------------------------------------------------------------------------------------
410
+ module OptiFlag
411
+ module Flagset
412
+ def parse(args,clone=true)
413
+ safe_args = args.clone if clone
414
+ safe_args = args if ! clone
415
+ # the following 10 lines were changed so
416
+ # that a module could reparse a command-line
417
+ # and not have a global-state change for
418
+ # everyone... I had mulled just mandating that
419
+ # a SomeArgModule::parse(ARGV) statement
420
+ # could only occur once, but since everything else
421
+ # is getting ugly, might as well allow this
422
+ # --D.O.E 5/30/2006
423
+ new_self = self.clone
424
+ new_flags = {}
425
+ @all_flags.each_pair do |key,val|
426
+ val = val.clone
427
+ new_flags[key] = val
428
+ end
429
+ new_self.module_eval do
430
+ @all_flags = new_flags
431
+ safe_args = search_for_missing_character_switches(safe_args)
432
+
433
+ safe_args = create_api(safe_args)
434
+
435
+ safe_args = search_for_missing_flags(safe_args)
436
+ populate_values(safe_args)
437
+ now_populate_hash(@all_flags,safe_args)
438
+ end
439
+ return safe_args
440
+ end
441
+
442
+ private
443
+ def now_populate_hash(all_flags,safe_args)
444
+ all_flags.each_pair do |k,v|
445
+ safe_args.flag_value[k.to_sym] = v.value
446
+ v.the_alternate_forms.each do |x|
447
+ safe_args.flag_value[x.to_sym] = v.value
448
+ end
449
+ end
450
+ end
451
+ def find_help_flags(safe_args)
452
+ arg_copy = safe_args.clone
453
+
454
+ #first we get rid of all non-help flags...
455
+ non_help_flags = @all_flags.values.select{|value| !value.for_help }
456
+ non_help_flags.each do |val|
457
+ flag_finder_and_stripper(val.as_the_form_that_is_actually_used,val.the_arity,arg_copy)
458
+ end
459
+ # ...because the help flag is overloaded... it can have an arity of 0 or 1
460
+ help_flag = @all_flags.values.select{|value| value.for_help }
461
+ if help_flag.length > 0
462
+ flag = help_flag[0].as_the_form_that_is_actually_used
463
+
464
+ found,discard = flag_finder_and_stripper(flag,1,arg_copy)
465
+ if found.length > 0
466
+ safe_args.help_requested = true
467
+ if found.length == 2
468
+ safe_args.help_requested_on = found[1]
469
+ end
470
+ end
471
+ end
472
+ arg_copy = safe_args.clone
473
+
474
+ ext_help_flag = @all_flags.values.select{|value| value.for_extended_help }
475
+ if ext_help_flag.length > 0
476
+ flag = ext_help_flag[0].as_the_form_that_is_actually_used
477
+
478
+ found,discard = flag_finder_and_stripper(flag,0,arg_copy)
479
+ if found.length > 0
480
+ safe_args.extended_help_requested = true
481
+ end
482
+ end
483
+ end
484
+ def flag_finder_and_stripper(flag,arity,args)
485
+ idx = args.index(flag)
486
+ if idx == nil
487
+ return [], args
488
+ end
489
+ the_range = idx..(idx + arity)
490
+ flag_and_values = args[the_range]
491
+ fragment = args[the_range].clone
492
+ args[the_range] = nil
493
+ return fragment, args
494
+ end
495
+ def populate_values(safe_args)
496
+ find_the_flag_that_is_actually_used(safe_args)
497
+ arg_copy = safe_args.clone
498
+ @all_flags.values.each do |flag_obj|
499
+ the_string_flag = flag_obj.as_the_form_that_is_actually_used
500
+ flag_and_values, arg_copy =
501
+ flag_finder_and_stripper(the_string_flag,flag_obj.the_arity,arg_copy)
502
+ if flag_and_values.length >2
503
+ discard,*theRest = flag_and_values
504
+ flag_obj.value = theRest
505
+ end
506
+ flag_obj.value = flag_and_values[1] if flag_and_values.length ==2
507
+ flag_obj.value = true if flag_and_values.length == 1 and flag_obj.the_arity == 0
508
+ if flag_and_values.length == 1 and flag_obj.the_arity >0
509
+ problem = "Argument(s) missing for flag #{ flag_obj.as_the_form_that_is_actually_used }"
510
+ safe_args.errors ||= Errors.new
511
+ safe_args.errors.validation_errors << problem
512
+ end
513
+ end
514
+ if arg_copy.length > 0 # is there anything left over
515
+ safe_args.warnings ||= []
516
+ safe_args.warnings <<
517
+ "There are extra arguments left over: [#{ arg_copy.join(', ') }]. "
518
+ end
519
+ validate_values(safe_args)
520
+ find_help_flags(safe_args)
521
+
522
+ return safe_args
523
+ end
524
+ def validate_values(safe_args)
525
+ run_pre_translate(safe_args)
526
+ #TODO: the two following helper methods
527
+ # are essentially the same... maybe, we can pull the
528
+ # logic into the EachFlag object itself...
529
+ # something to think about (D.O.E. 5/22/2006)
530
+ validate_values_by_regexp(safe_args)
531
+ validate_values_by_enumerated_values(safe_args)
532
+ run_post_translate(safe_args)
533
+ end
534
+ def validate_values_by_enumerated_values(safe_args)
535
+ flags_requiring_validation = @all_flags.values.select do |x|
536
+ x.position_enumerated_values_validator.length > 0 && x.value
537
+ end
538
+ flags_requiring_validation.each do |flag_obj|
539
+ value = flag_obj.value
540
+ value = [value] if value.class != Array
541
+ flag_obj.position_enumerated_values_validator.each_with_index do |enum_vals,idx|
542
+ something_matches = enum_vals.select{|x| x.to_s == value[idx] }
543
+ if something_matches.length == 0
544
+ problem = "For the flag: '#{ flag_obj.as_string_basic }' the value you gave was '#{ value[idx] }'."
545
+ problem << "\n But the value must be one of the following: [#{ enum_vals.join(', ') }]"
546
+ flag_obj.validation_error << problem
547
+ safe_args.errors ||= Errors.new
548
+ safe_args.errors.validation_errors << problem
549
+ end
550
+ end
551
+ end
552
+ end
553
+ def validate_values_by_regexp(safe_args)
554
+ flags_requiring_validation = @all_flags.values.select do |x|
555
+ x.position_validator.length > 0 && x.value
556
+ end
557
+ flags_requiring_validation.each do |flag_obj|
558
+ value = flag_obj.value
559
+ value = [value] if value.class != Array
560
+ flag_obj.position_validator.each_with_index do |(desc,regex),idx|
561
+ if ! value[idx].match regex
562
+ problem = "For the flag: '#{ flag_obj.as_string_basic }' the value you gave was '#{ value[idx] }'."
563
+ problem << "\n #{ desc }"
564
+ flag_obj.validation_error << problem
565
+ safe_args.errors ||= Errors.new
566
+ safe_args.errors.validation_errors << problem
567
+ end
568
+ end
569
+ end
570
+ end
571
+ def run_pre_translate(safe_args)
572
+ flags_requiring_pre_translating = @all_flags.values.select do |x|
573
+ x.the_pretranslate && x.value
574
+ end
575
+ standard_translating(flags_requiring_pre_translating,:the_pretranslate)
576
+ end
577
+ def run_post_translate(safe_args)
578
+ flags_requiring_post_translating = @all_flags.values.select do |x|
579
+ x.the_posttranslate && x.value
580
+ end
581
+ standard_translating(flags_requiring_post_translating,:the_posttranslate)
582
+ end
583
+ def standard_translating(arr,pre_or_post)
584
+ arr.each do |flag|
585
+ flag.send(pre_or_post).each_with_index do |translate,idx|
586
+ the_value = flag.value
587
+ the_value = [the_value] if the_value.class != Array
588
+ if translate.arity > 1
589
+ retVal = translate.call *the_value
590
+ retVal ||= []
591
+ retVal = [retVal] if retVal.class !=Array
592
+ if retVal.length != translate.arity
593
+ raise "Error: the translate block you used had #{ translate.arity } arguments, but your block returned #{ retVal.length } values. They must be equal."
594
+ end
595
+ flag.value = retVal
596
+ elsif translate.arity == 1
597
+ retVal = translate.call(the_value[idx])
598
+ flag.value[idx] = retVal
599
+ end
600
+ end
601
+ end
602
+ end
603
+ def find_the_flag_that_is_actually_used(safe_args)
604
+ there_might_be_errors = safe_args.errors || Errors.new
605
+ args_copy = safe_args.clone
606
+ @all_flags.values.each do |x|
607
+ shortform,longform = x.as_string_basic,x.as_string_extended
608
+ all_forms = [shortform,longform] + x.as_alternate_forms
609
+ form_found_mask = all_forms.collect do |form|
610
+ is_form_found, args_copy =
611
+ flag_finder_and_stripper(form,x.the_arity,args_copy)
612
+ [ (is_form_found.length > 0), is_form_found ]
613
+ end
614
+ any_found = form_found_mask.select{|(found,parms)| found}
615
+ if any_found.length > 1
616
+ there_might_be_errors.other_errors <<
617
+ "More than one flag form of -- is present. This is ambiguous. Choose one only."
618
+ end
619
+ if any_found.length == 1
620
+ x.the_form_that_is_actually_used = any_found[0][1][0]
621
+ end
622
+ end
623
+ if there_might_be_errors.any_errors?
624
+ safe_args.errors = there_might_be_errors
625
+ end
626
+ return safe_args
627
+ end
628
+ def search_for_missing_character_switches(safe_args)
629
+ these_args = safe_args.clone
630
+ return safe_args if @group == nil
631
+ chars_found_for_this_group = {}
632
+ all_chars = ""
633
+ @group.each_pair do |k,val|
634
+ name_of_flag = val.collect{|x| x.name}
635
+ all_chars_alphabetical = name_of_flag.join('').unpack('c*').sort.pack('c*')
636
+ args_namespaced = these_args.select{|x| x.match("^#{ k[1] }") }
637
+ seems_to_match = []
638
+ args_namespaced.each do |flag|
639
+ flag_value = flag.match("^#{ k[1]}").post_match
640
+ potential = all_chars_alphabetical.tr(flag_value,"")
641
+ if potential.length == all_chars_alphabetical.length - flag_value.length
642
+ seems_to_match << flag_value
643
+ all_chars_alphabetical = all_chars_alphabetical.tr(flag_value,"")
644
+ these_args = these_args - [flag]
645
+ end
646
+ end
647
+ seems_to_match = seems_to_match.flatten.join('')
648
+ chars_found_for_this_group[k] = seems_to_match
649
+ all_chars << seems_to_match
650
+ end
651
+
652
+ all_chars.split(//).each do |x|
653
+ opt_flag = @all_flags[x.to_sym]
654
+ opt_flag.value = true
655
+ end
656
+
657
+ return safe_args
658
+ end
659
+
660
+ def search_for_missing_flags(safe_args)
661
+ there_might_be_errors = Errors.new
662
+ required_flags = @all_flags.values.sort{|x,y| x.ordered_added <=> y.ordered_added }.select{|x| x.the_is_required }
663
+ args_copy = safe_args.clone
664
+ required_flags.each do |x|
665
+ shortform,longform = x.as_string_basic,x.as_string_extended
666
+ all_forms = [shortform,longform] + x.as_alternate_forms
667
+
668
+ form_found_mask = all_forms.collect do |form|
669
+ is_form_found, args_copy =
670
+ flag_finder_and_stripper(form,x.the_arity,args_copy)
671
+ [ (is_form_found.length > 0), is_form_found ]
672
+ end
673
+ is_first_found,is_second_found = form_found_mask
674
+ any_found = form_found_mask.select{|(found,parms)| found}
675
+ if any_found.length == 0
676
+ there_might_be_errors.missing_flags << x.as_string_basic
677
+ end
678
+ if is_second_found[0] && is_first_found[0]
679
+ there_might_be_errors.other_errors <<
680
+ "Both forms #{ x.as_string_basic } and #{x.as_string_extended } are present. This is ambiguous. Choose one only."
681
+ end
682
+ if any_found.length == 1
683
+ x.the_form_that_is_actually_used = any_found[0][1][0]
684
+ end
685
+ end
686
+ if there_might_be_errors.any_errors?
687
+ safe_args.errors = there_might_be_errors
688
+ end
689
+ return safe_args
690
+ end
691
+ def create_api(safe_args)
692
+
693
+ safe_args.extend NewInterface
694
+ safe_args.flag_value = create_new_value_class()
695
+ return safe_args
696
+ end
697
+ end
698
+ end
699
+
700
+ module OptiFlag
701
+ def OptiFlag.Flagset(hash)
702
+ # changed this from just returning Flagset...
703
+ # Reason Being: a user can specify two modules in one file
704
+ # one with this method, and one just using Flagset...
705
+ # if you don't clone at this point, you are left with
706
+ # a global change... BUT to get the cloning working
707
+ # I had to do some singleton_class trickeration as part of
708
+ # the initialize method for EachFlag... I am not
709
+ # 100% sure I understand what I just did. -- D.O.E 5/30/06
710
+ mod = Flagset.clone
711
+ hash.each_pair do |symb,val|
712
+ mod.send(symb.to_sym,val)
713
+ end
714
+ return mod
715
+ end
716
+
717
+ end
718
+
719
+ module OptiFlag
720
+ module Flagset
721
+ def handle_errors_and_help(level=:not_strict)
722
+ return if !@all_flags
723
+ parse(ARGV,false)
724
+ if ARGV.help_requested?
725
+ if !ARGV.help_requested_on
726
+ show_help
727
+ elsif the_on = ARGV.help_requested_on
728
+ show_individual_extended_help(the_on.to_sym)
729
+ end
730
+ exit
731
+ end
732
+ if ARGV.extended_help_requested?
733
+ show_extended_help
734
+ exit
735
+ end
736
+ if ARGV.errors?
737
+ ARGV.errors.divulge_problems
738
+ show_help
739
+ exit
740
+ end
741
+ if ARGV.warnings? and level == :with_no_warnings
742
+ puts "In strict warning handling mode. Warnings will cause process to exit."
743
+ ARGV.warnings.each do |x|
744
+ puts " #{ x }"
745
+ end
746
+ puts "Please fix these warnings and try again."
747
+ exit
748
+ end
749
+ ARGV
750
+ end # end of method handle_errors_and_help
751
+ end # end of Flagset
752
+ end # end of OptiFlag
753
+
754
+
755
+
756
+ # Specification error possibilities (at FlagsetDefinition)
757
+ # 1) a value_matches and a value_in_set on the same argument
758
+ # 2) ambiguous flag names (e.g. two flags both with name -help)
759
+ # 3) short symbol flag and long symbol flags match each other
760
+
761
+ # Specification error possibilities (at DefinitionSwitcher)
762
+ # 1)
763
+ # 2)
764
+
765
+ # Warning conditions
766
+ # 1) Left-over arguments
767
+
768
+
769
+ #---------------------------------------------------------------------------------------------------------------
770
+ #---------------------------------------------------------------------------------------------------------------
771
+ #---------------------------------------------------------------------------------------------------------------
772
+ #---------------------------------- help and error rendering stuff --------------------------------------------
773
+ #---------------------------------------------------------------------------------------------------------------
774
+ #---------------------------------------------------------------------------------------------------------------
775
+ #---------------------------------------------------------------------------------------------------------------
776
+ module OptiFlag
777
+ module Flagset
778
+ module Help
779
+ class Bundle
780
+ attr_accessor :help,:extended_help,:banner;
781
+ end
782
+ module StandardHelpBundle
783
+ STANDARD_HELP_BANNER = proc do |render_on|
784
+ render_on.printf(" %-10s %-15s %5s\n","Flag","Name","Is Required?")
785
+ end
786
+ STANDARD_HELP = proc do |render_on,short,long,dash_short,dash_long,required_or_not,description|
787
+ render_on.printf(" #{ dash_short }%-10s %-15s %5s\n",
788
+ short,short,required_or_not)
789
+ end
790
+ STANDARD_EXTENDED_HELP = proc do |render_on,short,long,dash_short,dash_long,required_or_not,description,arity,alternate_forms,name|
791
+ render_on.puts "--------------------------------"
792
+ desc = <<-EOF
793
+ Name: #{ name }
794
+ Simple Flag: #{ dash_short }#{ short }
795
+ Required?: #{ required_or_not }
796
+ # of Arguments: #{ (arity > 0) ? arity : 'None' }
797
+ EOF
798
+ desc << <<-EOF if description
799
+ Description: #{ description }
800
+ EOF
801
+ desc << <<-EOF if long
802
+ Long Form Flag: #{ dash_long }#{ long }
803
+ EOF
804
+ desc << <<-EOF if alternate_forms.length > 0
805
+ Alternate Flags: #{ dash_short }[#{ alternate_forms.join(', ') }]
806
+ EOF
807
+ render_on.puts desc
808
+ end
809
+ end
810
+ end
811
+ end
812
+ end
813
+
814
+
815
+ module OptiFlag
816
+ module Flagset
817
+ attr_accessor :registered_help,:help_banner,:registered_extended_help;
818
+ def register_bundle(bundle)
819
+ self.registered_extended_help = bundle.extended_help
820
+ self.registered_help = bundle.help
821
+ self.help_banner = bundle.banner
822
+ end
823
+
824
+ def registered_help; Help::StandardHelpBundle::STANDARD_HELP; end
825
+ def registered_extended_help; Help::StandardHelpBundle::STANDARD_EXTENDED_HELP; end
826
+ def help_banner; Help::StandardHelpBundle::STANDARD_HELP_BANNER; end
827
+
828
+ def render_help(stdo=$stdout)
829
+ help = self.registered_help
830
+ help_banner = self.help_banner
831
+
832
+ help_banner.call stdo
833
+ @all_flags.each_pair do |key,val|
834
+ help.call stdo,val.flag,val.the_long_form,val.the_dash_symbol,val.the_long_dash_symbol,val.the_is_required,val.the_description
835
+ end
836
+ end
837
+ def show_help(start_message="",stdo=$stdout)
838
+ stdo.puts start_message
839
+ render_help(stdo)
840
+ @all_keywords ||= []
841
+ @all_keywords.each do |x|
842
+ stdo.puts "Flagless Argument: #{ x }"
843
+ end
844
+ end
845
+ def show_extended_help(start_message="",stdo=$stdout)
846
+ show_help(start_message,stdo)
847
+ @all_flags.keys.each do |name|
848
+ show_individual_extended_help(name,stdo)
849
+ end
850
+ end
851
+ def show_individual_extended_help(name,stdo=$stdout)
852
+ x = @all_flags[name]
853
+ return if !x
854
+ extended_help = self.registered_extended_help
855
+ extended_help.call stdo, x.flag, x.the_long_form,x.the_dash_symbol,x.the_long_dash_symbol,
856
+ x.the_is_required,x.the_description,x.the_arity,x.the_alternate_forms,x.name
857
+ end
858
+ end
859
+ end
860
+