main 2.1.0 → 2.2.0
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.
- data/README +20 -0
- data/README.tmpl +20 -0
- data/a.rb +6 -8
- data/lib/main.rb +1 -1
- data/lib/main/base.rb +37 -10
- data/lib/main/mode.rb +2 -2
- data/lib/main/parameter.rb +16 -21
- data/lib/main/usage.rb +13 -0
- data/main-2.2.0.gem +0 -0
- metadata +3 -4
- data/lib/arrayfields.rb +0 -434
- data/main-2.0.0.gem +0 -0
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:
|
data/README.tmpl
CHANGED
@@ -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
|
-
|
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? }
|
data/lib/main.rb
CHANGED
data/lib/main/base.rb
CHANGED
@@ -318,15 +318,25 @@ module Main
|
|
318
318
|
def post_run() :hook end
|
319
319
|
|
320
320
|
def mode_given?
|
321
|
-
|
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 =
|
326
|
-
klass =
|
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?(:
|
338
|
-
fcall(e, :
|
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?(:
|
342
|
-
fcall(e, :
|
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?(:
|
356
|
-
fcall(e, :
|
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
|
data/lib/main/mode.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Mode < ::String
|
2
2
|
class Error < ::StandardError; end
|
3
3
|
class Duplicate < Error; end
|
4
|
-
class
|
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
|
-
|
34
|
+
raise Ambiguous, "ambiguous mode: #{ m } = (#{ candidates.sort.join ' or ' })?"
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
data/lib/main/parameter.rb
CHANGED
@@ -69,9 +69,9 @@ module Main
|
|
69
69
|
attribute 'arity' => 1
|
70
70
|
attribute 'required' => false
|
71
71
|
|
72
|
-
attribute '
|
73
|
-
attribute '
|
74
|
-
attribute '
|
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
|
-
|
192
|
+
esc =
|
193
193
|
class << e
|
194
194
|
self
|
195
195
|
end
|
196
196
|
|
197
197
|
this = self
|
198
198
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
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 = :
|
565
|
-
p.send "#{ which }
|
559
|
+
def error which = :instead, &block
|
560
|
+
p.send "error_handler_#{ which }=", block
|
566
561
|
end
|
567
562
|
end
|
568
563
|
|
data/lib/main/usage.rb
CHANGED
@@ -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
|
|
data/main-2.2.0.gem
ADDED
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.
|
7
|
-
date: 2007-10-
|
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.
|
52
|
+
- main-2.2.0.gem
|
54
53
|
- README
|
55
54
|
- README.tmpl
|
56
55
|
- samples
|
data/lib/arrayfields.rb
DELETED
@@ -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
|
data/main-2.0.0.gem
DELETED
Binary file
|