arrayfields 3.6.0 → 3.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 extend
4
- # Array's - they are auto-extended when Array#fields= is called
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 = '3.6.0'
8
+ VERSION = '3.7.0' unless defined? 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
- @sets ||= {}
19
- obj = @sets[fields]
20
- unless obj
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,20 @@
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 [](idx, *args)
64
- #{{{
54
+ def [] idx, *args
65
55
  if @fieldset and (String === idx or Symbol === idx)
66
56
  pos = @fieldset.pos idx
67
57
  return nil unless pos
@@ -69,11 +59,18 @@
69
59
  else
70
60
  super
71
61
  end
72
- #}}}
73
62
  end
74
- alias slice []
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
+
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
- alias indices values_at
133
- alias indexes values_at
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
157
  def each_value(*args, &block)
164
- #{{{
165
158
  each(*args, &block)
166
- #}}}
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
- alias member? has_key?
179
- alias key? has_key?
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
- alias value? has_value?
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,39 +218,42 @@
223
218
  @fieldset.fields.zip(a){|f,e| h[f] = e}
224
219
  h
225
220
  end
226
- #}}}
227
221
  end
228
- alias to_h to_hash
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
246
  end
247
247
  #
248
248
  # Fieldable encapsulates methods in common for classes which may have their
249
- # fields set
249
+ # fields set and subsequently be auto-extended by ArrayFields
250
250
  #
251
251
  module Fieldable
252
- #{{{
253
252
  #
254
253
  # sets fields an dynamically extends this Array instance with methods for
255
254
  # keyword access
256
255
  #
257
256
  def fields= fields
258
- #{{{
259
257
  extend ArrayFields unless defined? @fieldset
260
258
 
261
259
  @fieldset =
@@ -264,7 +262,6 @@
264
262
  else
265
263
  ArrayFields::FieldSet.new fields
266
264
  end
267
- #}}}
268
265
  end
269
266
  #
270
267
  # access to fieldset
@@ -274,19 +271,32 @@
274
271
  # access to field list
275
272
  #
276
273
  def fields
277
- #{{{
278
274
  @fieldset and @fieldset.fields
279
- #}}}
280
275
  end
281
- #}}}
282
276
  end
283
277
  #
284
- # The Array class is extened with a methods to allow keyword access
278
+ # Array instances are extened with two methods only: Fieldable#fields= and
279
+ # Fieldable#fields. only when Fieldable#fields= is called will the full set
280
+ # of ArrayFields methods auto-extend the Array instance. the Array class also
281
+ # has added a class generator when the fields are known apriori.
285
282
  #
286
283
  class Array
287
- #{{{
288
284
  include Fieldable
289
- #}}}
285
+
286
+ class << self
287
+ def fields *fields
288
+ Class.new(self) do
289
+ const_set :FIELDS, ArrayFields::FieldSet.new(fields.flatten)
290
+ include ArrayFields
291
+ def initialize *a, &b
292
+ super
293
+ ensure
294
+ @fieldset = self.class.const_get :FIELDS
295
+ end
296
+ end
297
+ end
298
+ alias_method 'struct', 'fields'
299
+ end
290
300
  end
291
301
  #
292
302
  # proxy class that allows an array to be wrapped in a way that still allows #
@@ -300,48 +310,59 @@
300
310
  #
301
311
  #
302
312
  class FieldedArray
303
- #{{{
304
313
  include Fieldable
305
314
  class << self
306
-
307
315
  def [](*pairs)
308
- #{{{
309
316
  pairs.flatten!
310
- raise ArgumentError, "argument must be key/val paris" unless
317
+ raise ArgumentError, "argument must be key/val pairs" unless
311
318
  (pairs.size % 2 == 0 and pairs.size >= 2)
312
319
  fields, elements = [], []
313
- #pairs.each do |f,e|
314
320
  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
321
  fields << f and elements << e
318
322
  end
319
323
  new fields, elements
320
- #}}}
321
324
  end
322
-
323
325
  end
324
- def initialize fields, array
325
- #{{{
326
+ def initialize fields = [], array = []
326
327
  @a = array
327
328
  self.fields = fields
328
- #}}}
329
329
  end
330
330
  def method_missing(meth, *args, &block)
331
- #{{{
332
331
  @a.send(meth, *args, &block)
333
- #}}}
334
332
  end
335
333
  delegates =
336
- #{{{
337
334
  %w(
338
335
  to_s
339
336
  to_str
340
337
  inspect
341
338
  )
342
- #}}}
343
339
  delegates.each do |meth|
344
340
  class_eval "def #{ meth }(*a,&b); @a.#{ meth }(*a,&b);end"
345
341
  end
346
- #}}}
342
+ end
343
+
344
+ class PseudoHash < ::Array
345
+ class << self
346
+ def [](*pairs)
347
+ pairs.flatten!
348
+ raise ArgumentError, "argument must be key/val pairs" unless
349
+ (pairs.size % 2 == 0 and pairs.size >= 2)
350
+ keys, values = [], []
351
+ while((k = pairs.shift) and (v = pairs.shift))
352
+ keys << k and values << v
353
+ end
354
+ new keys, values
355
+ end
356
+ end
357
+ def initialize keys = [], values = []
358
+ self.replace values
359
+ self.fields = keys
360
+ end
361
+ def to_yaml opts = {}
362
+ YAML::quick_emit object_id, opts do |out|
363
+ out.map taguri, to_yaml_style do |map|
364
+ each_pair{|f,v| map.add f,v}
365
+ end
366
+ end
367
+ end
347
368
  end
@@ -1,11 +1,4 @@
1
- #
2
- # you must require the arrayfields package
3
- #
4
- $:.unshift 'lib'
5
- $:.unshift '../lib'
6
- $:.unshift '.'
7
- require 'arrayfields'
8
-
1
+ require 'arrayfields'
9
2
  #
10
3
  # the class Array has only a few added method, one is for setting the fields,
11
4
  # when the fields are set for an array THIS INSTANCE ONLY will be modified to
@@ -46,21 +39,3 @@
46
39
 
47
40
  a.slice! 'two', 2
48
41
  p a #=> [0,1]
49
-
50
- __END__
51
-
52
- the expected output of this program :
53
-
54
- 0
55
- 1
56
- 2
57
- 1
58
- [0, 2]
59
- 42
60
- "zero,one,two"
61
- nil
62
- "zero,one,two,three"
63
- 3
64
- [42, 42, 42, 42]
65
- [0, 1]
66
-