ThiagoLelis-backgroundjob 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/lib/main/logger.rb CHANGED
@@ -1,51 +1,51 @@
1
- module Main
2
- ### because active_record fubars the hell out of Logger ;-(
3
- class Logger < ::Logger
4
- def self.new *a, &b
5
- super(*a, &b).instance_eval{ @default_formatter = @formatter = Formatter.new; self }
6
- end
7
- def format_message(severity, datetime, progname, msg)
8
- (@formatter || @default_formatter).call(severity, datetime, progname, msg)
9
- end
10
-
11
- def device
12
- @logdev.instance_eval{ @dev }
13
- end
14
-
15
- def tty?
16
- device.respond_to?('tty?') and device.tty?
17
- end
18
-
19
- def turn which
20
- @logdev.extend OnOff unless OnOff === @logdev
21
- @logdev.turn which
22
- end
23
-
24
- def on
25
- turn :on
26
- end
27
- alias_method "on!", "on"
28
- def self.on *a, &b
29
- new(*a, &b).instance_eval{ turn :on; self }
30
- end
31
-
32
- def off
33
- turn :off
34
- end
35
- alias_method "off!", "off"
36
- def self.off *a, &b
37
- new(*a, &b).instance_eval{ turn :off; self }
38
- end
39
-
40
- module OnOff
41
- def turn which
42
- @turned = which.to_s =~ %r/on/i ? :on : :off
43
- end
44
-
45
- def write message
46
- return message.to_s.size if @turned == :off
47
- super
48
- end
49
- end
50
- end
51
- end
1
+ module Main
2
+ ### because active_record fubars the hell out of Logger ;-(
3
+ class Logger < ::Logger
4
+ def self.new *a, &b
5
+ super(*a, &b).instance_eval{ @default_formatter = @formatter = Formatter.new; self }
6
+ end
7
+ def format_message(severity, datetime, progname, msg)
8
+ (@formatter || @default_formatter).call(severity, datetime, progname, msg)
9
+ end
10
+
11
+ def device
12
+ @logdev.instance_eval{ @dev }
13
+ end
14
+
15
+ def tty?
16
+ device.respond_to?('tty?') and device.tty?
17
+ end
18
+
19
+ def turn which
20
+ @logdev.extend OnOff unless OnOff === @logdev
21
+ @logdev.turn which
22
+ end
23
+
24
+ def on
25
+ turn :on
26
+ end
27
+ alias_method "on!", "on"
28
+ def self.on *a, &b
29
+ new(*a, &b).instance_eval{ turn :on; self }
30
+ end
31
+
32
+ def off
33
+ turn :off
34
+ end
35
+ alias_method "off!", "off"
36
+ def self.off *a, &b
37
+ new(*a, &b).instance_eval{ turn :off; self }
38
+ end
39
+
40
+ module OnOff
41
+ def turn which
42
+ @turned = which.to_s =~ %r/on/i ? :on : :off
43
+ end
44
+
45
+ def write message
46
+ return message.to_s.size if @turned == :off
47
+ super
48
+ end
49
+ end
50
+ end
51
+ end
data/lib/main/mode.rb CHANGED
@@ -1,42 +1,42 @@
1
- class Mode < ::String
2
- class Error < ::StandardError; end
3
- class Duplicate < Error; end
4
- class Ambiguous < Error
5
- include Main::Softspoken
6
- end
7
-
8
- class List < ::Array
9
- def initialize *a, &b
10
- super
11
- ensure
12
- self.fields = []
13
- end
14
- def add klass
15
- mode_name = Mode.new klass.mode_name
16
- raise Duplicate, mode_name if has_key? mode_name
17
- self[mode_name] = klass
18
- end
19
- def find_by_mode m, options = {}
20
- quiet = options['quiet'] || options[:quiet]
21
- each_pair do |mode, klass|
22
- return mode if mode == m
23
- end
24
- candidates = []
25
- each_pair do |mode, klass|
26
- candidates << mode if mode.index(m) == 0
27
- end
28
- case candidates.size
29
- when 0
30
- nil
31
- when 1
32
- candidates.first
33
- else
34
- raise Ambiguous, "ambiguous mode: #{ m } = (#{ candidates.sort.join ' or ' })?"
35
- end
36
- end
37
- end
38
-
39
- def self.list *a, &b
40
- List.new *a, &b
41
- end
42
- end
1
+ class Mode < ::String
2
+ class Error < ::StandardError; end
3
+ class Duplicate < Error; end
4
+ class Ambiguous < Error
5
+ include Main::Softspoken
6
+ end
7
+
8
+ class List < ::Array
9
+ def initialize *a, &b
10
+ super
11
+ ensure
12
+ self.fields = []
13
+ end
14
+ def add klass
15
+ mode_name = Mode.new klass.mode_name
16
+ raise Duplicate, mode_name if has_key? mode_name
17
+ self[mode_name] = klass
18
+ end
19
+ def find_by_mode m, options = {}
20
+ quiet = options['quiet'] || options[:quiet]
21
+ each_pair do |mode, klass|
22
+ return mode if mode == m
23
+ end
24
+ candidates = []
25
+ each_pair do |mode, klass|
26
+ candidates << mode if mode.index(m) == 0
27
+ end
28
+ case candidates.size
29
+ when 0
30
+ nil
31
+ when 1
32
+ candidates.first
33
+ else
34
+ raise Ambiguous, "ambiguous mode: #{ m } = (#{ candidates.sort.join ' or ' })?"
35
+ end
36
+ end
37
+ end
38
+
39
+ def self.list *a, &b
40
+ List.new *a, &b
41
+ end
42
+ end
@@ -1,685 +1,685 @@
1
- module Main
2
- class Parameter
3
- class Error < StandardError
4
- include Softspoken
5
- fattr 'wrapped'
6
- end
7
- class Arity < Error; end
8
- class NotGiven < Arity; end
9
- class InValid < Error; end
10
- class NoneSuch < Error; end
11
- class AmbigousOption < Error; end
12
- class NeedlessArgument < Error; end
13
- class MissingArgument < Error; end
14
- class InvalidOption < Error; end
15
-
16
- class << self
17
- def wrapped_error w
18
- e = Error.new "(#{ w.message } (#{ w.class }))"
19
- e.wrapped = w
20
- e.set_backtrace(w.backtrace || [])
21
- e
22
- end
23
-
24
- def wrap_errors
25
- begin
26
- yield
27
- rescue => e
28
- raise wrapped_error(e)
29
- end
30
- end
31
-
32
- Types = [ Parameter ]
33
- def inherited other
34
- Types << other
35
- end
36
-
37
- def sym
38
- @sym ||= name.split(%r/::/).last.downcase.to_sym
39
- end
40
-
41
- def class_for type
42
- sym = type.to_s.downcase.to_sym
43
- c = Types.detect{|t| t.sym == sym}
44
- raise ArgumentError, type.inspect unless c
45
- c
46
- end
47
-
48
- def create type, *a, &b
49
- c = class_for type
50
- obj = c.allocate
51
- obj.type = c.sym
52
- obj.instance_eval{ initialize *a, &b }
53
- obj
54
- end
55
- end
56
-
57
- fattr 'type'
58
- fattr 'names'
59
- fattr 'abbreviations'
60
- fattr 'argument'
61
- fattr 'given'
62
- fattr 'cast'
63
- fattr 'validate'
64
- fattr 'description'
65
- fattr 'synopsis'
66
- fattr('values'){ [] }
67
- fattr('defaults'){ [] }
68
- fattr('examples'){ [] }
69
-
70
- fattr 'arity' => 1
71
- fattr 'required' => false
72
-
73
- fattr 'error_handler_before'
74
- fattr 'error_handler_instead'
75
- fattr 'error_handler_after'
76
-
77
- def initialize name, *names, &block
78
- @names = Cast.list_of_string name, *names
79
- @names.map! do |name|
80
- if name =~ %r/^-+/
81
- name.gsub! %r/^-+/, ''
82
- end
83
-
84
- if name =~ %r/=.*$/
85
- argument( name =~ %r/=\s*\[.*$/ ? :optional : :required )
86
- name.gsub! %r/=.*$/, ''
87
- end
88
-
89
- name
90
- end
91
- @names = @names.sort.reverse
92
- @names[1..-1].each do |name|
93
- raise ArgumentError, "only one long name allowed (#{ @names.inspect })" if
94
- name.size > 1
95
- end
96
-
97
- DSL.evaluate(self, &block) if block
98
- sanity_check!
99
- end
100
-
101
- def sanity_check!
102
- raise Arity, "#{ name } with arity -1 (zero or more args) cannot be required" if(arity == -1 and required?)
103
- end
104
-
105
- def name
106
- names.first
107
- end
108
-
109
- def default
110
- defaults.first
111
- end
112
-
113
- def typename
114
- prefix = '--' if type.to_s =~ %r/option/
115
- "#{ type }(#{ prefix }#{ name })"
116
- end
117
-
118
- def add_value value
119
- given true
120
- values << value
121
- end
122
-
123
- def value
124
- values.first
125
- end
126
-
127
- def argument_none?
128
- argument.nil?
129
- end
130
-
131
- def argument_required?
132
- argument and
133
- argument.to_s.downcase.to_sym == :required
134
- end
135
- def argument_optional?
136
- argument and
137
- argument.to_s.downcase.to_sym == :optional
138
- end
139
-
140
- def optional?
141
- not required?
142
- end
143
- def optional= bool
144
- self.required !bool
145
- end
146
-
147
- =begin
148
- def setup!
149
- return false unless given?
150
- adding_handlers do
151
- check_arity
152
- apply_casting
153
- check_validation
154
- end
155
- true
156
- end
157
- =end
158
-
159
- def setup!
160
- adding_handlers do
161
- check_arity
162
- apply_casting
163
- check_validation
164
- end
165
- end
166
-
167
- def check_arity
168
- return true if not given? and optional?
169
-
170
- ex = values.size == 0 ? NotGiven : Arity
171
-
172
- (raise ex, "#{ typename })" if values.size.zero? and argument_required?) unless arity == -1
173
-
174
- if arity >= 0
175
- min = arity
176
- sign = ''
177
- else
178
- min = arity.abs - 1
179
- sign = '-'
180
- end
181
-
182
- arity = min
183
-
184
- =begin
185
- puts
186
- p :values => values
187
- p :arity => arity
188
- p :argument_required => argument_required?
189
- p :argument_none => argument_none?
190
- puts
191
- =end
192
- if values.size < arity
193
- if argument_optional?
194
- raise ex, "#{ typename }) #{ values.size }/#{ sign }#{ arity }" if(values.size < arity and values.size > 0)
195
- elsif argument_required? or argument_none?
196
- raise ex, "#{ typename }) #{ values.size }/#{ sign }#{ arity }" if(values.size < arity)
197
- end
198
- end
199
- end
200
-
201
- def apply_casting
202
- if cast?
203
- op = cast.respond_to?('call') ? cast : Cast[cast]
204
- values.map! do |val|
205
- Parameter.wrap_errors{ op.call val }
206
- end
207
- end
208
- end
209
-
210
- def check_validation
211
- if validate?
212
- values.each do |value|
213
- validate[value] or
214
- raise InValid, "invalid: #{ typename }=#{ value.inspect }"
215
- end
216
- end
217
- end
218
-
219
- def add_handlers e
220
- esc =
221
- class << e
222
- self
223
- end
224
-
225
- this = self
226
-
227
- %w[ before instead after ].each do |which|
228
- getter = "error_handler_#{ which }"
229
- query = "error_handler_#{ which }?"
230
- if send(query)
231
- handler = send getter
232
- esc.module_eval do
233
- define_method(getter) do |main|
234
- main.instance_eval_block self, &handler
235
- end
236
- end
237
- end
238
- end
239
- end
240
-
241
- def adding_handlers
242
- begin
243
- yield
244
- rescue Exception => e
245
- add_handlers e
246
- raise
247
- end
248
- end
249
-
250
- class Argument < Parameter
251
- fattr 'required' => true
252
-
253
- fattr 'synopsis' do
254
- label = name
255
- op = required ? "->" : "~>"
256
- value = defaults.size > 0 ? "#{ name }=#{ defaults.join ',' }" : name
257
- value = "#{ cast }(#{ value })" if(cast and not cast.respond_to?(:call))
258
- "#{ label } (#{ arity } #{ op } #{ value })"
259
- end
260
- end
261
-
262
- class Option < Parameter
263
- fattr 'required' => false
264
- fattr 'arity' => 0
265
-
266
- fattr 'synopsis' do
267
- long, *short = names
268
- value = cast || name
269
- rhs = argument ? (argument == :required ? "=#{ name }" : "=[#{ name }]") : nil
270
- label = ["--#{ long }#{ rhs }", short.map{|s| "-#{ s }"}].flatten.join(", ")
271
- unless argument_none?
272
- op = required ? "->" : "~>"
273
- value = defaults.size > 0 ? "#{ name }=#{ defaults.join ',' }" : name
274
- value = "#{ cast }(#{ value })" if(cast and not cast.respond_to?(:call))
275
- "#{ label } (#{ arity } #{ op } #{ value })"
276
- else
277
- label
278
- end
279
- end
280
- end
281
-
282
- class Keyword < Parameter
283
- fattr 'required' => false
284
- fattr 'argument' => :required
285
-
286
- fattr 'synopsis' do
287
- label = "#{ name }=#{ name }"
288
- op = required ? "->" : "~>"
289
- value = defaults.size > 0 ? "#{ name }=#{ defaults.join ',' }" : name
290
- value = "#{ cast }(#{ value })" if(cast and not cast.respond_to?(:call))
291
- "#{ label } (#{ arity } #{ op } #{ value })"
292
- end
293
- end
294
-
295
- class Environment < Parameter
296
- fattr 'argument' => :required
297
-
298
- fattr 'synopsis' do
299
- label = "env[#{ name }]=#{ name }"
300
- op = required ? "->" : "~>"
301
- value = defaults.size > 0 ? "#{ name }=#{ defaults.join ',' }" : name
302
- value = "#{ cast }(#{ value })" if(cast and not cast.respond_to?(:call))
303
- "#{ label } (#{ arity } #{ op } #{ value })"
304
- end
305
- end
306
-
307
- class List < ::Array
308
- def parse argv, env
309
- ignore, stop = [], argv.index('--')
310
- if stop
311
- ignore = argv[stop .. -1]
312
- (argv.size - stop).times{ argv.pop }
313
- end
314
- parse_options argv
315
- return 'help' if detect{|p| p.name.to_s == 'help' and p.given?}
316
- parse_keywords argv
317
- parse_arguments argv
318
- parse_environment env
319
- defaults!
320
- validate!
321
- argv.push *ignore[1 .. -1] unless ignore.empty?
322
- self
323
- end
324
-
325
- def parse_options argv, params = nil
326
- params ||= options
327
-
328
- spec, h, s = [], {}, {}
329
-
330
- params.each do |p|
331
- head, *tail = p.names
332
- long = "--#{ head }"
333
- shorts = tail.map{|t| "-#{ t }"}
334
- type =
335
- if p.argument_required? then GetoptLong::REQUIRED_ARGUMENT
336
- elsif p.argument_optional? then GetoptLong::OPTIONAL_ARGUMENT
337
- else GetoptLong::NO_ARGUMENT
338
- end
339
- a = [ long, shorts, type ].flatten
340
- spec << a
341
- h[long] = p
342
- s[long] = a
343
- end
344
-
345
- begin
346
- GetoptLong.new(argv, *spec).each do |long, value|
347
- value =
348
- case s[long].last
349
- when GetoptLong::NO_ARGUMENT
350
- value.empty? ? true : value
351
- when GetoptLong::OPTIONAL_ARGUMENT
352
- value.empty? ? true : value
353
- when GetoptLong::REQUIRED_ARGUMENT
354
- value
355
- end
356
- p = h[long]
357
- p.add_value value
358
- end
359
- rescue GetoptLong::AmbigousOption, GetoptLong::NeedlessArgument,
360
- GetoptLong::MissingArgument, GetoptLong::InvalidOption => e
361
- c = Parameter.const_get e.class.name.split(/::/).last
362
- ex = c.new e.message
363
- ex.set_backtrace e.message
364
- ex.extend Softspoken
365
- raise ex
366
- end
367
-
368
- =begin
369
- params.each do |p|
370
- p.setup!
371
- end
372
- =end
373
- end
374
-
375
- def parse_arguments argv, params=nil
376
- params ||= select{|p| p.type == :argument}
377
-
378
- params.each do |p|
379
- if p.arity >= 0
380
- p.arity.times do
381
- break if argv.empty?
382
- value = argv.shift
383
- p.add_value value
384
- end
385
- else
386
- arity = p.arity.abs - 1
387
- arity.times do
388
- break if argv.empty?
389
- value = argv.shift
390
- p.add_value value
391
- end
392
- argv.size.times do
393
- value = argv.shift
394
- p.add_value value
395
- end
396
- end
397
- end
398
-
399
- =begin
400
- params.each do |p|
401
- p.setup!
402
- end
403
- =end
404
- end
405
-
406
- def parse_keywords argv, params=nil
407
- params ||= select{|p| p.type == :keyword}
408
-
409
- replacements = {}
410
-
411
- params.each do |p|
412
- names = p.names
413
- name = names.sort_by{|n| [n.size,n]}.last
414
-
415
- kre = %r/^\s*(#{ names.join '|' })\s*=/
416
- opt = "--#{ name }"
417
- i = -1
418
-
419
- argv.each_with_index do |a, idx|
420
- i += 1
421
- b = argv[idx + 1]
422
- s = "#{ a }#{ b }"
423
- m, key, *ignored = kre.match(s).to_a
424
- if m
425
- replacements[i] ||= a.gsub %r/^\s*#{ key }/, opt
426
- next
427
- end
428
- =begin
429
- abbrev = name.index(key) == 0
430
- if abbrev
431
- replacements[i] ||= a.gsub %r/^\s*#{ key }/, opt
432
- end
433
- =end
434
- end
435
- end
436
-
437
- replacements.each do |i, r|
438
- argv[i] = r
439
- end
440
-
441
- parse_options argv, params
442
- end
443
-
444
- def parse_environment env, params=nil
445
- params ||= select{|p| p.type == :environment}
446
-
447
- params.each do |p|
448
- names = p.names
449
- name = names.first
450
- value = env[name]
451
- next unless value
452
- p.add_value value
453
- end
454
-
455
- =begin
456
- params.each do |p|
457
- p.setup!
458
- end
459
- =end
460
- end
461
-
462
- def defaults!
463
- each do |p|
464
- if(p.defaults? and (not p.given?))
465
- p.defaults.each do |default|
466
- p.values << default # so as NOT to set 'given?'
467
- end
468
- end
469
- end
470
- end
471
-
472
- def validate!
473
- each do |p|
474
- #p.adding_handlers do
475
- #next if p.arity == -1
476
- #raise NotGiven, "#{ p.typename } not given" if(p.required? and (not p.given?))
477
- #end
478
- p.setup!
479
- end
480
- end
481
-
482
- [:parameter, :option, :argument, :keyword, :environment].each do |m|
483
- define_method("#{ m }s"){ select{|p| p.type == m or m == :parameter} }
484
-
485
- define_method("has_#{ m }?") do |name, *names|
486
- catch :has do
487
- names = Cast.list_of_string name, *names
488
- send("#{ m }s").each do |param|
489
- common = Cast.list_of_string(param.names) & names
490
- throw :has, true unless common.empty?
491
- end
492
- false
493
- end
494
- end
495
- end
496
-
497
- def delete name, *names
498
- name, *names = name.names if Parameter === name
499
- names = Cast.list_of_string name, *names
500
- keep = []
501
- each do |param|
502
- common = Cast.list_of_string(param.names) & names
503
- keep << param if common.empty?
504
- end
505
- replace keep
506
- end
507
-
508
- def << *a
509
- delete *a
510
- super
511
- end
512
- end
513
-
514
- class DSL
515
- def self.evaluate param, &block
516
- new(param).evaluate(&block)
517
- end
518
-
519
- attr 'param'
520
- alias_method 'evaluate', 'instance_eval'
521
-
522
- def initialize param
523
- @param = param
524
- end
525
-
526
- def fattr a = nil, &block
527
- name = param.name
528
- a ||= name
529
- b = fattr_block_for name, &block
530
- Main.current.module_eval{ fattr *a, &b }
531
- end
532
- alias_method 'attribute', 'fattr'
533
-
534
- def fattr_block_for name, &block
535
- block ||= lambda{|param| [0,1].include?(param.arity) ? param.value : param.values }
536
- lambda{ block.call self.param[name] }
537
- end
538
-
539
- def attr *a, &b
540
- fattr *a, &b
541
- end
542
-
543
- def example *list
544
- list.flatten.compact.each do |elem|
545
- param.examples << elem.to_s
546
- end
547
- end
548
- alias_method "examples", "example"
549
-
550
-
551
- def type *sym
552
- sym.size == 0 ? param.type : (param.type = sym.first)
553
- end
554
- def type?
555
- param.type?
556
- end
557
-
558
- def synopsis *arg
559
- arg.size == 0 ? param.synopsis : (param.synopsis arg.first)
560
- end
561
-
562
- def argument arg
563
- param.argument arg
564
- end
565
- def argument_required bool = true
566
- if bool
567
- param.argument :required
568
- else
569
- param.argument false
570
- end
571
- end
572
- def argument_required?
573
- param.argument_required?
574
- end
575
-
576
- def argument_optional bool = true
577
- if bool
578
- param.argument :optional
579
- else
580
- param.argument false
581
- end
582
- end
583
- def argument_optional?
584
- param.argument_optional?
585
- end
586
-
587
- def required bool = true
588
- param.required = bool
589
- end
590
- def required?
591
- param.required?
592
- end
593
-
594
- def optional bool = true
595
- if bool
596
- param.required !bool
597
- else
598
- param.required bool
599
- end
600
- end
601
- def optional?
602
- param.optional?
603
- end
604
-
605
- def cast sym=nil, &b
606
- param.cast = sym || b
607
- end
608
- def cast?
609
- param.cast?
610
- end
611
-
612
- def validate sym=nil, &b
613
- param.validate = sym || b
614
- end
615
- def validate?
616
- param.validate?
617
- end
618
-
619
- def description s
620
- param.description = s.to_s
621
- end
622
- def description?
623
- param.description?
624
- end
625
- alias_method 'desc', 'description'
626
-
627
- def default value, *values
628
- param.defaults.push value
629
- param.defaults.push *values
630
- param.defaults
631
- end
632
- def defaults?
633
- param.defaults?
634
- end
635
- def defaults value, *values
636
- param.defaults.push value
637
- param.defaults.push *values
638
- param.defaults
639
- end
640
- def defaults?
641
- param.defaults?
642
- end
643
-
644
- def arity value
645
- raise Arity if value.nil?
646
- value = -1 if value.to_s == '*'
647
- value = Integer value
648
- raise Arity if value.zero?
649
- param.arity = value
650
- if param.arity == -1
651
- optional true
652
- end
653
- value
654
- end
655
- def arity?
656
- param.arity?
657
- end
658
-
659
- def error which = :instead, &block
660
- param.send "error_handler_#{ which }=", block
661
- end
662
- end
663
-
664
- class Table < ::Array
665
- def initialize
666
- super()
667
- self.fields = []
668
- extend BoundsCheck
669
- end
670
-
671
- def to_options
672
- (hash = self.to_hash ).keys.each { |key| hash[key] = hash[key].value }
673
- return hash
674
- end
675
-
676
- module BoundsCheck
677
- def [] *a, &b
678
- p = super
679
- ensure
680
- raise NoneSuch, a.join(',') unless p
681
- end
682
- end
683
- end
684
- end
685
- end
1
+ module Main
2
+ class Parameter
3
+ class Error < StandardError
4
+ include Softspoken
5
+ fattr 'wrapped'
6
+ end
7
+ class Arity < Error; end
8
+ class NotGiven < Arity; end
9
+ class InValid < Error; end
10
+ class NoneSuch < Error; end
11
+ class AmbigousOption < Error; end
12
+ class NeedlessArgument < Error; end
13
+ class MissingArgument < Error; end
14
+ class InvalidOption < Error; end
15
+
16
+ class << self
17
+ def wrapped_error w
18
+ e = Error.new "(#{ w.message } (#{ w.class }))"
19
+ e.wrapped = w
20
+ e.set_backtrace(w.backtrace || [])
21
+ e
22
+ end
23
+
24
+ def wrap_errors
25
+ begin
26
+ yield
27
+ rescue => e
28
+ raise wrapped_error(e)
29
+ end
30
+ end
31
+
32
+ Types = [ Parameter ]
33
+ def inherited other
34
+ Types << other
35
+ end
36
+
37
+ def sym
38
+ @sym ||= name.split(%r/::/).last.downcase.to_sym
39
+ end
40
+
41
+ def class_for type
42
+ sym = type.to_s.downcase.to_sym
43
+ c = Types.detect{|t| t.sym == sym}
44
+ raise ArgumentError, type.inspect unless c
45
+ c
46
+ end
47
+
48
+ def create type, *a, &b
49
+ c = class_for type
50
+ obj = c.allocate
51
+ obj.type = c.sym
52
+ obj.instance_eval{ initialize *a, &b }
53
+ obj
54
+ end
55
+ end
56
+
57
+ fattr 'type'
58
+ fattr 'names'
59
+ fattr 'abbreviations'
60
+ fattr 'argument'
61
+ fattr 'given'
62
+ fattr 'cast'
63
+ fattr 'validate'
64
+ fattr 'description'
65
+ fattr 'synopsis'
66
+ fattr('values'){ [] }
67
+ fattr('defaults'){ [] }
68
+ fattr('examples'){ [] }
69
+
70
+ fattr 'arity' => 1
71
+ fattr 'required' => false
72
+
73
+ fattr 'error_handler_before'
74
+ fattr 'error_handler_instead'
75
+ fattr 'error_handler_after'
76
+
77
+ def initialize name, *names, &block
78
+ @names = Cast.list_of_string name, *names
79
+ @names.map! do |name|
80
+ if name =~ %r/^-+/
81
+ name.gsub! %r/^-+/, ''
82
+ end
83
+
84
+ if name =~ %r/=.*$/
85
+ argument( name =~ %r/=\s*\[.*$/ ? :optional : :required )
86
+ name.gsub! %r/=.*$/, ''
87
+ end
88
+
89
+ name
90
+ end
91
+ @names = @names.sort.reverse
92
+ @names[1..-1].each do |name|
93
+ raise ArgumentError, "only one long name allowed (#{ @names.inspect })" if
94
+ name.size > 1
95
+ end
96
+
97
+ DSL.evaluate(self, &block) if block
98
+ sanity_check!
99
+ end
100
+
101
+ def sanity_check!
102
+ raise Arity, "#{ name } with arity -1 (zero or more args) cannot be required" if(arity == -1 and required?)
103
+ end
104
+
105
+ def name
106
+ names.first
107
+ end
108
+
109
+ def default
110
+ defaults.first
111
+ end
112
+
113
+ def typename
114
+ prefix = '--' if type.to_s =~ %r/option/
115
+ "#{ type }(#{ prefix }#{ name })"
116
+ end
117
+
118
+ def add_value value
119
+ given true
120
+ values << value
121
+ end
122
+
123
+ def value
124
+ values.first
125
+ end
126
+
127
+ def argument_none?
128
+ argument.nil?
129
+ end
130
+
131
+ def argument_required?
132
+ argument and
133
+ argument.to_s.downcase.to_sym == :required
134
+ end
135
+ def argument_optional?
136
+ argument and
137
+ argument.to_s.downcase.to_sym == :optional
138
+ end
139
+
140
+ def optional?
141
+ not required?
142
+ end
143
+ def optional= bool
144
+ self.required !bool
145
+ end
146
+
147
+ =begin
148
+ def setup!
149
+ return false unless given?
150
+ adding_handlers do
151
+ check_arity
152
+ apply_casting
153
+ check_validation
154
+ end
155
+ true
156
+ end
157
+ =end
158
+
159
+ def setup!
160
+ adding_handlers do
161
+ check_arity
162
+ apply_casting
163
+ check_validation
164
+ end
165
+ end
166
+
167
+ def check_arity
168
+ return true if not given? and optional?
169
+
170
+ ex = values.size == 0 ? NotGiven : Arity
171
+
172
+ (raise ex, "#{ typename })" if values.size.zero? and argument_required?) unless arity == -1
173
+
174
+ if arity >= 0
175
+ min = arity
176
+ sign = ''
177
+ else
178
+ min = arity.abs - 1
179
+ sign = '-'
180
+ end
181
+
182
+ arity = min
183
+
184
+ =begin
185
+ puts
186
+ p :values => values
187
+ p :arity => arity
188
+ p :argument_required => argument_required?
189
+ p :argument_none => argument_none?
190
+ puts
191
+ =end
192
+ if values.size < arity
193
+ if argument_optional?
194
+ raise ex, "#{ typename }) #{ values.size }/#{ sign }#{ arity }" if(values.size < arity and values.size > 0)
195
+ elsif argument_required? or argument_none?
196
+ raise ex, "#{ typename }) #{ values.size }/#{ sign }#{ arity }" if(values.size < arity)
197
+ end
198
+ end
199
+ end
200
+
201
+ def apply_casting
202
+ if cast?
203
+ op = cast.respond_to?('call') ? cast : Cast[cast]
204
+ values.map! do |val|
205
+ Parameter.wrap_errors{ op.call val }
206
+ end
207
+ end
208
+ end
209
+
210
+ def check_validation
211
+ if validate?
212
+ values.each do |value|
213
+ validate[value] or
214
+ raise InValid, "invalid: #{ typename }=#{ value.inspect }"
215
+ end
216
+ end
217
+ end
218
+
219
+ def add_handlers e
220
+ esc =
221
+ class << e
222
+ self
223
+ end
224
+
225
+ this = self
226
+
227
+ %w[ before instead after ].each do |which|
228
+ getter = "error_handler_#{ which }"
229
+ query = "error_handler_#{ which }?"
230
+ if send(query)
231
+ handler = send getter
232
+ esc.module_eval do
233
+ define_method(getter) do |main|
234
+ main.instance_eval_block self, &handler
235
+ end
236
+ end
237
+ end
238
+ end
239
+ end
240
+
241
+ def adding_handlers
242
+ begin
243
+ yield
244
+ rescue Exception => e
245
+ add_handlers e
246
+ raise
247
+ end
248
+ end
249
+
250
+ class Argument < Parameter
251
+ fattr 'required' => true
252
+
253
+ fattr 'synopsis' do
254
+ label = name
255
+ op = required ? "->" : "~>"
256
+ value = defaults.size > 0 ? "#{ name }=#{ defaults.join ',' }" : name
257
+ value = "#{ cast }(#{ value })" if(cast and not cast.respond_to?(:call))
258
+ "#{ label } (#{ arity } #{ op } #{ value })"
259
+ end
260
+ end
261
+
262
+ class Option < Parameter
263
+ fattr 'required' => false
264
+ fattr 'arity' => 0
265
+
266
+ fattr 'synopsis' do
267
+ long, *short = names
268
+ value = cast || name
269
+ rhs = argument ? (argument == :required ? "=#{ name }" : "=[#{ name }]") : nil
270
+ label = ["--#{ long }#{ rhs }", short.map{|s| "-#{ s }"}].flatten.join(", ")
271
+ unless argument_none?
272
+ op = required ? "->" : "~>"
273
+ value = defaults.size > 0 ? "#{ name }=#{ defaults.join ',' }" : name
274
+ value = "#{ cast }(#{ value })" if(cast and not cast.respond_to?(:call))
275
+ "#{ label } (#{ arity } #{ op } #{ value })"
276
+ else
277
+ label
278
+ end
279
+ end
280
+ end
281
+
282
+ class Keyword < Parameter
283
+ fattr 'required' => false
284
+ fattr 'argument' => :required
285
+
286
+ fattr 'synopsis' do
287
+ label = "#{ name }=#{ name }"
288
+ op = required ? "->" : "~>"
289
+ value = defaults.size > 0 ? "#{ name }=#{ defaults.join ',' }" : name
290
+ value = "#{ cast }(#{ value })" if(cast and not cast.respond_to?(:call))
291
+ "#{ label } (#{ arity } #{ op } #{ value })"
292
+ end
293
+ end
294
+
295
+ class Environment < Parameter
296
+ fattr 'argument' => :required
297
+
298
+ fattr 'synopsis' do
299
+ label = "env[#{ name }]=#{ name }"
300
+ op = required ? "->" : "~>"
301
+ value = defaults.size > 0 ? "#{ name }=#{ defaults.join ',' }" : name
302
+ value = "#{ cast }(#{ value })" if(cast and not cast.respond_to?(:call))
303
+ "#{ label } (#{ arity } #{ op } #{ value })"
304
+ end
305
+ end
306
+
307
+ class List < ::Array
308
+ def parse argv, env
309
+ ignore, stop = [], argv.index('--')
310
+ if stop
311
+ ignore = argv[stop .. -1]
312
+ (argv.size - stop).times{ argv.pop }
313
+ end
314
+ parse_options argv
315
+ return 'help' if detect{|p| p.name.to_s == 'help' and p.given?}
316
+ parse_keywords argv
317
+ parse_arguments argv
318
+ parse_environment env
319
+ defaults!
320
+ validate!
321
+ argv.push *ignore[1 .. -1] unless ignore.empty?
322
+ self
323
+ end
324
+
325
+ def parse_options argv, params = nil
326
+ params ||= options
327
+
328
+ spec, h, s = [], {}, {}
329
+
330
+ params.each do |p|
331
+ head, *tail = p.names
332
+ long = "--#{ head }"
333
+ shorts = tail.map{|t| "-#{ t }"}
334
+ type =
335
+ if p.argument_required? then GetoptLong::REQUIRED_ARGUMENT
336
+ elsif p.argument_optional? then GetoptLong::OPTIONAL_ARGUMENT
337
+ else GetoptLong::NO_ARGUMENT
338
+ end
339
+ a = [ long, shorts, type ].flatten
340
+ spec << a
341
+ h[long] = p
342
+ s[long] = a
343
+ end
344
+
345
+ begin
346
+ GetoptLong.new(argv, *spec).each do |long, value|
347
+ value =
348
+ case s[long].last
349
+ when GetoptLong::NO_ARGUMENT
350
+ value.empty? ? true : value
351
+ when GetoptLong::OPTIONAL_ARGUMENT
352
+ value.empty? ? true : value
353
+ when GetoptLong::REQUIRED_ARGUMENT
354
+ value
355
+ end
356
+ p = h[long]
357
+ p.add_value value
358
+ end
359
+ rescue GetoptLong::AmbigousOption, GetoptLong::NeedlessArgument,
360
+ GetoptLong::MissingArgument, GetoptLong::InvalidOption => e
361
+ c = Parameter.const_get e.class.name.split(/::/).last
362
+ ex = c.new e.message
363
+ ex.set_backtrace e.message
364
+ ex.extend Softspoken
365
+ raise ex
366
+ end
367
+
368
+ =begin
369
+ params.each do |p|
370
+ p.setup!
371
+ end
372
+ =end
373
+ end
374
+
375
+ def parse_arguments argv, params=nil
376
+ params ||= select{|p| p.type == :argument}
377
+
378
+ params.each do |p|
379
+ if p.arity >= 0
380
+ p.arity.times do
381
+ break if argv.empty?
382
+ value = argv.shift
383
+ p.add_value value
384
+ end
385
+ else
386
+ arity = p.arity.abs - 1
387
+ arity.times do
388
+ break if argv.empty?
389
+ value = argv.shift
390
+ p.add_value value
391
+ end
392
+ argv.size.times do
393
+ value = argv.shift
394
+ p.add_value value
395
+ end
396
+ end
397
+ end
398
+
399
+ =begin
400
+ params.each do |p|
401
+ p.setup!
402
+ end
403
+ =end
404
+ end
405
+
406
+ def parse_keywords argv, params=nil
407
+ params ||= select{|p| p.type == :keyword}
408
+
409
+ replacements = {}
410
+
411
+ params.each do |p|
412
+ names = p.names
413
+ name = names.sort_by{|n| [n.size,n]}.last
414
+
415
+ kre = %r/^\s*(#{ names.join '|' })\s*=/
416
+ opt = "--#{ name }"
417
+ i = -1
418
+
419
+ argv.each_with_index do |a, idx|
420
+ i += 1
421
+ b = argv[idx + 1]
422
+ s = "#{ a }#{ b }"
423
+ m, key, *ignored = kre.match(s).to_a
424
+ if m
425
+ replacements[i] ||= a.gsub %r/^\s*#{ key }/, opt
426
+ next
427
+ end
428
+ =begin
429
+ abbrev = name.index(key) == 0
430
+ if abbrev
431
+ replacements[i] ||= a.gsub %r/^\s*#{ key }/, opt
432
+ end
433
+ =end
434
+ end
435
+ end
436
+
437
+ replacements.each do |i, r|
438
+ argv[i] = r
439
+ end
440
+
441
+ parse_options argv, params
442
+ end
443
+
444
+ def parse_environment env, params=nil
445
+ params ||= select{|p| p.type == :environment}
446
+
447
+ params.each do |p|
448
+ names = p.names
449
+ name = names.first
450
+ value = env[name]
451
+ next unless value
452
+ p.add_value value
453
+ end
454
+
455
+ =begin
456
+ params.each do |p|
457
+ p.setup!
458
+ end
459
+ =end
460
+ end
461
+
462
+ def defaults!
463
+ each do |p|
464
+ if(p.defaults? and (not p.given?))
465
+ p.defaults.each do |default|
466
+ p.values << default # so as NOT to set 'given?'
467
+ end
468
+ end
469
+ end
470
+ end
471
+
472
+ def validate!
473
+ each do |p|
474
+ #p.adding_handlers do
475
+ #next if p.arity == -1
476
+ #raise NotGiven, "#{ p.typename } not given" if(p.required? and (not p.given?))
477
+ #end
478
+ p.setup!
479
+ end
480
+ end
481
+
482
+ [:parameter, :option, :argument, :keyword, :environment].each do |m|
483
+ define_method("#{ m }s"){ select{|p| p.type == m or m == :parameter} }
484
+
485
+ define_method("has_#{ m }?") do |name, *names|
486
+ catch :has do
487
+ names = Cast.list_of_string name, *names
488
+ send("#{ m }s").each do |param|
489
+ common = Cast.list_of_string(param.names) & names
490
+ throw :has, true unless common.empty?
491
+ end
492
+ false
493
+ end
494
+ end
495
+ end
496
+
497
+ def delete name, *names
498
+ name, *names = name.names if Parameter === name
499
+ names = Cast.list_of_string name, *names
500
+ keep = []
501
+ each do |param|
502
+ common = Cast.list_of_string(param.names) & names
503
+ keep << param if common.empty?
504
+ end
505
+ replace keep
506
+ end
507
+
508
+ def << *a
509
+ delete *a
510
+ super
511
+ end
512
+ end
513
+
514
+ class DSL
515
+ def self.evaluate param, &block
516
+ new(param).evaluate(&block)
517
+ end
518
+
519
+ attr 'param'
520
+ alias_method 'evaluate', 'instance_eval'
521
+
522
+ def initialize param
523
+ @param = param
524
+ end
525
+
526
+ def fattr a = nil, &block
527
+ name = param.name
528
+ a ||= name
529
+ b = fattr_block_for name, &block
530
+ Main.current.module_eval{ fattr *a, &b }
531
+ end
532
+ alias_method 'attribute', 'fattr'
533
+
534
+ def fattr_block_for name, &block
535
+ block ||= lambda{|param| [0,1].include?(param.arity) ? param.value : param.values }
536
+ lambda{ block.call self.param[name] }
537
+ end
538
+
539
+ def attr *a, &b
540
+ fattr *a, &b
541
+ end
542
+
543
+ def example *list
544
+ list.flatten.compact.each do |elem|
545
+ param.examples << elem.to_s
546
+ end
547
+ end
548
+ alias_method "examples", "example"
549
+
550
+
551
+ def type *sym
552
+ sym.size == 0 ? param.type : (param.type = sym.first)
553
+ end
554
+ def type?
555
+ param.type?
556
+ end
557
+
558
+ def synopsis *arg
559
+ arg.size == 0 ? param.synopsis : (param.synopsis arg.first)
560
+ end
561
+
562
+ def argument arg
563
+ param.argument arg
564
+ end
565
+ def argument_required bool = true
566
+ if bool
567
+ param.argument :required
568
+ else
569
+ param.argument false
570
+ end
571
+ end
572
+ def argument_required?
573
+ param.argument_required?
574
+ end
575
+
576
+ def argument_optional bool = true
577
+ if bool
578
+ param.argument :optional
579
+ else
580
+ param.argument false
581
+ end
582
+ end
583
+ def argument_optional?
584
+ param.argument_optional?
585
+ end
586
+
587
+ def required bool = true
588
+ param.required = bool
589
+ end
590
+ def required?
591
+ param.required?
592
+ end
593
+
594
+ def optional bool = true
595
+ if bool
596
+ param.required !bool
597
+ else
598
+ param.required bool
599
+ end
600
+ end
601
+ def optional?
602
+ param.optional?
603
+ end
604
+
605
+ def cast sym=nil, &b
606
+ param.cast = sym || b
607
+ end
608
+ def cast?
609
+ param.cast?
610
+ end
611
+
612
+ def validate sym=nil, &b
613
+ param.validate = sym || b
614
+ end
615
+ def validate?
616
+ param.validate?
617
+ end
618
+
619
+ def description s
620
+ param.description = s.to_s
621
+ end
622
+ def description?
623
+ param.description?
624
+ end
625
+ alias_method 'desc', 'description'
626
+
627
+ def default value, *values
628
+ param.defaults.push value
629
+ param.defaults.push *values
630
+ param.defaults
631
+ end
632
+ def defaults?
633
+ param.defaults?
634
+ end
635
+ def defaults value, *values
636
+ param.defaults.push value
637
+ param.defaults.push *values
638
+ param.defaults
639
+ end
640
+ def defaults?
641
+ param.defaults?
642
+ end
643
+
644
+ def arity value
645
+ raise Arity if value.nil?
646
+ value = -1 if value.to_s == '*'
647
+ value = Integer value
648
+ raise Arity if value.zero?
649
+ param.arity = value
650
+ if param.arity == -1
651
+ optional true
652
+ end
653
+ value
654
+ end
655
+ def arity?
656
+ param.arity?
657
+ end
658
+
659
+ def error which = :instead, &block
660
+ param.send "error_handler_#{ which }=", block
661
+ end
662
+ end
663
+
664
+ class Table < ::Array
665
+ def initialize
666
+ super()
667
+ self.fields = []
668
+ extend BoundsCheck
669
+ end
670
+
671
+ def to_options
672
+ (hash = self.to_hash ).keys.each { |key| hash[key] = hash[key].value }
673
+ return hash
674
+ end
675
+
676
+ module BoundsCheck
677
+ def [] *a, &b
678
+ p = super
679
+ ensure
680
+ raise NoneSuch, a.join(',') unless p
681
+ end
682
+ end
683
+ end
684
+ end
685
+ end