main 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,496 @@
1
+ module Main
2
+ class Parameter
3
+ class Error < StandardError; attribute 'wrapped'; end
4
+ class NotGiven < Error; end
5
+ class Arity < Error; end
6
+ class InValid < Error; end
7
+ class NoneSuch < Error; end
8
+ class AmbigousOption < Error; end
9
+ class NeedlessArgument < Error; end
10
+ class MissingArgument < Error; end
11
+ class InvalidOption < Error; end
12
+
13
+ class << self
14
+ def new *a, &b
15
+ raise
16
+ end
17
+
18
+ def wrapped_error w
19
+ e = Error.new "(#{ w.message } (#{ w.class }))"
20
+ e.wrapped = w
21
+ e.set_backtrace(w.backtrace || [])
22
+ e
23
+ end
24
+
25
+ def wrap_errors
26
+ begin
27
+ yield
28
+ rescue => e
29
+ raise wrapped_error(e)
30
+ end
31
+ end
32
+
33
+ Types = []
34
+ def inherited other
35
+ Types << other
36
+ end
37
+
38
+ def sym
39
+ @sym ||= name.split(%r/::/).last.downcase.to_sym
40
+ end
41
+
42
+ def class_for type
43
+ sym = type.to_s.downcase.to_sym
44
+ c = Types.detect{|t| t.sym == sym}
45
+ raise ArgumentError, type.inspect unless c
46
+ c
47
+ end
48
+
49
+ def create type, *a, &b
50
+ c = class_for type
51
+ obj = c.allocate
52
+ obj.type = c.sym
53
+ obj.instance_eval{ initialize *a, &b }
54
+ obj
55
+ end
56
+ end
57
+
58
+ attribute 'type'
59
+ attribute 'names'
60
+ attribute 'abbreviations'
61
+ attribute 'argument'
62
+ attribute 'given'
63
+ attribute 'cast'
64
+ attribute 'validate'
65
+ attribute 'description'
66
+ attribute 'synopsis'
67
+ attribute('values'){ [] }
68
+ attribute('defaults'){ [] }
69
+
70
+ attribute 'arity' => 1
71
+ attribute 'required' => false
72
+
73
+ def initialize name, *names, &block
74
+ @names = Cast.list_of_string name, *names
75
+ @names.map! do |name|
76
+ if name =~ %r/^-+/
77
+ name.gsub! %r/^-+/, ''
78
+ end
79
+
80
+ if name =~ %r/=.*$/
81
+ argument( name =~ %r/=\s*\[.*$/ ? :optional : :required )
82
+ name.gsub! %r/=.*$/, ''
83
+ end
84
+
85
+ name
86
+ end
87
+ @names = @names.sort.reverse
88
+ @names[1..-1].each do |name|
89
+ raise ArgumentError, "only one long name allowed (#{ @names.inspect })" if
90
+ name.size > 1
91
+ end
92
+
93
+ DSL.evaluate(self, &block) if block
94
+ end
95
+
96
+ def name
97
+ names.first
98
+ end
99
+
100
+ def default
101
+ defaults.first
102
+ end
103
+
104
+ def typename
105
+ prefix = '--' if type.to_s =~ %r/option/
106
+ "#{ type }(#{ prefix }#{ name })"
107
+ end
108
+
109
+ def add_value value
110
+ given true
111
+ values << value
112
+ end
113
+
114
+ def value
115
+ values.first
116
+ end
117
+
118
+ def argument_none?
119
+ argument.nil?
120
+ end
121
+
122
+ def argument_required?
123
+ argument and
124
+ argument.to_s.downcase.to_sym == :required
125
+ end
126
+ def argument_optional?
127
+ argument and
128
+ argument.to_s.downcase.to_sym == :optional
129
+ end
130
+
131
+ def optional?
132
+ not required?
133
+ end
134
+ def optional= bool
135
+ self.required !bool
136
+ end
137
+
138
+ def setup!
139
+ return false unless given?
140
+ validate_arity!
141
+ cast!
142
+ validate!
143
+ true
144
+ end
145
+
146
+ def validate_arity!
147
+ raise Arity, "#{ typename })" if values.size.zero? and argument_required?
148
+ if values.size < arity
149
+ if argument_required?
150
+ raise Arity, "#{ typename }) #{ values.size }/#{ arity }" if(values.size < arity)
151
+ elsif argument_optional?
152
+ raise Arity, "#{ typename }) #{ values.size }/#{ arity }" if(values.size < arity and values.size > 0)
153
+ end
154
+ end
155
+ end
156
+
157
+ def validate!
158
+ if validate?
159
+ values.each do |value|
160
+ validate[value] or
161
+ raise InValid, "#{ typename }=#{ value.inspect }"
162
+ end
163
+ end
164
+ end
165
+
166
+ def cast!
167
+ if cast?
168
+ op = cast.respond_to?('call') ? cast : Cast[cast]
169
+ values.map! do |val|
170
+ Parameter.wrap_errors{ op.call val }
171
+ end
172
+ end
173
+ end
174
+
175
+ class Argument < Parameter
176
+ attribute 'required' => true
177
+
178
+ attribute 'synopsis' do
179
+ label = name
180
+ op = required ? "->" : "~>"
181
+ value = defaults.size > 0 ? "#{ name }=#{ defaults.join ',' }" : name
182
+ value = "#{ cast }(#{ value })" if cast
183
+ "#{ label } [ #{ arity } #{ op } #{ value } ]"
184
+ end
185
+ end
186
+
187
+ class Option < Parameter
188
+ attribute 'required' => false
189
+
190
+ attribute 'synopsis' do
191
+ long, *short = names
192
+ value = cast || name
193
+ rhs = argument ? (argument == :required ? "=#{ name }" : "=[#{ name }]") : nil
194
+ label = ["--#{ long }#{ rhs }", short.map{|s| "-#{ s }"}].flatten.join(", ")
195
+ unless argument_none?
196
+ op = required ? "->" : "~>"
197
+ value = defaults.size > 0 ? "#{ name }=#{ defaults.join ',' }" : name
198
+ value = "#{ cast }(#{ value })" if cast
199
+ "#{ label } [ #{ arity } #{ op } #{ value } ]"
200
+ else
201
+ label
202
+ end
203
+ end
204
+ end
205
+
206
+ class Keyword < Parameter
207
+ attribute 'required' => false
208
+ attribute 'argument' => :required
209
+
210
+ attribute 'synopsis' do
211
+ label = "#{ name }=#{ name }"
212
+ op = required ? "->" : "~>"
213
+ value = defaults.size > 0 ? "#{ name }=#{ defaults.join ',' }" : name
214
+ value = "#{ cast }(#{ value })" if cast
215
+ "#{ label } [ #{ arity } #{ op } #{ value } ]"
216
+ end
217
+ end
218
+
219
+ class Environment < Parameter
220
+ attribute 'argument' => :required
221
+
222
+ attribute 'synopsis' do
223
+ label = "env[#{ name }]=#{ name }"
224
+ op = required ? "->" : "~>"
225
+ value = defaults.size > 0 ? "#{ name }=#{ defaults.join ',' }" : name
226
+ value = "#{ cast }(#{ value })" if cast
227
+ "#{ label } [ #{ arity } #{ op } #{ value } ]"
228
+ end
229
+ end
230
+
231
+ class List < ::Array
232
+ def parse argv, env
233
+ parse_options argv
234
+ return 'help' if detect{|p| p.name.to_s == 'help' and p.given?}
235
+ parse_keywords argv
236
+ parse_arguments argv
237
+ parse_environment env
238
+ defaults!
239
+ validate!
240
+ self
241
+ end
242
+
243
+ def parse_options argv, params = nil
244
+ params ||= select{|p| p.type == :option}
245
+
246
+ spec, h, s = [], {}, {}
247
+
248
+ params.each do |p|
249
+ head, *tail = p.names
250
+ long = "--#{ head }"
251
+ shorts = tail.map{|t| "-#{ t }"}
252
+ type =
253
+ if p.argument_required? then GetoptLong::REQUIRED_ARGUMENT
254
+ elsif p.argument_optional? then GetoptLong::OPTIONAL_ARGUMENT
255
+ else GetoptLong::NO_ARGUMENT
256
+ end
257
+ a = [ long, shorts, type ].flatten
258
+ spec << a
259
+ h[long] = p
260
+ s[long] = a
261
+ end
262
+
263
+ begin
264
+ GetoptLong.new(argv, *spec).each do |long, value|
265
+ value =
266
+ case s[long].last
267
+ when GetoptLong::NO_ARGUMENT
268
+ value.empty? ? true : value
269
+ when GetoptLong::OPTIONAL_ARGUMENT
270
+ value.empty? ? true : value
271
+ when GetoptLong::REQUIRED_ARGUMENT
272
+ value
273
+ end
274
+ p = h[long]
275
+ p.add_value value
276
+ end
277
+ rescue GetoptLong::AmbigousOption, GetoptLong::NeedlessArgument,
278
+ GetoptLong::MissingArgument, GetoptLong::InvalidOption => e
279
+ c = Parameter.const_get e.class.name.split(/::/).last
280
+ ex = c.new e.message
281
+ ex.set_backtrace e.message
282
+ raise ex
283
+ end
284
+
285
+ params.each do |p|
286
+ p.setup!
287
+ end
288
+ end
289
+
290
+ def parse_arguments argv, params=nil
291
+ params ||= select{|p| p.type == :argument}
292
+
293
+ params.each do |p|
294
+ p.arity.times do
295
+ break if argv.empty?
296
+ value = argv.shift
297
+ p.add_value value
298
+ end
299
+ end
300
+
301
+ params.each do |p|
302
+ p.setup!
303
+ end
304
+ end
305
+
306
+ def parse_keywords argv, params=nil
307
+ params ||= select{|p| p.type == :keyword}
308
+
309
+ replacements = {}
310
+
311
+ params.each do |p|
312
+ names = p.names
313
+ name = names.first
314
+
315
+ kre = %r/^\s*(#{ names.join '|' })\s*=/
316
+ opt = "--#{ name }"
317
+ i = 0
318
+
319
+ argv.each_with_index do |a, idx|
320
+ b = argv[idx + 1]
321
+ m, key, *ignored = kre.match("#{ a }#{ b }").to_a
322
+ if m
323
+ replacements[i] ||= a.gsub %r/^\s*#{ key }/, opt
324
+ end
325
+ i += 1
326
+ end
327
+ end
328
+
329
+ replacements.each do |i, r|
330
+ argv[i] = r
331
+ end
332
+
333
+ parse_options argv, params
334
+ end
335
+
336
+ def parse_environment env, params=nil
337
+ params ||= select{|p| p.type == :environment}
338
+
339
+ params.each do |p|
340
+ names = p.names
341
+ name = names.first
342
+ value = env[name]
343
+ next unless value
344
+ p.add_value value
345
+ end
346
+
347
+ params.each do |p|
348
+ p.setup!
349
+ end
350
+ end
351
+
352
+ def defaults!
353
+ each do |p|
354
+ #p.add_value p.default if(p.default? and (not p.given?))
355
+ if(p.defaults? and (not p.given?))
356
+ p.defaults.each do |default|
357
+ p.add_value default
358
+ end
359
+ end
360
+ end
361
+ end
362
+
363
+ def validate!
364
+ each do |p|
365
+ raise NotGiven, p.typename if(p.required? and (not p.given?))
366
+ end
367
+ end
368
+ end
369
+
370
+ class DSL
371
+ def self.evaluate param, &block
372
+ new(param).evaluate(&block)
373
+ end
374
+ attr 'p'
375
+ alias_method 'evaluate', 'instance_eval'
376
+ def initialize param
377
+ @p = param
378
+ end
379
+
380
+ def type sym
381
+ p.type = sym
382
+ end
383
+ def type?
384
+ p.type?
385
+ end
386
+
387
+ def synopsis arg
388
+ p.synopsis arg
389
+ end
390
+
391
+ def argument arg
392
+ p.argument arg
393
+ end
394
+ def argument_required bool = true
395
+ if bool
396
+ p.argument :required
397
+ else
398
+ p.argument false
399
+ end
400
+ end
401
+ def argument_required?
402
+ p.argument_required?
403
+ end
404
+
405
+ def argument_optional bool = true
406
+ if bool
407
+ p.argument :optional
408
+ else
409
+ p.argument false
410
+ end
411
+ end
412
+ def argument_optional?
413
+ p.argument_optional?
414
+ end
415
+
416
+ def required bool = true
417
+ p.required = bool
418
+ end
419
+ def required?
420
+ p.required?
421
+ end
422
+
423
+ def optional bool = true
424
+ if bool
425
+ p.required !bool
426
+ else
427
+ p.required bool
428
+ end
429
+ end
430
+ def optional?
431
+ p.optional?
432
+ end
433
+
434
+ def cast sym=nil, &b
435
+ p.cast = sym || b
436
+ end
437
+ def cast?
438
+ p.cast?
439
+ end
440
+
441
+ def validate sym=nil, &b
442
+ p.validate = sym || b
443
+ end
444
+ def validate?
445
+ p.validate?
446
+ end
447
+
448
+ def description s
449
+ p.description = s.to_s
450
+ end
451
+ def description?
452
+ p.description?
453
+ end
454
+ alias_method 'desc', 'description'
455
+
456
+ def default value, *values
457
+ p.defaults.push value
458
+ p.defaults.push *values
459
+ p.defaults
460
+ end
461
+ def defaults?
462
+ p.defaults?
463
+ end
464
+ def defaults value, *values
465
+ p.defaults.push value
466
+ p.defaults.push *values
467
+ p.defaults
468
+ end
469
+ def defaults?
470
+ p.defaults?
471
+ end
472
+
473
+ def arity value
474
+ p.arity = Integer value
475
+ end
476
+ def arity?
477
+ p.arity?
478
+ end
479
+ end
480
+
481
+ class Table < ::Array
482
+ def initialize
483
+ super()
484
+ self.fields = []
485
+ extend BoundsCheck
486
+ end
487
+ module BoundsCheck
488
+ def [] *a, &b
489
+ p = super
490
+ ensure
491
+ raise NoneSuch, a.join(',') unless p
492
+ end
493
+ end
494
+ end
495
+ end
496
+ end