optiflag 0.6

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.
@@ -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
+