main 0.0.2 → 2.0.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 +136 -25
- data/README.tmpl +126 -9
- data/TODO +2 -0
- data/a.rb +26 -0
- data/gemspec.rb +1 -1
- data/gen_readme.rb +4 -0
- data/lib/arrayfields.rb +434 -0
- data/lib/main.rb +46 -17
- data/lib/main/arrayfields.rb +190 -103
- data/lib/main/attributes.rb +84 -25
- data/lib/main/base.rb +146 -23
- data/lib/main/factories.rb +12 -8
- data/lib/main/mode.rb +42 -0
- data/lib/main/parameter.rb +77 -38
- data/lib/main/pervasives.rb +52 -0
- data/lib/main/softspoken.rb +12 -0
- data/lib/main/stdext.rb +18 -0
- data/lib/main/usage.rb +21 -3
- data/samples/e.rb +18 -0
- data/samples/f.rb +27 -0
- data/test/main.rb +156 -30
- metadata +25 -17
- data/lib/main/proxy.rb +0 -54
data/lib/main/arrayfields.rb
CHANGED
@@ -1,35 +1,30 @@
|
|
1
1
|
#
|
2
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
|
-
#
|
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
|
5
6
|
#
|
6
7
|
module ArrayFields
|
7
|
-
|
8
|
-
VERSION
|
8
|
+
self::VERSION = '4.5.0' unless defined? self::VERSION
|
9
|
+
def self.version() VERSION end
|
9
10
|
#
|
10
11
|
# multiton cache of fields - wraps fields and fieldpos map to save memory
|
11
12
|
#
|
12
13
|
class FieldSet
|
13
|
-
#{{{
|
14
14
|
class << self
|
15
|
-
#{{{
|
16
15
|
def new fields
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
obj = super
|
22
|
-
@sets[fields] = obj
|
23
|
-
end
|
24
|
-
obj
|
25
|
-
#}}}
|
16
|
+
@sets[fields] ||= super
|
17
|
+
end
|
18
|
+
def init_sets
|
19
|
+
@sets = {}
|
26
20
|
end
|
27
|
-
#}}}
|
28
21
|
end
|
22
|
+
|
23
|
+
init_sets
|
24
|
+
|
29
25
|
attr :fields
|
30
26
|
attr :fieldpos
|
31
27
|
def initialize fields
|
32
|
-
#{{{
|
33
28
|
raise ArgumentError, "<#{ fields.inspect }> not inject-able" unless
|
34
29
|
fields.respond_to? :inject
|
35
30
|
|
@@ -43,25 +38,29 @@
|
|
43
38
|
end
|
44
39
|
|
45
40
|
@fields = fields
|
46
|
-
#}}}
|
47
41
|
end
|
48
42
|
def pos f
|
49
|
-
#{{{
|
50
43
|
return @fieldpos[f] if @fieldpos.has_key? f
|
51
44
|
f = f.to_s
|
52
45
|
return @fieldpos[f] if @fieldpos.has_key? f
|
53
46
|
f = f.intern
|
54
47
|
return @fieldpos[f] if @fieldpos.has_key? f
|
55
48
|
nil
|
56
|
-
#}}}
|
57
49
|
end
|
58
|
-
#}}}
|
59
50
|
end
|
60
51
|
#
|
61
52
|
# methods redefined to work with fields as well as numeric indexes
|
62
53
|
#
|
63
|
-
def []
|
64
|
-
|
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
|
65
64
|
if @fieldset and (String === idx or Symbol === idx)
|
66
65
|
pos = @fieldset.pos idx
|
67
66
|
return nil unless pos
|
@@ -69,11 +68,9 @@
|
|
69
68
|
else
|
70
69
|
super
|
71
70
|
end
|
72
|
-
#}}}
|
73
71
|
end
|
74
|
-
|
72
|
+
|
75
73
|
def []=(idx, *args)
|
76
|
-
#{{{
|
77
74
|
if @fieldset and (String === idx or Symbol === idx)
|
78
75
|
pos = @fieldset.pos idx
|
79
76
|
unless pos
|
@@ -84,10 +81,8 @@
|
|
84
81
|
else
|
85
82
|
super
|
86
83
|
end
|
87
|
-
#}}}
|
88
84
|
end
|
89
85
|
def at idx
|
90
|
-
#{{{
|
91
86
|
if @fieldset and (String === idx or Symbol === idx)
|
92
87
|
pos = @fieldset.pos idx
|
93
88
|
return nil unless pos
|
@@ -95,10 +90,8 @@
|
|
95
90
|
else
|
96
91
|
super
|
97
92
|
end
|
98
|
-
#}}}
|
99
93
|
end
|
100
94
|
def delete_at idx
|
101
|
-
#{{{
|
102
95
|
if @fieldset and (String === idx or Symbol === idx)
|
103
96
|
pos = @fieldset.pos idx
|
104
97
|
return nil unless pos
|
@@ -106,10 +99,8 @@
|
|
106
99
|
else
|
107
100
|
super
|
108
101
|
end
|
109
|
-
#}}}
|
110
102
|
end
|
111
103
|
def fill(obj, *args)
|
112
|
-
#{{{
|
113
104
|
idx = args.first
|
114
105
|
if idx and @fieldset and (String === idx or Symbol === idx)
|
115
106
|
idx = args.shift
|
@@ -118,67 +109,69 @@
|
|
118
109
|
else
|
119
110
|
super
|
120
111
|
end
|
121
|
-
#}}}
|
122
112
|
end
|
113
|
+
|
123
114
|
def values_at(*idxs)
|
124
|
-
#{{{
|
125
115
|
idxs.flatten!
|
126
116
|
if @fieldset
|
127
117
|
idxs.map!{|i| (String === i or Symbol === i) ? @fieldset.pos(i) : i}
|
128
118
|
end
|
129
119
|
super(*idxs)
|
130
|
-
#}}}
|
131
120
|
end
|
132
|
-
|
133
|
-
|
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
|
+
|
134
136
|
def slice!(*args)
|
135
|
-
#{{{
|
136
137
|
ret = self[*args]
|
137
138
|
self[*args] = nil
|
138
139
|
ret
|
139
|
-
#}}}
|
140
140
|
end
|
141
141
|
def each_with_field
|
142
|
-
#{{{
|
143
142
|
each_with_index do |elem, i|
|
144
143
|
yield elem, @fieldset.fields[i]
|
145
144
|
end
|
146
|
-
#}}}
|
147
145
|
end
|
148
146
|
#
|
149
147
|
# methods which give a hash-like interface
|
150
148
|
#
|
151
149
|
def each_pair
|
152
|
-
#{{{
|
153
150
|
each_with_index do |elem, i|
|
154
151
|
yield @fieldset.fields[i], elem
|
155
152
|
end
|
156
|
-
#}}}
|
157
153
|
end
|
158
154
|
def each_key
|
159
|
-
#{{{
|
160
155
|
@fieldset.each{|field| yield field}
|
161
|
-
#}}}
|
162
156
|
end
|
163
|
-
def each_value
|
164
|
-
|
165
|
-
each(*args, &block)
|
166
|
-
#}}}
|
157
|
+
def each_value *args, &block
|
158
|
+
each *args, &block
|
167
159
|
end
|
168
160
|
def fetch key
|
169
|
-
#{{{
|
170
161
|
self[key] or raise IndexError, 'key not found'
|
171
|
-
#}}}
|
172
162
|
end
|
163
|
+
|
173
164
|
def has_key? key
|
174
|
-
#{{{
|
175
165
|
@fieldset.fields.include? key
|
176
|
-
#}}}
|
177
166
|
end
|
178
|
-
|
179
|
-
|
167
|
+
def member? key
|
168
|
+
@fieldset.fields.include? key
|
169
|
+
end
|
170
|
+
def key? key
|
171
|
+
@fieldset.fields.include? key
|
172
|
+
end
|
173
|
+
|
180
174
|
def has_value? value
|
181
|
-
#{{{
|
182
175
|
if respond_to? 'include?'
|
183
176
|
self.include? value
|
184
177
|
else
|
@@ -186,21 +179,24 @@
|
|
186
179
|
each{|val| a << val}
|
187
180
|
a.include? value
|
188
181
|
end
|
189
|
-
#}}}
|
190
182
|
end
|
191
|
-
|
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
|
+
|
192
193
|
def keys
|
193
|
-
#{{{
|
194
194
|
fields
|
195
|
-
#}}}
|
196
195
|
end
|
197
196
|
def store key, value
|
198
|
-
#{{{
|
199
197
|
self[key] = value
|
200
|
-
#}}}
|
201
198
|
end
|
202
199
|
def values
|
203
|
-
#{{{
|
204
200
|
if respond_to? 'to_ary'
|
205
201
|
self.to_ary
|
206
202
|
else
|
@@ -208,10 +204,9 @@
|
|
208
204
|
each{|val| a << val}
|
209
205
|
a
|
210
206
|
end
|
211
|
-
#}}}
|
212
207
|
end
|
208
|
+
|
213
209
|
def to_hash
|
214
|
-
#{{{
|
215
210
|
if respond_to? 'to_ary'
|
216
211
|
h = {}
|
217
212
|
@fieldset.fields.zip(to_ary){|f,e| h[f] = e}
|
@@ -223,40 +218,81 @@
|
|
223
218
|
@fieldset.fields.zip(a){|f,e| h[f] = e}
|
224
219
|
h
|
225
220
|
end
|
226
|
-
#}}}
|
227
221
|
end
|
228
|
-
|
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
|
+
|
229
236
|
def update other
|
230
|
-
#--{{{
|
231
237
|
other.each{|k,v| self[k] = v}
|
232
238
|
to_hash
|
233
|
-
#--}}}
|
234
239
|
end
|
235
240
|
def replace other
|
236
|
-
#--{{{
|
237
241
|
Hash === other ? update(other) : super
|
238
|
-
#--}}}
|
239
242
|
end
|
240
243
|
def invert
|
241
|
-
#--{{{
|
242
244
|
to_hash.invert
|
243
|
-
#--}}}
|
244
245
|
end
|
245
|
-
|
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
|
246
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
|
247
285
|
#
|
248
286
|
# Fieldable encapsulates methods in common for classes which may have their
|
249
|
-
# fields set
|
287
|
+
# fields set and subsequently be auto-extended by ArrayFields
|
250
288
|
#
|
251
289
|
module Fieldable
|
252
|
-
#{{{
|
253
290
|
#
|
254
291
|
# sets fields an dynamically extends this Array instance with methods for
|
255
292
|
# keyword access
|
256
293
|
#
|
257
294
|
def fields= fields
|
258
|
-
|
259
|
-
extend ArrayFields unless defined? @fieldset
|
295
|
+
extend ArrayFields unless ArrayFields === self
|
260
296
|
|
261
297
|
@fieldset =
|
262
298
|
if ArrayFields::FieldSet === fields
|
@@ -264,7 +300,6 @@
|
|
264
300
|
else
|
265
301
|
ArrayFields::FieldSet.new fields
|
266
302
|
end
|
267
|
-
#}}}
|
268
303
|
end
|
269
304
|
#
|
270
305
|
# access to fieldset
|
@@ -274,19 +309,58 @@
|
|
274
309
|
# access to field list
|
275
310
|
#
|
276
311
|
def fields
|
277
|
-
#{{{
|
278
312
|
@fieldset and @fieldset.fields
|
279
|
-
#}}}
|
280
313
|
end
|
281
|
-
#}}}
|
282
314
|
end
|
283
315
|
#
|
284
|
-
#
|
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.
|
285
320
|
#
|
286
321
|
class Array
|
287
|
-
#{{{
|
288
322
|
include Fieldable
|
289
|
-
|
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
|
290
364
|
end
|
291
365
|
#
|
292
366
|
# proxy class that allows an array to be wrapped in a way that still allows #
|
@@ -300,48 +374,61 @@
|
|
300
374
|
#
|
301
375
|
#
|
302
376
|
class FieldedArray
|
303
|
-
#{{{
|
304
377
|
include Fieldable
|
305
378
|
class << self
|
306
|
-
|
307
379
|
def [](*pairs)
|
308
|
-
#{{{
|
309
380
|
pairs.flatten!
|
310
|
-
raise ArgumentError, "argument must be key/val
|
311
|
-
(pairs.size % 2 == 0
|
381
|
+
raise ArgumentError, "argument must be key/val pairs" unless
|
382
|
+
(pairs.size % 2 == 0)
|
312
383
|
fields, elements = [], []
|
313
|
-
#pairs.each do |f,e|
|
314
384
|
while((f = pairs.shift) and (e = pairs.shift))
|
315
|
-
raise ArgumentError, "field must be String or Symbol" unless
|
316
|
-
(String === f or Symbol === f)
|
317
385
|
fields << f and elements << e
|
318
386
|
end
|
319
387
|
new fields, elements
|
320
|
-
#}}}
|
321
388
|
end
|
322
|
-
|
323
389
|
end
|
324
|
-
def initialize fields, array
|
325
|
-
#{{{
|
390
|
+
def initialize fields = [], array = []
|
326
391
|
@a = array
|
327
392
|
self.fields = fields
|
328
|
-
#}}}
|
329
393
|
end
|
330
394
|
def method_missing(meth, *args, &block)
|
331
|
-
#{{{
|
332
395
|
@a.send(meth, *args, &block)
|
333
|
-
#}}}
|
334
396
|
end
|
335
397
|
delegates =
|
336
|
-
#{{{
|
337
398
|
%w(
|
338
399
|
to_s
|
339
400
|
to_str
|
340
401
|
inspect
|
341
402
|
)
|
342
|
-
#}}}
|
343
403
|
delegates.each do |meth|
|
344
404
|
class_eval "def #{ meth }(*a,&b); @a.#{ meth }(*a,&b);end"
|
345
405
|
end
|
346
|
-
#}}}
|
347
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
|