arrayfields 3.5.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/lib/arrayfields-3.5.0.rb +342 -0
- data/lib/arrayfields.rb +342 -0
- data/test/arrayfields.rb +323 -0
- metadata +41 -0
@@ -0,0 +1,342 @@
|
|
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 extend
|
4
|
+
# Array's - they are auto-extended when Array#fields= is called
|
5
|
+
#
|
6
|
+
module ArrayFields
|
7
|
+
#{{{
|
8
|
+
VERSION = '3.5.0'
|
9
|
+
#
|
10
|
+
# multiton cache of fields - wraps fields and fieldpos map to save memory
|
11
|
+
#
|
12
|
+
class FieldSet
|
13
|
+
#{{{
|
14
|
+
class << self
|
15
|
+
#{{{
|
16
|
+
def new fields
|
17
|
+
#{{{
|
18
|
+
@sets ||= {}
|
19
|
+
obj = @sets[fields]
|
20
|
+
unless obj
|
21
|
+
obj = super
|
22
|
+
@sets[fields] = obj
|
23
|
+
end
|
24
|
+
obj
|
25
|
+
#}}}
|
26
|
+
end
|
27
|
+
#}}}
|
28
|
+
end
|
29
|
+
attr :fields
|
30
|
+
attr :fieldpos
|
31
|
+
def initialize fields
|
32
|
+
#{{{
|
33
|
+
raise ArgumentError, "<#{ fields.inspect }> not inject-able" unless
|
34
|
+
fields.respond_to? :inject
|
35
|
+
|
36
|
+
@fieldpos =
|
37
|
+
fields.inject({}) do |h, f|
|
38
|
+
unless String === f or Symbol === f
|
39
|
+
raise ArgumentError, "<#{ f.inspect }> neither String nor Symbol"
|
40
|
+
end
|
41
|
+
h[f] = h.size
|
42
|
+
h
|
43
|
+
end
|
44
|
+
|
45
|
+
@fields = fields
|
46
|
+
#}}}
|
47
|
+
end
|
48
|
+
def pos field
|
49
|
+
#{{{
|
50
|
+
@fieldpos[field]
|
51
|
+
#}}}
|
52
|
+
end
|
53
|
+
#}}}
|
54
|
+
end
|
55
|
+
#
|
56
|
+
# methods redefined to work with fields as well as numeric indexes
|
57
|
+
#
|
58
|
+
def [](idx, *args)
|
59
|
+
#{{{
|
60
|
+
if @fieldset and (String === idx or Symbol === idx)
|
61
|
+
pos = @fieldset.pos idx
|
62
|
+
return nil unless pos
|
63
|
+
super(pos, *args)
|
64
|
+
else
|
65
|
+
super
|
66
|
+
end
|
67
|
+
#}}}
|
68
|
+
end
|
69
|
+
alias slice []
|
70
|
+
def []=(idx, *args)
|
71
|
+
#{{{
|
72
|
+
if @fieldset and (String === idx or Symbol === idx)
|
73
|
+
pos = @fieldset.pos idx
|
74
|
+
unless pos
|
75
|
+
@fieldset.fields << idx
|
76
|
+
@fieldset.fieldpos[idx] = pos = size
|
77
|
+
end
|
78
|
+
super(pos, *args)
|
79
|
+
else
|
80
|
+
super
|
81
|
+
end
|
82
|
+
#}}}
|
83
|
+
end
|
84
|
+
def at idx
|
85
|
+
#{{{
|
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
|
+
#}}}
|
94
|
+
end
|
95
|
+
def delete_at idx
|
96
|
+
#{{{
|
97
|
+
if @fieldset and (String === idx or Symbol === idx)
|
98
|
+
pos = @fieldset.pos idx
|
99
|
+
return nil unless pos
|
100
|
+
super pos
|
101
|
+
else
|
102
|
+
super
|
103
|
+
end
|
104
|
+
#}}}
|
105
|
+
end
|
106
|
+
def fill(obj, *args)
|
107
|
+
#{{{
|
108
|
+
idx = args.first
|
109
|
+
if idx and @fieldset and (String === idx or Symbol === idx)
|
110
|
+
idx = args.shift
|
111
|
+
pos = @fieldset.pos idx
|
112
|
+
super(obj, pos, *args)
|
113
|
+
else
|
114
|
+
super
|
115
|
+
end
|
116
|
+
#}}}
|
117
|
+
end
|
118
|
+
def values_at(*idxs)
|
119
|
+
#{{{
|
120
|
+
idxs.flatten!
|
121
|
+
if @fieldset
|
122
|
+
idxs.map!{|i| (String === i or Symbol === i) ? @fieldset.pos(i) : i}
|
123
|
+
end
|
124
|
+
super(*idxs)
|
125
|
+
#}}}
|
126
|
+
end
|
127
|
+
alias indices values_at
|
128
|
+
alias indexes values_at
|
129
|
+
def slice!(*args)
|
130
|
+
#{{{
|
131
|
+
ret = self[*args]
|
132
|
+
self[*args] = nil
|
133
|
+
ret
|
134
|
+
#}}}
|
135
|
+
end
|
136
|
+
def each_with_field
|
137
|
+
#{{{
|
138
|
+
each_with_index do |elem, i|
|
139
|
+
yield elem, @fieldset.fields[i]
|
140
|
+
end
|
141
|
+
#}}}
|
142
|
+
end
|
143
|
+
#
|
144
|
+
# methods which give a hash-like interface
|
145
|
+
#
|
146
|
+
def each_pair
|
147
|
+
#{{{
|
148
|
+
each_with_index do |elem, i|
|
149
|
+
yield @fieldset.fields[i], elem
|
150
|
+
end
|
151
|
+
#}}}
|
152
|
+
end
|
153
|
+
def each_key
|
154
|
+
#{{{
|
155
|
+
@fieldset.each{|field| yield field}
|
156
|
+
#}}}
|
157
|
+
end
|
158
|
+
def each_value(*args, &block)
|
159
|
+
#{{{
|
160
|
+
each(*args, &block)
|
161
|
+
#}}}
|
162
|
+
end
|
163
|
+
def fetch key
|
164
|
+
#{{{
|
165
|
+
self[key] or raise IndexError, 'key not found'
|
166
|
+
#}}}
|
167
|
+
end
|
168
|
+
def has_key? key
|
169
|
+
#{{{
|
170
|
+
@fieldset.fields.include? key
|
171
|
+
#}}}
|
172
|
+
end
|
173
|
+
alias member? has_key?
|
174
|
+
alias key? has_key?
|
175
|
+
def has_value? value
|
176
|
+
#{{{
|
177
|
+
if respond_to? 'include?'
|
178
|
+
self.include? value
|
179
|
+
else
|
180
|
+
a = []
|
181
|
+
each{|val| a << val}
|
182
|
+
a.include? value
|
183
|
+
end
|
184
|
+
#}}}
|
185
|
+
end
|
186
|
+
alias value? has_value?
|
187
|
+
def keys
|
188
|
+
#{{{
|
189
|
+
fields
|
190
|
+
#}}}
|
191
|
+
end
|
192
|
+
def store key, value
|
193
|
+
#{{{
|
194
|
+
self[key] = value
|
195
|
+
#}}}
|
196
|
+
end
|
197
|
+
def values
|
198
|
+
#{{{
|
199
|
+
if respond_to? 'to_ary'
|
200
|
+
self.to_ary
|
201
|
+
else
|
202
|
+
a = []
|
203
|
+
each{|val| a << val}
|
204
|
+
a
|
205
|
+
end
|
206
|
+
#}}}
|
207
|
+
end
|
208
|
+
def to_hash
|
209
|
+
#{{{
|
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
|
+
#}}}
|
222
|
+
end
|
223
|
+
alias to_h to_hash
|
224
|
+
def update other
|
225
|
+
#--{{{
|
226
|
+
other.each{|k,v| self[k] = v}
|
227
|
+
to_hash
|
228
|
+
#--}}}
|
229
|
+
end
|
230
|
+
def replace other
|
231
|
+
#--{{{
|
232
|
+
Hash === other ? update(other) : super
|
233
|
+
#--}}}
|
234
|
+
end
|
235
|
+
def invert
|
236
|
+
#--{{{
|
237
|
+
to_hash.invert
|
238
|
+
#--}}}
|
239
|
+
end
|
240
|
+
#}}}
|
241
|
+
end
|
242
|
+
#
|
243
|
+
# Fieldable encapsulates methods in common for classes which may have their
|
244
|
+
# fields set
|
245
|
+
#
|
246
|
+
module Fieldable
|
247
|
+
#{{{
|
248
|
+
#
|
249
|
+
# sets fields an dynamically extends this Array instance with methods for
|
250
|
+
# keyword access
|
251
|
+
#
|
252
|
+
def fields= fields
|
253
|
+
#{{{
|
254
|
+
extend ArrayFields unless defined? @fieldset
|
255
|
+
|
256
|
+
@fieldset =
|
257
|
+
if ArrayFields::FieldSet === fields
|
258
|
+
fields
|
259
|
+
else
|
260
|
+
ArrayFields::FieldSet.new fields
|
261
|
+
end
|
262
|
+
#}}}
|
263
|
+
end
|
264
|
+
#
|
265
|
+
# access to fieldset
|
266
|
+
#
|
267
|
+
attr_reader :fieldset
|
268
|
+
#
|
269
|
+
# access to field list
|
270
|
+
#
|
271
|
+
def fields
|
272
|
+
#{{{
|
273
|
+
@fieldset and @fieldset.fields
|
274
|
+
#}}}
|
275
|
+
end
|
276
|
+
#}}}
|
277
|
+
end
|
278
|
+
#
|
279
|
+
# The Array class is extened with a methods to allow keyword access
|
280
|
+
#
|
281
|
+
class Array
|
282
|
+
#{{{
|
283
|
+
include Fieldable
|
284
|
+
#}}}
|
285
|
+
end
|
286
|
+
#
|
287
|
+
# proxy class that allows an array to be wrapped in a way that still allows #
|
288
|
+
# keyword access. also facilitate usage of ArrayFields with arraylike objects.
|
289
|
+
# thnx to Sean O'Dell for the suggestion.
|
290
|
+
#
|
291
|
+
# sample usage
|
292
|
+
#
|
293
|
+
# fa = FieldedArray.new %w(zero one two), [0,1,2]
|
294
|
+
# p fa['zero'] #=> 0
|
295
|
+
#
|
296
|
+
#
|
297
|
+
class FieldedArray
|
298
|
+
#{{{
|
299
|
+
include Fieldable
|
300
|
+
class << self
|
301
|
+
|
302
|
+
def [](*pairs)
|
303
|
+
#{{{
|
304
|
+
pairs.flatten!
|
305
|
+
raise ArgumentError, "argument must be key/val paris" unless
|
306
|
+
(pairs.size % 2 == 0 and pairs.size >= 2)
|
307
|
+
fields, elements = [], []
|
308
|
+
#pairs.each do |f,e|
|
309
|
+
while((f = pairs.shift) and (e = pairs.shift))
|
310
|
+
raise ArgumentError, "field must be String or Symbol" unless
|
311
|
+
(String === f or Symbol === f)
|
312
|
+
fields << f and elements << e
|
313
|
+
end
|
314
|
+
new fields, elements
|
315
|
+
#}}}
|
316
|
+
end
|
317
|
+
|
318
|
+
end
|
319
|
+
def initialize fields, array
|
320
|
+
#{{{
|
321
|
+
@a = array
|
322
|
+
self.fields = fields
|
323
|
+
#}}}
|
324
|
+
end
|
325
|
+
def method_missing(meth, *args, &block)
|
326
|
+
#{{{
|
327
|
+
@a.send(meth, *args, &block)
|
328
|
+
#}}}
|
329
|
+
end
|
330
|
+
delegates =
|
331
|
+
#{{{
|
332
|
+
%w(
|
333
|
+
to_s
|
334
|
+
to_str
|
335
|
+
inspect
|
336
|
+
)
|
337
|
+
#}}}
|
338
|
+
delegates.each do |meth|
|
339
|
+
class_eval "def #{ meth }(*a,&b); @a.#{ meth }(*a,&b);end"
|
340
|
+
end
|
341
|
+
#}}}
|
342
|
+
end
|
data/lib/arrayfields.rb
ADDED
@@ -0,0 +1,342 @@
|
|
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 extend
|
4
|
+
# Array's - they are auto-extended when Array#fields= is called
|
5
|
+
#
|
6
|
+
module ArrayFields
|
7
|
+
#{{{
|
8
|
+
VERSION = '3.5.0'
|
9
|
+
#
|
10
|
+
# multiton cache of fields - wraps fields and fieldpos map to save memory
|
11
|
+
#
|
12
|
+
class FieldSet
|
13
|
+
#{{{
|
14
|
+
class << self
|
15
|
+
#{{{
|
16
|
+
def new fields
|
17
|
+
#{{{
|
18
|
+
@sets ||= {}
|
19
|
+
obj = @sets[fields]
|
20
|
+
unless obj
|
21
|
+
obj = super
|
22
|
+
@sets[fields] = obj
|
23
|
+
end
|
24
|
+
obj
|
25
|
+
#}}}
|
26
|
+
end
|
27
|
+
#}}}
|
28
|
+
end
|
29
|
+
attr :fields
|
30
|
+
attr :fieldpos
|
31
|
+
def initialize fields
|
32
|
+
#{{{
|
33
|
+
raise ArgumentError, "<#{ fields.inspect }> not inject-able" unless
|
34
|
+
fields.respond_to? :inject
|
35
|
+
|
36
|
+
@fieldpos =
|
37
|
+
fields.inject({}) do |h, f|
|
38
|
+
unless String === f or Symbol === f
|
39
|
+
raise ArgumentError, "<#{ f.inspect }> neither String nor Symbol"
|
40
|
+
end
|
41
|
+
h[f] = h.size
|
42
|
+
h
|
43
|
+
end
|
44
|
+
|
45
|
+
@fields = fields
|
46
|
+
#}}}
|
47
|
+
end
|
48
|
+
def pos field
|
49
|
+
#{{{
|
50
|
+
@fieldpos[field]
|
51
|
+
#}}}
|
52
|
+
end
|
53
|
+
#}}}
|
54
|
+
end
|
55
|
+
#
|
56
|
+
# methods redefined to work with fields as well as numeric indexes
|
57
|
+
#
|
58
|
+
def [](idx, *args)
|
59
|
+
#{{{
|
60
|
+
if @fieldset and (String === idx or Symbol === idx)
|
61
|
+
pos = @fieldset.pos idx
|
62
|
+
return nil unless pos
|
63
|
+
super(pos, *args)
|
64
|
+
else
|
65
|
+
super
|
66
|
+
end
|
67
|
+
#}}}
|
68
|
+
end
|
69
|
+
alias slice []
|
70
|
+
def []=(idx, *args)
|
71
|
+
#{{{
|
72
|
+
if @fieldset and (String === idx or Symbol === idx)
|
73
|
+
pos = @fieldset.pos idx
|
74
|
+
unless pos
|
75
|
+
@fieldset.fields << idx
|
76
|
+
@fieldset.fieldpos[idx] = pos = size
|
77
|
+
end
|
78
|
+
super(pos, *args)
|
79
|
+
else
|
80
|
+
super
|
81
|
+
end
|
82
|
+
#}}}
|
83
|
+
end
|
84
|
+
def at idx
|
85
|
+
#{{{
|
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
|
+
#}}}
|
94
|
+
end
|
95
|
+
def delete_at idx
|
96
|
+
#{{{
|
97
|
+
if @fieldset and (String === idx or Symbol === idx)
|
98
|
+
pos = @fieldset.pos idx
|
99
|
+
return nil unless pos
|
100
|
+
super pos
|
101
|
+
else
|
102
|
+
super
|
103
|
+
end
|
104
|
+
#}}}
|
105
|
+
end
|
106
|
+
def fill(obj, *args)
|
107
|
+
#{{{
|
108
|
+
idx = args.first
|
109
|
+
if idx and @fieldset and (String === idx or Symbol === idx)
|
110
|
+
idx = args.shift
|
111
|
+
pos = @fieldset.pos idx
|
112
|
+
super(obj, pos, *args)
|
113
|
+
else
|
114
|
+
super
|
115
|
+
end
|
116
|
+
#}}}
|
117
|
+
end
|
118
|
+
def values_at(*idxs)
|
119
|
+
#{{{
|
120
|
+
idxs.flatten!
|
121
|
+
if @fieldset
|
122
|
+
idxs.map!{|i| (String === i or Symbol === i) ? @fieldset.pos(i) : i}
|
123
|
+
end
|
124
|
+
super(*idxs)
|
125
|
+
#}}}
|
126
|
+
end
|
127
|
+
alias indices values_at
|
128
|
+
alias indexes values_at
|
129
|
+
def slice!(*args)
|
130
|
+
#{{{
|
131
|
+
ret = self[*args]
|
132
|
+
self[*args] = nil
|
133
|
+
ret
|
134
|
+
#}}}
|
135
|
+
end
|
136
|
+
def each_with_field
|
137
|
+
#{{{
|
138
|
+
each_with_index do |elem, i|
|
139
|
+
yield elem, @fieldset.fields[i]
|
140
|
+
end
|
141
|
+
#}}}
|
142
|
+
end
|
143
|
+
#
|
144
|
+
# methods which give a hash-like interface
|
145
|
+
#
|
146
|
+
def each_pair
|
147
|
+
#{{{
|
148
|
+
each_with_index do |elem, i|
|
149
|
+
yield @fieldset.fields[i], elem
|
150
|
+
end
|
151
|
+
#}}}
|
152
|
+
end
|
153
|
+
def each_key
|
154
|
+
#{{{
|
155
|
+
@fieldset.each{|field| yield field}
|
156
|
+
#}}}
|
157
|
+
end
|
158
|
+
def each_value(*args, &block)
|
159
|
+
#{{{
|
160
|
+
each(*args, &block)
|
161
|
+
#}}}
|
162
|
+
end
|
163
|
+
def fetch key
|
164
|
+
#{{{
|
165
|
+
self[key] or raise IndexError, 'key not found'
|
166
|
+
#}}}
|
167
|
+
end
|
168
|
+
def has_key? key
|
169
|
+
#{{{
|
170
|
+
@fieldset.fields.include? key
|
171
|
+
#}}}
|
172
|
+
end
|
173
|
+
alias member? has_key?
|
174
|
+
alias key? has_key?
|
175
|
+
def has_value? value
|
176
|
+
#{{{
|
177
|
+
if respond_to? 'include?'
|
178
|
+
self.include? value
|
179
|
+
else
|
180
|
+
a = []
|
181
|
+
each{|val| a << val}
|
182
|
+
a.include? value
|
183
|
+
end
|
184
|
+
#}}}
|
185
|
+
end
|
186
|
+
alias value? has_value?
|
187
|
+
def keys
|
188
|
+
#{{{
|
189
|
+
fields
|
190
|
+
#}}}
|
191
|
+
end
|
192
|
+
def store key, value
|
193
|
+
#{{{
|
194
|
+
self[key] = value
|
195
|
+
#}}}
|
196
|
+
end
|
197
|
+
def values
|
198
|
+
#{{{
|
199
|
+
if respond_to? 'to_ary'
|
200
|
+
self.to_ary
|
201
|
+
else
|
202
|
+
a = []
|
203
|
+
each{|val| a << val}
|
204
|
+
a
|
205
|
+
end
|
206
|
+
#}}}
|
207
|
+
end
|
208
|
+
def to_hash
|
209
|
+
#{{{
|
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
|
+
#}}}
|
222
|
+
end
|
223
|
+
alias to_h to_hash
|
224
|
+
def update other
|
225
|
+
#--{{{
|
226
|
+
other.each{|k,v| self[k] = v}
|
227
|
+
to_hash
|
228
|
+
#--}}}
|
229
|
+
end
|
230
|
+
def replace other
|
231
|
+
#--{{{
|
232
|
+
Hash === other ? update(other) : super
|
233
|
+
#--}}}
|
234
|
+
end
|
235
|
+
def invert
|
236
|
+
#--{{{
|
237
|
+
to_hash.invert
|
238
|
+
#--}}}
|
239
|
+
end
|
240
|
+
#}}}
|
241
|
+
end
|
242
|
+
#
|
243
|
+
# Fieldable encapsulates methods in common for classes which may have their
|
244
|
+
# fields set
|
245
|
+
#
|
246
|
+
module Fieldable
|
247
|
+
#{{{
|
248
|
+
#
|
249
|
+
# sets fields an dynamically extends this Array instance with methods for
|
250
|
+
# keyword access
|
251
|
+
#
|
252
|
+
def fields= fields
|
253
|
+
#{{{
|
254
|
+
extend ArrayFields unless defined? @fieldset
|
255
|
+
|
256
|
+
@fieldset =
|
257
|
+
if ArrayFields::FieldSet === fields
|
258
|
+
fields
|
259
|
+
else
|
260
|
+
ArrayFields::FieldSet.new fields
|
261
|
+
end
|
262
|
+
#}}}
|
263
|
+
end
|
264
|
+
#
|
265
|
+
# access to fieldset
|
266
|
+
#
|
267
|
+
attr_reader :fieldset
|
268
|
+
#
|
269
|
+
# access to field list
|
270
|
+
#
|
271
|
+
def fields
|
272
|
+
#{{{
|
273
|
+
@fieldset and @fieldset.fields
|
274
|
+
#}}}
|
275
|
+
end
|
276
|
+
#}}}
|
277
|
+
end
|
278
|
+
#
|
279
|
+
# The Array class is extened with a methods to allow keyword access
|
280
|
+
#
|
281
|
+
class Array
|
282
|
+
#{{{
|
283
|
+
include Fieldable
|
284
|
+
#}}}
|
285
|
+
end
|
286
|
+
#
|
287
|
+
# proxy class that allows an array to be wrapped in a way that still allows #
|
288
|
+
# keyword access. also facilitate usage of ArrayFields with arraylike objects.
|
289
|
+
# thnx to Sean O'Dell for the suggestion.
|
290
|
+
#
|
291
|
+
# sample usage
|
292
|
+
#
|
293
|
+
# fa = FieldedArray.new %w(zero one two), [0,1,2]
|
294
|
+
# p fa['zero'] #=> 0
|
295
|
+
#
|
296
|
+
#
|
297
|
+
class FieldedArray
|
298
|
+
#{{{
|
299
|
+
include Fieldable
|
300
|
+
class << self
|
301
|
+
|
302
|
+
def [](*pairs)
|
303
|
+
#{{{
|
304
|
+
pairs.flatten!
|
305
|
+
raise ArgumentError, "argument must be key/val paris" unless
|
306
|
+
(pairs.size % 2 == 0 and pairs.size >= 2)
|
307
|
+
fields, elements = [], []
|
308
|
+
#pairs.each do |f,e|
|
309
|
+
while((f = pairs.shift) and (e = pairs.shift))
|
310
|
+
raise ArgumentError, "field must be String or Symbol" unless
|
311
|
+
(String === f or Symbol === f)
|
312
|
+
fields << f and elements << e
|
313
|
+
end
|
314
|
+
new fields, elements
|
315
|
+
#}}}
|
316
|
+
end
|
317
|
+
|
318
|
+
end
|
319
|
+
def initialize fields, array
|
320
|
+
#{{{
|
321
|
+
@a = array
|
322
|
+
self.fields = fields
|
323
|
+
#}}}
|
324
|
+
end
|
325
|
+
def method_missing(meth, *args, &block)
|
326
|
+
#{{{
|
327
|
+
@a.send(meth, *args, &block)
|
328
|
+
#}}}
|
329
|
+
end
|
330
|
+
delegates =
|
331
|
+
#{{{
|
332
|
+
%w(
|
333
|
+
to_s
|
334
|
+
to_str
|
335
|
+
inspect
|
336
|
+
)
|
337
|
+
#}}}
|
338
|
+
delegates.each do |meth|
|
339
|
+
class_eval "def #{ meth }(*a,&b); @a.#{ meth }(*a,&b);end"
|
340
|
+
end
|
341
|
+
#}}}
|
342
|
+
end
|
data/test/arrayfields.rb
ADDED
@@ -0,0 +1,323 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
STDOUT.sync = true
|
3
|
+
$:.unshift 'lib'
|
4
|
+
$:.unshift '../lib'
|
5
|
+
$:.unshift '.'
|
6
|
+
require 'arrayfields'
|
7
|
+
|
8
|
+
class ArrayFieldsTest < Test::Unit::TestCase
|
9
|
+
#{{{
|
10
|
+
def setup
|
11
|
+
#{{{
|
12
|
+
@fields = %w(zero one two)
|
13
|
+
@str_fields = %w(zero one two)
|
14
|
+
@sym_fields = [:zero, :one, :two]
|
15
|
+
@a = [0,1,2]
|
16
|
+
#}}}
|
17
|
+
end
|
18
|
+
#
|
19
|
+
# setting fields correctly
|
20
|
+
#
|
21
|
+
def test_00
|
22
|
+
#{{{
|
23
|
+
assert_nothing_raised do
|
24
|
+
@a.fields = @str_fields
|
25
|
+
end
|
26
|
+
assert_equal @a.fields, @str_fields
|
27
|
+
#}}}
|
28
|
+
end
|
29
|
+
def test_01
|
30
|
+
#{{{
|
31
|
+
assert_nothing_raised do
|
32
|
+
@a.fields = @sym_fields
|
33
|
+
end
|
34
|
+
assert_equal @a.fields, @sym_fields
|
35
|
+
#}}}
|
36
|
+
end
|
37
|
+
def test_02
|
38
|
+
#{{{
|
39
|
+
assert_nothing_raised do
|
40
|
+
a = ArrayFields::FieldSet.new @str_fields
|
41
|
+
b = ArrayFields::FieldSet.new @str_fields
|
42
|
+
assert_equal a, b
|
43
|
+
assert_equal a.id, b.id
|
44
|
+
end
|
45
|
+
#}}}
|
46
|
+
end
|
47
|
+
def test_03
|
48
|
+
#{{{
|
49
|
+
assert_nothing_raised do
|
50
|
+
a = ArrayFields::FieldSet.new @sym_fields
|
51
|
+
b = ArrayFields::FieldSet.new @sym_fields
|
52
|
+
c = ArrayFields::FieldSet.new @str_fields
|
53
|
+
d = ArrayFields::FieldSet.new @str_fields
|
54
|
+
assert_equal a, b
|
55
|
+
assert_equal a.id, b.id
|
56
|
+
assert_not_equal a, c
|
57
|
+
assert_not_equal a.id, c.id
|
58
|
+
end
|
59
|
+
#}}}
|
60
|
+
end
|
61
|
+
#
|
62
|
+
# setting fields incorrectly
|
63
|
+
#
|
64
|
+
def test_10
|
65
|
+
#{{{
|
66
|
+
assert_raises(ArgumentError) do
|
67
|
+
@a.fields = nil
|
68
|
+
end
|
69
|
+
#}}}
|
70
|
+
end
|
71
|
+
def test_11
|
72
|
+
#{{{
|
73
|
+
assert_raises(ArgumentError) do
|
74
|
+
@a.fields = []
|
75
|
+
end
|
76
|
+
#}}}
|
77
|
+
end
|
78
|
+
def test_11
|
79
|
+
#{{{
|
80
|
+
assert_raises(ArgumentError) do
|
81
|
+
@a.fields = [Hash.new]
|
82
|
+
end
|
83
|
+
#}}}
|
84
|
+
end
|
85
|
+
#
|
86
|
+
# []
|
87
|
+
#
|
88
|
+
def test_20
|
89
|
+
#{{{
|
90
|
+
a, b, c = @a[0], @a[1,1].first, @a[2..2].first
|
91
|
+
assert_nothing_raised do
|
92
|
+
@a.fields = @str_fields
|
93
|
+
end
|
94
|
+
assert_nothing_raised do
|
95
|
+
assert_equal a, @a['zero']
|
96
|
+
end
|
97
|
+
assert_nothing_raised do
|
98
|
+
assert_equal b, @a['one']
|
99
|
+
end
|
100
|
+
assert_nothing_raised do
|
101
|
+
assert_equal c, @a['two']
|
102
|
+
end
|
103
|
+
#}}}
|
104
|
+
end
|
105
|
+
def test_21
|
106
|
+
#{{{
|
107
|
+
a = @a[0,@a.size]
|
108
|
+
assert_nothing_raised do
|
109
|
+
@a.fields = @str_fields
|
110
|
+
end
|
111
|
+
assert_nothing_raised do
|
112
|
+
assert_equal a, @a['zero', @a.size]
|
113
|
+
end
|
114
|
+
#}}}
|
115
|
+
end
|
116
|
+
#
|
117
|
+
# []=
|
118
|
+
#
|
119
|
+
def test_30
|
120
|
+
#{{{
|
121
|
+
assert_nothing_raised do
|
122
|
+
@a.fields = @str_fields
|
123
|
+
end
|
124
|
+
value = 42
|
125
|
+
assert_nothing_raised do
|
126
|
+
@a['zero'] = value
|
127
|
+
assert_equal value, @a['zero']
|
128
|
+
assert_equal @a[0], @a['zero']
|
129
|
+
end
|
130
|
+
#}}}
|
131
|
+
end
|
132
|
+
def test_31
|
133
|
+
#{{{
|
134
|
+
assert_nothing_raised do
|
135
|
+
@a.fields = @str_fields
|
136
|
+
end
|
137
|
+
value = 42
|
138
|
+
assert_nothing_raised do
|
139
|
+
@a['zero', 1] = value
|
140
|
+
assert_equal value, @a['zero']
|
141
|
+
assert_equal @a[0,1], @a['zero',1]
|
142
|
+
end
|
143
|
+
#}}}
|
144
|
+
end
|
145
|
+
def test_32
|
146
|
+
#{{{
|
147
|
+
assert_nothing_raised do
|
148
|
+
@a.fields = @str_fields
|
149
|
+
end
|
150
|
+
value = 42
|
151
|
+
assert_nothing_raised do
|
152
|
+
@a[0..0] = value
|
153
|
+
assert_equal value, @a['zero']
|
154
|
+
assert_equal @a[0,1], @a['zero',1]
|
155
|
+
end
|
156
|
+
#}}}
|
157
|
+
end
|
158
|
+
def test_33
|
159
|
+
#{{{
|
160
|
+
assert_nothing_raised do
|
161
|
+
@a.fields = @str_fields
|
162
|
+
end
|
163
|
+
assert_nothing_raised do
|
164
|
+
@a['zero', @a.size] = nil
|
165
|
+
assert_equal @a, []
|
166
|
+
end
|
167
|
+
#}}}
|
168
|
+
end
|
169
|
+
def test_34
|
170
|
+
#{{{
|
171
|
+
assert_nothing_raised do
|
172
|
+
@a.fields = @str_fields
|
173
|
+
end
|
174
|
+
assert_nothing_raised do
|
175
|
+
@a['three'] = 3
|
176
|
+
assert_equal 3, @a['three']
|
177
|
+
assert_equal 3, @a[3]
|
178
|
+
end
|
179
|
+
#}}}
|
180
|
+
end
|
181
|
+
def test_35
|
182
|
+
#{{{
|
183
|
+
assert_nothing_raised do
|
184
|
+
@a.fields = @str_fields
|
185
|
+
@a['three'] = 3
|
186
|
+
end
|
187
|
+
%w(zero one two three).inject(exp=[]){|ex,f| ex << [ex.size, f]}
|
188
|
+
actual = []
|
189
|
+
assert_nothing_raised do
|
190
|
+
@a.each_with_field{|e,f| actual << [e,f]}
|
191
|
+
end
|
192
|
+
assert_equal exp, actual
|
193
|
+
#}}}
|
194
|
+
end
|
195
|
+
def test_36
|
196
|
+
#{{{
|
197
|
+
assert_nothing_raised do
|
198
|
+
@a.fields = @str_fields
|
199
|
+
@a['three'] = 3
|
200
|
+
end
|
201
|
+
assert_equal %w(zero one two three), @a.fields
|
202
|
+
#}}}
|
203
|
+
end
|
204
|
+
#
|
205
|
+
# at
|
206
|
+
#
|
207
|
+
def test_40
|
208
|
+
#{{{
|
209
|
+
assert_nothing_raised do
|
210
|
+
@a.fields = @str_fields
|
211
|
+
end
|
212
|
+
@str_fields.each_with_index do |f, i|
|
213
|
+
ret = nil
|
214
|
+
assert_nothing_raised do
|
215
|
+
ret = @a.at f
|
216
|
+
end
|
217
|
+
assert_equal ret, i
|
218
|
+
end
|
219
|
+
#}}}
|
220
|
+
end
|
221
|
+
#
|
222
|
+
# delete_at
|
223
|
+
#
|
224
|
+
def test_50
|
225
|
+
#{{{
|
226
|
+
assert_nothing_raised do
|
227
|
+
@a.fields = @str_fields
|
228
|
+
end
|
229
|
+
assert_nothing_raised do
|
230
|
+
value = @a.delete_at 'zero'
|
231
|
+
assert_equal 0, value
|
232
|
+
end
|
233
|
+
assert_nothing_raised do
|
234
|
+
value = @a.delete_at 'three'
|
235
|
+
assert_equal nil, value
|
236
|
+
end
|
237
|
+
#}}}
|
238
|
+
end
|
239
|
+
#
|
240
|
+
# fill
|
241
|
+
#
|
242
|
+
def test_60
|
243
|
+
#{{{
|
244
|
+
assert_nothing_raised do
|
245
|
+
@a.fields = @str_fields
|
246
|
+
end
|
247
|
+
assert_nothing_raised do
|
248
|
+
@a.fill 42, 'zero', 1
|
249
|
+
assert_equal 42, @a[0]
|
250
|
+
end
|
251
|
+
#}}}
|
252
|
+
end
|
253
|
+
def test_61
|
254
|
+
#{{{
|
255
|
+
assert_nothing_raised do
|
256
|
+
@a.fields = @str_fields
|
257
|
+
end
|
258
|
+
assert_nothing_raised do
|
259
|
+
@a.fill 42
|
260
|
+
assert_equal 42, @a[-1]
|
261
|
+
end
|
262
|
+
#}}}
|
263
|
+
end
|
264
|
+
def test_62
|
265
|
+
#{{{
|
266
|
+
assert_nothing_raised do
|
267
|
+
@a.fields = @str_fields
|
268
|
+
end
|
269
|
+
assert_nothing_raised do
|
270
|
+
@a.fill 42, 0...@a.size
|
271
|
+
assert_equal(Array.new(@a.size, 42), @a)
|
272
|
+
end
|
273
|
+
#}}}
|
274
|
+
end
|
275
|
+
#
|
276
|
+
# slice
|
277
|
+
#
|
278
|
+
def test_70
|
279
|
+
#{{{
|
280
|
+
a, b, c = @a[0], @a[1,1].first, @a[2..2].first
|
281
|
+
assert_nothing_raised do
|
282
|
+
@a.fields = @str_fields
|
283
|
+
end
|
284
|
+
assert_nothing_raised do
|
285
|
+
assert_equal a, @a.slice('zero')
|
286
|
+
end
|
287
|
+
assert_nothing_raised do
|
288
|
+
assert_equal b, @a.slice('one')
|
289
|
+
end
|
290
|
+
assert_nothing_raised do
|
291
|
+
assert_equal c, @a.slice('two')
|
292
|
+
end
|
293
|
+
#}}}
|
294
|
+
end
|
295
|
+
#
|
296
|
+
# slice!
|
297
|
+
#
|
298
|
+
def test_80
|
299
|
+
#{{{
|
300
|
+
assert_nothing_raised do
|
301
|
+
@a.fields = @str_fields
|
302
|
+
end
|
303
|
+
assert_nothing_raised do
|
304
|
+
@a.slice! 'zero', @a.size
|
305
|
+
assert_equal @a, []
|
306
|
+
end
|
307
|
+
#}}}
|
308
|
+
end
|
309
|
+
def test_81
|
310
|
+
#{{{
|
311
|
+
assert_nothing_raised do
|
312
|
+
@a.fields = @str_fields
|
313
|
+
end
|
314
|
+
assert_nothing_raised do
|
315
|
+
@a.slice! 0, @a.size
|
316
|
+
assert_equal @a, []
|
317
|
+
end
|
318
|
+
#}}}
|
319
|
+
end
|
320
|
+
if false
|
321
|
+
end
|
322
|
+
#}}}
|
323
|
+
end
|
metadata
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: arrayfields
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 3.5.0
|
7
|
+
date: 2005-11-01 00:00:00.000000 -07:00
|
8
|
+
summary: arrayfields
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: ara.t.howard@noaa.gov
|
12
|
+
homepage: http://codeforpeople.com/lib/ruby/arrayfields/
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire: arrayfields
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: false
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
-
|
22
|
+
- ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.0
|
25
|
+
version:
|
26
|
+
platform: ruby
|
27
|
+
signing_key:
|
28
|
+
cert_chain:
|
29
|
+
authors:
|
30
|
+
- Ara T. Howard
|
31
|
+
files:
|
32
|
+
- lib/arrayfields.rb
|
33
|
+
- lib/arrayfields-3.5.0.rb
|
34
|
+
test_files:
|
35
|
+
- test/arrayfields.rb
|
36
|
+
rdoc_options: []
|
37
|
+
extra_rdoc_files: []
|
38
|
+
executables: []
|
39
|
+
extensions: []
|
40
|
+
requirements: []
|
41
|
+
dependencies: []
|