main 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -370,6 +370,26 @@ DOCS
370
370
  API section below
371
371
 
372
372
  HISTORY
373
+ 2.2.0
374
+ - added ability for parameter dsl error handlers to accept an argument,
375
+ this will be passed the current error. for example
376
+
377
+ argument(:x) do
378
+ arity 42
379
+
380
+ error do |e|
381
+ case e
382
+ when Parameter::Arity
383
+ ...
384
+ end
385
+ end
386
+
387
+ - refined the mode parsing a bit: modes can now be abbreviated to uniqness
388
+ and, when the mode is ambiuous, a nice error message is printed, for
389
+ example:
390
+
391
+ ambiguous mode: in = (inflate or install)?
392
+
373
393
  2.1.0
374
394
  - added custom error handling dsl for parameters, this includes the ability
375
395
  to prepend, append, or replace the standard error handlers:
@@ -186,6 +186,26 @@ DOCS
186
186
  API section below
187
187
 
188
188
  HISTORY
189
+ 2.2.0
190
+ - added ability for parameter dsl error handlers to accept an argument,
191
+ this will be passed the current error. for example
192
+
193
+ argument(:x) do
194
+ arity 42
195
+
196
+ error do |e|
197
+ case e
198
+ when Parameter::Arity
199
+ ...
200
+ end
201
+ end
202
+
203
+ - refined the mode parsing a bit: modes can now be abbreviated to uniqness
204
+ and, when the mode is ambiuous, a nice error message is printed, for
205
+ example:
206
+
207
+ ambiguous mode: in = (inflate or install)?
208
+
189
209
  2.1.0
190
210
  - added custom error handling dsl for parameters, this includes the ability
191
211
  to prepend, append, or replace the standard error handlers:
data/a.rb CHANGED
@@ -1,20 +1,18 @@
1
1
  require 'main'
2
2
 
3
- puts Main.version
4
-
5
3
  Main {
6
4
  argument 'x' do
7
- error :before do
5
+ arity 2
6
+
7
+ error :before do |e|
8
+ p e
8
9
  puts 'this fires *before* normal error handling using #instance_eval...'
9
10
  end
10
11
 
11
- error do
12
+ error do |e|
13
+ p e
12
14
  puts 'this fires *instead of* normal error handling using #instance_eval...'
13
15
  end
14
-
15
- error :after do
16
- puts 'this fires *after* normal error handling using #instance_eval...'
17
- end
18
16
  end
19
17
 
20
18
  run(){ p param['x'].given? }
@@ -2,7 +2,7 @@ module Main
2
2
  #
3
3
  # top level constants
4
4
  #
5
- Main::VERSION = '2.1.0' unless
5
+ Main::VERSION = '2.2.0' unless
6
6
  defined? Main::VERSION
7
7
  def self.version() Main::VERSION end
8
8
 
@@ -318,15 +318,25 @@ module Main
318
318
  def post_run() :hook end
319
319
 
320
320
  def mode_given?
321
- self.class.modes.find_by_mode argv.first, :quiet => true if argv.first
321
+ begin
322
+ modes.size > 0 and
323
+ argv.size > 0 and
324
+ modes.find_by_mode(argv.first)
325
+ rescue Mode::Ambiguous
326
+ true
327
+ end
322
328
  end
323
-
324
329
  def mode_run!
325
- mode = self.class.modes.find_by_mode argv.shift
326
- klass = self.class.modes[mode] or abort "bad mode <#{ mode }>"
330
+ mode = modes.find_by_mode argv.shift
331
+ klass = modes[mode] or abort "bad mode <#{ mode }>"
327
332
  main = klass.new @argv, @env, @opts
333
+ main.mode = mode
328
334
  main.run
329
335
  end
336
+ def modes
337
+ self.class.modes
338
+ end
339
+ attribute 'mode'
330
340
 
331
341
  def help! status = 0
332
342
  print usage.to_s
@@ -334,12 +344,12 @@ module Main
334
344
  end
335
345
 
336
346
  def handle_exception e
337
- if e.respond_to?(:before_handler)
338
- fcall(e, :before_handler, self)
347
+ if e.respond_to?(:error_handler_before)
348
+ fcall(e, :error_handler_before, self)
339
349
  end
340
350
 
341
- if e.respond_to?(:handler)
342
- fcall(e, :handler, self)
351
+ if e.respond_to?(:error_handler_instead)
352
+ fcall(e, :error_handler_instead, self)
343
353
  else
344
354
  if e.respond_to? :status
345
355
  exit_status(( e.status ))
@@ -352,8 +362,8 @@ module Main
352
362
  end
353
363
  end
354
364
 
355
- if e.respond_to?(:after_handler)
356
- fcall(e, :after_handler, self)
365
+ if e.respond_to?(:error_handler_after)
366
+ fcall(e, :error_handler_after, self)
357
367
  end
358
368
 
359
369
  exit_status(( exit_failure )) if exit_status == exit_success
@@ -376,5 +386,22 @@ module Main
376
386
  def handle_throw status
377
387
  exit(( Integer(status) rescue 0 ))
378
388
  end
389
+
390
+ %w[ before instead after ].each do |which|
391
+ module_eval <<-code
392
+ def error_handler_#{ which } *argv, &block
393
+ block.call *argv
394
+ end
395
+ code
396
+ end
397
+
398
+ def instance_eval_block *argv, &block
399
+ sc =
400
+ class << self
401
+ self
402
+ end
403
+ sc.module_eval{ define_method '__instance_eval_block', &block }
404
+ fcall self, '__instance_eval_block', *argv, &block
405
+ end
379
406
  end
380
407
  end
@@ -1,7 +1,7 @@
1
1
  class Mode < ::String
2
2
  class Error < ::StandardError; end
3
3
  class Duplicate < Error; end
4
- class Ambigous < Error
4
+ class Ambiguous < Error
5
5
  include Main::Softspoken
6
6
  end
7
7
 
@@ -31,7 +31,7 @@ class Mode < ::String
31
31
  when 1
32
32
  candidates.first
33
33
  else
34
- quiet ? nil : raise(Ambigous, m)
34
+ raise Ambiguous, "ambiguous mode: #{ m } = (#{ candidates.sort.join ' or ' })?"
35
35
  end
36
36
  end
37
37
  end
@@ -69,9 +69,9 @@ module Main
69
69
  attribute 'arity' => 1
70
70
  attribute 'required' => false
71
71
 
72
- attribute 'before_handler'
73
- attribute 'error_handler'
74
- attribute 'after_handler'
72
+ attribute 'error_handler_before'
73
+ attribute 'error_handler_instead'
74
+ attribute 'error_handler_after'
75
75
 
76
76
  def initialize name, *names, &block
77
77
  @names = Cast.list_of_string name, *names
@@ -189,28 +189,23 @@ module Main
189
189
  end
190
190
 
191
191
  def add_handlers e
192
- sc =
192
+ esc =
193
193
  class << e
194
194
  self
195
195
  end
196
196
 
197
197
  this = self
198
198
 
199
- if before_handler?
200
- sc.module_eval do
201
- define_method(:before_handler){|main| main.instance_eval &this.before_handler}
202
- end
203
- end
204
-
205
- if error_handler?
206
- sc.module_eval do
207
- define_method(:handler){|main| main.instance_eval &this.error_handler}
208
- end
209
- end
210
-
211
- if after_handler?
212
- sc.module_eval do
213
- define_method(:after_handler){|main| main.instance_eval &this.after_handler}
199
+ %w[ before instead after ].each do |which|
200
+ getter = "error_handler_#{ which }"
201
+ query = "error_handler_#{ which }?"
202
+ if send(query)
203
+ handler = send getter
204
+ esc.module_eval do
205
+ define_method(getter) do |main|
206
+ main.instance_eval_block self, &handler
207
+ end
208
+ end
214
209
  end
215
210
  end
216
211
  end
@@ -561,8 +556,8 @@ module Main
561
556
  p.arity?
562
557
  end
563
558
 
564
- def error which = :error, &block
565
- p.send "#{ which }_handler=", block
559
+ def error which = :instead, &block
560
+ p.send "error_handler_#{ which }=", block
566
561
  end
567
562
  end
568
563
 
@@ -83,6 +83,19 @@ module Main
83
83
  s << " [options]+"
84
84
  end
85
85
 
86
+ # help info
87
+ =begin
88
+ if main.modes.size > 0
89
+ modes = main.modes.keys.join('|')
90
+ s << "\n#{ main.name } (#{ modes }) help"
91
+ end
92
+ if main.mode_name != 'main'
93
+ s << "\n#{ main.name } #{ main.fully_qualified_mode.join ' ' } help"
94
+ else
95
+ s << "\n#{ main.name } help"
96
+ end
97
+ =end
98
+
86
99
  s
87
100
  end
88
101
 
File without changes
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: main
5
5
  version: !ruby/object:Gem::Version
6
- version: 2.1.0
7
- date: 2007-10-20 00:00:00 -06:00
6
+ version: 2.2.0
7
+ date: 2007-10-24 00:00:00 -06:00
8
8
  summary: main
9
9
  require_paths:
10
10
  - lib
@@ -34,7 +34,6 @@ files:
34
34
  - gen_readme.rb
35
35
  - install.rb
36
36
  - lib
37
- - lib/arrayfields.rb
38
37
  - lib/main
39
38
  - lib/main/arrayfields.rb
40
39
  - lib/main/attributes.rb
@@ -50,7 +49,7 @@ files:
50
49
  - lib/main/usage.rb
51
50
  - lib/main/util.rb
52
51
  - lib/main.rb
53
- - main-2.0.0.gem
52
+ - main-2.2.0.gem
54
53
  - README
55
54
  - README.tmpl
56
55
  - samples
@@ -1,434 +0,0 @@
1
- #
2
- # The ArrayFields module implements methods which allow an Array to be indexed
3
- # by String or Symbol. It is not required to manually use this module to
4
- # extend Arrays - they are auto-extended on a per-object basis when
5
- # Array#fields= is called
6
- #
7
- module ArrayFields
8
- self::VERSION = '4.5.0' unless defined? self::VERSION
9
- def self.version() VERSION end
10
- #
11
- # multiton cache of fields - wraps fields and fieldpos map to save memory
12
- #
13
- class FieldSet
14
- class << self
15
- def new fields
16
- @sets[fields] ||= super
17
- end
18
- def init_sets
19
- @sets = {}
20
- end
21
- end
22
-
23
- init_sets
24
-
25
- attr :fields
26
- attr :fieldpos
27
- def initialize fields
28
- raise ArgumentError, "<#{ fields.inspect }> not inject-able" unless
29
- fields.respond_to? :inject
30
-
31
- @fieldpos =
32
- fields.inject({}) do |h, f|
33
- unless String === f or Symbol === f
34
- raise ArgumentError, "<#{ f.inspect }> neither String nor Symbol"
35
- end
36
- h[f] = h.size
37
- h
38
- end
39
-
40
- @fields = fields
41
- end
42
- def pos f
43
- return @fieldpos[f] if @fieldpos.has_key? f
44
- f = f.to_s
45
- return @fieldpos[f] if @fieldpos.has_key? f
46
- f = f.intern
47
- return @fieldpos[f] if @fieldpos.has_key? f
48
- nil
49
- end
50
- end
51
- #
52
- # methods redefined to work with fields as well as numeric indexes
53
- #
54
- def [] idx, *args
55
- if @fieldset and (String === idx or Symbol === idx)
56
- pos = @fieldset.pos idx
57
- return nil unless pos
58
- super(pos, *args)
59
- else
60
- super
61
- end
62
- end
63
- def slice idx, *args
64
- if @fieldset and (String === idx or Symbol === idx)
65
- pos = @fieldset.pos idx
66
- return nil unless pos
67
- super(pos, *args)
68
- else
69
- super
70
- end
71
- end
72
-
73
- def []=(idx, *args)
74
- if @fieldset and (String === idx or Symbol === idx)
75
- pos = @fieldset.pos idx
76
- unless pos
77
- @fieldset.fields << idx
78
- @fieldset.fieldpos[idx] = pos = size
79
- end
80
- super(pos, *args)
81
- else
82
- super
83
- end
84
- end
85
- def at idx
86
- if @fieldset and (String === idx or Symbol === idx)
87
- pos = @fieldset.pos idx
88
- return nil unless pos
89
- super pos
90
- else
91
- super
92
- end
93
- end
94
- def delete_at idx
95
- if @fieldset and (String === idx or Symbol === idx)
96
- pos = @fieldset.pos idx
97
- return nil unless pos
98
- super pos
99
- else
100
- super
101
- end
102
- end
103
- def fill(obj, *args)
104
- idx = args.first
105
- if idx and @fieldset and (String === idx or Symbol === idx)
106
- idx = args.shift
107
- pos = @fieldset.pos idx
108
- super(obj, pos, *args)
109
- else
110
- super
111
- end
112
- end
113
-
114
- def values_at(*idxs)
115
- idxs.flatten!
116
- if @fieldset
117
- idxs.map!{|i| (String === i or Symbol === i) ? @fieldset.pos(i) : i}
118
- end
119
- super(*idxs)
120
- end
121
- def indices(*idxs)
122
- idxs.flatten!
123
- if @fieldset
124
- idxs.map!{|i| (String === i or Symbol === i) ? @fieldset.pos(i) : i}
125
- end
126
- super(*idxs)
127
- end
128
- def indexes(*idxs)
129
- idxs.flatten!
130
- if @fieldset
131
- idxs.map!{|i| (String === i or Symbol === i) ? @fieldset.pos(i) : i}
132
- end
133
- super(*idxs)
134
- end
135
-
136
- def slice!(*args)
137
- ret = self[*args]
138
- self[*args] = nil
139
- ret
140
- end
141
- def each_with_field
142
- each_with_index do |elem, i|
143
- yield elem, @fieldset.fields[i]
144
- end
145
- end
146
- #
147
- # methods which give a hash-like interface
148
- #
149
- def each_pair
150
- each_with_index do |elem, i|
151
- yield @fieldset.fields[i], elem
152
- end
153
- end
154
- def each_key
155
- @fieldset.each{|field| yield field}
156
- end
157
- def each_value *args, &block
158
- each *args, &block
159
- end
160
- def fetch key
161
- self[key] or raise IndexError, 'key not found'
162
- end
163
-
164
- def has_key? key
165
- @fieldset.fields.include? key
166
- end
167
- def member? key
168
- @fieldset.fields.include? key
169
- end
170
- def key? key
171
- @fieldset.fields.include? key
172
- end
173
-
174
- def has_value? value
175
- if respond_to? 'include?'
176
- self.include? value
177
- else
178
- a = []
179
- each{|val| a << val}
180
- a.include? value
181
- end
182
- end
183
- def value? value
184
- if respond_to? 'include?'
185
- self.include? value
186
- else
187
- a = []
188
- each{|val| a << val}
189
- a.include? value
190
- end
191
- end
192
-
193
- def keys
194
- fields
195
- end
196
- def store key, value
197
- self[key] = value
198
- end
199
- def values
200
- if respond_to? 'to_ary'
201
- self.to_ary
202
- else
203
- a = []
204
- each{|val| a << val}
205
- a
206
- end
207
- end
208
-
209
- def to_hash
210
- if respond_to? 'to_ary'
211
- h = {}
212
- @fieldset.fields.zip(to_ary){|f,e| h[f] = e}
213
- h
214
- else
215
- a = []
216
- each{|val| a << val}
217
- h = {}
218
- @fieldset.fields.zip(a){|f,e| h[f] = e}
219
- h
220
- end
221
- end
222
- def to_h
223
- if respond_to? 'to_ary'
224
- h = {}
225
- @fieldset.fields.zip(to_ary){|f,e| h[f] = e}
226
- h
227
- else
228
- a = []
229
- each{|val| a << val}
230
- h = {}
231
- @fieldset.fields.zip(a){|f,e| h[f] = e}
232
- h
233
- end
234
- end
235
-
236
- def update other
237
- other.each{|k,v| self[k] = v}
238
- to_hash
239
- end
240
- def replace other
241
- Hash === other ? update(other) : super
242
- end
243
- def invert
244
- to_hash.invert
245
- end
246
-
247
- def to_pairs
248
- fields.zip values
249
- end
250
- alias_method 'pairs', 'to_pairs'
251
-
252
- def copy
253
- cp = clone
254
- cp.fields = fields.clone
255
- cp
256
- end
257
-
258
- alias_method 'dup', 'copy'
259
- alias_method 'clone', 'copy'
260
-
261
- def deepcopy
262
- cp = Marshal.load(Marshal.dump(self))
263
- cp.fields = Marshal.load(Marshal.dump(self.fields))
264
- cp
265
- end
266
- end
267
- Arrayfields = ArrayFields
268
-
269
- module Arrayfields
270
- def self.new *pairs
271
- pairs = pairs.map{|pair| Enumerable === pair ? pair.to_a : pair}.flatten
272
- raise ArgumentError, "pairs must be evenly sized" unless(pairs.size % 2 == 0)
273
- (( array = [] )).fields = []
274
- 0.step(pairs.size - 2, 2) do |a|
275
- b = a + 1
276
- array[ pairs[a] ] = pairs[b]
277
- end
278
- array
279
- end
280
- def self.[] *pairs
281
- new *pairs
282
- end
283
- end
284
- def Arrayfields(*a, &b) Arrayfields.new(*a, &b) end
285
- #
286
- # Fieldable encapsulates methods in common for classes which may have their
287
- # fields set and subsequently be auto-extended by ArrayFields
288
- #
289
- module Fieldable
290
- #
291
- # sets fields an dynamically extends this Array instance with methods for
292
- # keyword access
293
- #
294
- def fields= fields
295
- extend ArrayFields unless ArrayFields === self
296
-
297
- @fieldset =
298
- if ArrayFields::FieldSet === fields
299
- fields
300
- else
301
- ArrayFields::FieldSet.new fields
302
- end
303
- end
304
- #
305
- # access to fieldset
306
- #
307
- attr_reader :fieldset
308
- #
309
- # access to field list
310
- #
311
- def fields
312
- @fieldset and @fieldset.fields
313
- end
314
- end
315
- #
316
- # Array instances are extened with two methods only: Fieldable#fields= and
317
- # Fieldable#fields. only when Fieldable#fields= is called will the full set
318
- # of ArrayFields methods auto-extend the Array instance. the Array class also
319
- # has added a class generator when the fields are known apriori.
320
- #
321
- class Array
322
- include Fieldable
323
-
324
- class << self
325
- def struct *fields
326
- fields = fields.flatten
327
- Class.new(self) do
328
- include ArrayFields
329
- const_set :FIELDS, ArrayFields::FieldSet.new(fields)
330
- fields.each do |field|
331
- field = field.to_s
332
- if field =~ %r/^[a-zA-Z_][a-zA-Z0-9_]*$/
333
- begin
334
- module_eval <<-code
335
- def #{ field } *a
336
- a.size == 0 ? self['#{ field }'] : (self.#{ field } = a.shift)
337
- end
338
- def #{ field }= value
339
- self['#{ field }'] = value
340
- end
341
- code
342
- rescue SyntaxError
343
- :by_ignoring_it
344
- end
345
- end
346
- end
347
- def initialize *a, &b
348
- super
349
- ensure
350
- @fieldset = self.class.const_get :FIELDS
351
- end
352
- def self.[] *elements
353
- array = new
354
- array.replace elements
355
- array
356
- end
357
- end
358
- end
359
- def fields *fields, &block
360
- (( array = new(&block) )).fields = fields.map{|x| Enumerable === x ? x.to_a : x}.flatten
361
- array
362
- end
363
- end
364
- end
365
- #
366
- # proxy class that allows an array to be wrapped in a way that still allows #
367
- # keyword access. also facilitate usage of ArrayFields with arraylike objects.
368
- # thnx to Sean O'Dell for the suggestion.
369
- #
370
- # sample usage
371
- #
372
- # fa = FieldedArray.new %w(zero one two), [0,1,2]
373
- # p fa['zero'] #=> 0
374
- #
375
- #
376
- class FieldedArray
377
- include Fieldable
378
- class << self
379
- def [](*pairs)
380
- pairs.flatten!
381
- raise ArgumentError, "argument must be key/val pairs" unless
382
- (pairs.size % 2 == 0)
383
- fields, elements = [], []
384
- while((f = pairs.shift) and (e = pairs.shift))
385
- fields << f and elements << e
386
- end
387
- new fields, elements
388
- end
389
- end
390
- def initialize fields = [], array = []
391
- @a = array
392
- self.fields = fields
393
- end
394
- def method_missing(meth, *args, &block)
395
- @a.send(meth, *args, &block)
396
- end
397
- delegates =
398
- %w(
399
- to_s
400
- to_str
401
- inspect
402
- )
403
- delegates.each do |meth|
404
- class_eval "def #{ meth }(*a,&b); @a.#{ meth }(*a,&b);end"
405
- end
406
- end
407
- Fieldedarray = FieldedArray
408
-
409
- class PseudoHash < ::Array
410
- class << self
411
- def [](*pairs)
412
- pairs.flatten!
413
- raise ArgumentError, "argument must be key/val pairs" unless
414
- (pairs.size % 2 == 0 and pairs.size >= 2)
415
- keys, values = [], []
416
- while((k = pairs.shift) and (v = pairs.shift))
417
- keys << k and values << v
418
- end
419
- new keys, values
420
- end
421
- end
422
- def initialize keys = [], values = []
423
- self.fields = keys
424
- self.replace values
425
- end
426
- def to_yaml opts = {}
427
- YAML::quick_emit object_id, opts do |out|
428
- out.map taguri, to_yaml_style do |map|
429
- each_pair{|f,v| map.add f,v}
430
- end
431
- end
432
- end
433
- end
434
- Pseudohash = PseudoHash
Binary file