ThiagoLelis-backgroundjob 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/init.rb CHANGED
@@ -1,33 +1,33 @@
1
- dirname, basename = File.split(File.expand_path(__FILE__))
2
- libdir = File.join dirname, "lib"
3
-
4
- $LOAD_PATH.unshift libdir
5
- begin
6
- require "bj"
7
- ensure
8
- $LOAD_PATH.shift
9
- end
10
-
11
-
12
-
13
- =begin
14
- require "rubygems"
15
-
16
- dir = Gem.dir
17
- path = Gem.path
18
-
19
- dirname, basename = File.split(File.expand_path(__FILE__))
20
- gem_home = File.join dirname, "gem_home"
21
- gem_path = [gem_home] #, *path]
22
-
23
- Gem.send :use_paths, gem_home, gem_path
24
-
25
- begin
26
- %w[ attributes systemu orderedhash bj ].each do |lib|
27
- gem lib
28
- require lib
29
- end
30
- ensure
31
- Gem.send :use_paths, dir, path
32
- end
33
- =end
1
+ dirname, basename = File.split(File.expand_path(__FILE__))
2
+ libdir = File.join dirname, "lib"
3
+
4
+ $LOAD_PATH.unshift libdir
5
+ begin
6
+ require "bj"
7
+ ensure
8
+ $LOAD_PATH.shift
9
+ end
10
+
11
+
12
+
13
+ =begin
14
+ require "rubygems"
15
+
16
+ dir = Gem.dir
17
+ path = Gem.path
18
+
19
+ dirname, basename = File.split(File.expand_path(__FILE__))
20
+ gem_home = File.join dirname, "gem_home"
21
+ gem_path = [gem_home] #, *path]
22
+
23
+ Gem.send :use_paths, gem_home, gem_path
24
+
25
+ begin
26
+ %w[ attributes systemu orderedhash bj ].each do |lib|
27
+ gem lib
28
+ require lib
29
+ end
30
+ ensure
31
+ Gem.send :use_paths, dir, path
32
+ end
33
+ =end
data/install.rb CHANGED
@@ -1,95 +1,95 @@
1
- #! /usr/bin/env ruby
2
-
3
- dirname, basename = File.split File.expand_path(__FILE__)
4
-
5
- libidr = 'lib'
6
- bindir = 'bin'
7
- gem_home = 'gem_home'
8
-
9
- rails_root = File.expand_path File.join(dirname, '../../../')
10
- bj = File.join rails_root, 'script', 'bj'
11
-
12
- gems = %w[ attributes arrayfields main systemu orderedhash bj ]
13
-
14
- # in the plugin dir...
15
- Dir.chdir dirname do
16
- puts "in #{ dirname }..."
17
-
18
- # install gems locally
19
- puts "installing #{ gems.join ' ' }..."
20
- spawn "gem install #{ gems.join ' ' } --install-dir=#{ gem_home } --remote --force --include-dependencies --no-wrappers"
21
- puts "."
22
-
23
- =begin
24
- =end
25
- # copy libs over to libdir
26
- glob = File.join gem_home, "gems/*/lib/*"
27
- entries = Dir.glob glob
28
- entries.each do |entry|
29
- next if entry =~ %r/-\d+\.\d+\.\d+\.rb$/
30
- src, dst = entry, libidr
31
- puts "#{ src } -->> #{ dst }..."
32
- FileUtils.cp_r src, dst
33
- puts "."
34
- end
35
-
36
- # copy bins over to bindir
37
- glob = File.join gem_home, "gems/*/bin/*"
38
- entries = Dir.glob glob
39
- entries.each do |entry|
40
- next if entry =~ %r/-\d+\.\d+\.\d+\.rb$/
41
- src, dst = entry, bindir
42
- puts "#{ src } -->> #{ dst }..."
43
- FileUtils.cp_r src, dst
44
- puts "."
45
- end
46
-
47
- =begin
48
- # copy gem_home/bj-x.x.x/bin/bj to rails_root/script/bj
49
- glob = File.join gem_home, "gems/bj-*/bin/*"
50
- srcs = Dir.glob glob
51
- srcs.each do |src|
52
- basename = File.basename src
53
- dst = File.join rails_root, 'script', basename
54
- puts "#{ src } -->> #{ dst }..."
55
- FileUtils.cp_r src, dst
56
- File.chmod 0755, dst
57
- puts "."
58
- end
59
- =end
60
-
61
- # install bin/bj to script/bj
62
- src, dst = File.join(bindir, "bj"), File.join(rails_root, "script", "bj")
63
- puts "#{ src } -->> #{ dst }..."
64
- FileUtils.cp src, dst
65
- File.chmod 0755, dst
66
- puts "."
67
-
68
- # kill all the local gems
69
- FileUtils.rm_rf gem_home
70
-
71
- # dump help
72
- puts("=" * 79)
73
- ruby = which_ruby
74
- system "#{ ruby } #{ bj.inspect } '--help'"
75
- end
76
-
77
-
78
-
79
- BEGIN {
80
- require 'fileutils'
81
- require 'rbconfig'
82
-
83
- def spawn command
84
- oe = `#{ command } 2>&1`
85
- raise "command <#{ command }> failed with <#{ $?.inspect }>" unless $?.exitstatus == 0
86
- oe
87
- end
88
-
89
- def which_ruby
90
- c = ::Config::CONFIG
91
- ruby = File::join(c['bindir'], c['ruby_install_name']) << c['EXEEXT']
92
- raise "ruby @ #{ ruby } not executable!?" unless test(?e, ruby)
93
- ruby
94
- end
95
- }
1
+ #! /usr/bin/env ruby
2
+
3
+ dirname, basename = File.split File.expand_path(__FILE__)
4
+
5
+ libidr = 'lib'
6
+ bindir = 'bin'
7
+ gem_home = 'gem_home'
8
+
9
+ rails_root = File.expand_path File.join(dirname, '../../../')
10
+ bj = File.join rails_root, 'script', 'bj'
11
+
12
+ gems = %w[ attributes arrayfields main systemu orderedhash bj ]
13
+
14
+ # in the plugin dir...
15
+ Dir.chdir dirname do
16
+ puts "in #{ dirname }..."
17
+
18
+ # install gems locally
19
+ puts "installing #{ gems.join ' ' }..."
20
+ spawn "gem install #{ gems.join ' ' } --install-dir=#{ gem_home } --remote --force --include-dependencies --no-wrappers"
21
+ puts "."
22
+
23
+ =begin
24
+ =end
25
+ # copy libs over to libdir
26
+ glob = File.join gem_home, "gems/*/lib/*"
27
+ entries = Dir.glob glob
28
+ entries.each do |entry|
29
+ next if entry =~ %r/-\d+\.\d+\.\d+\.rb$/
30
+ src, dst = entry, libidr
31
+ puts "#{ src } -->> #{ dst }..."
32
+ FileUtils.cp_r src, dst
33
+ puts "."
34
+ end
35
+
36
+ # copy bins over to bindir
37
+ glob = File.join gem_home, "gems/*/bin/*"
38
+ entries = Dir.glob glob
39
+ entries.each do |entry|
40
+ next if entry =~ %r/-\d+\.\d+\.\d+\.rb$/
41
+ src, dst = entry, bindir
42
+ puts "#{ src } -->> #{ dst }..."
43
+ FileUtils.cp_r src, dst
44
+ puts "."
45
+ end
46
+
47
+ =begin
48
+ # copy gem_home/bj-x.x.x/bin/bj to rails_root/script/bj
49
+ glob = File.join gem_home, "gems/bj-*/bin/*"
50
+ srcs = Dir.glob glob
51
+ srcs.each do |src|
52
+ basename = File.basename src
53
+ dst = File.join rails_root, 'script', basename
54
+ puts "#{ src } -->> #{ dst }..."
55
+ FileUtils.cp_r src, dst
56
+ File.chmod 0755, dst
57
+ puts "."
58
+ end
59
+ =end
60
+
61
+ # install bin/bj to script/bj
62
+ src, dst = File.join(bindir, "bj"), File.join(rails_root, "script", "bj")
63
+ puts "#{ src } -->> #{ dst }..."
64
+ FileUtils.cp src, dst
65
+ File.chmod 0755, dst
66
+ puts "."
67
+
68
+ # kill all the local gems
69
+ FileUtils.rm_rf gem_home
70
+
71
+ # dump help
72
+ puts("=" * 79)
73
+ ruby = which_ruby
74
+ system "#{ ruby } #{ bj.inspect } '--help'"
75
+ end
76
+
77
+
78
+
79
+ BEGIN {
80
+ require 'fileutils'
81
+ require 'rbconfig'
82
+
83
+ def spawn command
84
+ oe = `#{ command } 2>&1`
85
+ raise "command <#{ command }> failed with <#{ $?.inspect }>" unless $?.exitstatus == 0
86
+ oe
87
+ end
88
+
89
+ def which_ruby
90
+ c = ::Config::CONFIG
91
+ ruby = File::join(c['bindir'], c['ruby_install_name']) << c['EXEEXT']
92
+ raise "ruby @ #{ ruby } not executable!?" unless test(?e, ruby)
93
+ ruby
94
+ end
95
+ }
data/lib/arrayfields.rb CHANGED
@@ -1,435 +1,435 @@
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.6.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 *values
312
- return(send('fields=', *values)) unless values.empty?
313
- @fieldset and @fieldset.fields
314
- end
315
- end
316
- #
317
- # Array instances are extened with two methods only: Fieldable#fields= and
318
- # Fieldable#fields. only when Fieldable#fields= is called will the full set
319
- # of ArrayFields methods auto-extend the Array instance. the Array class also
320
- # has added a class generator when the fields are known apriori.
321
- #
322
- class Array
323
- include Fieldable
324
-
325
- class << self
326
- def struct *fields
327
- fields = fields.flatten
328
- Class.new(self) do
329
- include ArrayFields
330
- const_set :FIELDS, ArrayFields::FieldSet.new(fields)
331
- fields.each do |field|
332
- field = field.to_s
333
- if field =~ %r/^[a-zA-Z_][a-zA-Z0-9_]*$/
334
- begin
335
- module_eval <<-code
336
- def #{ field } *a
337
- a.size == 0 ? self['#{ field }'] : (self.#{ field } = a.shift)
338
- end
339
- def #{ field }= value
340
- self['#{ field }'] = value
341
- end
342
- code
343
- rescue SyntaxError
344
- :by_ignoring_it
345
- end
346
- end
347
- end
348
- def initialize *a, &b
349
- super
350
- ensure
351
- @fieldset = self.class.const_get :FIELDS
352
- end
353
- def self.[] *elements
354
- array = new
355
- array.replace elements
356
- array
357
- end
358
- end
359
- end
360
- def fields *fields, &block
361
- (( array = new(&block) )).fields = fields.map{|x| Enumerable === x ? x.to_a : x}.flatten
362
- array
363
- end
364
- end
365
- end
366
- #
367
- # proxy class that allows an array to be wrapped in a way that still allows #
368
- # keyword access. also facilitate usage of ArrayFields with arraylike objects.
369
- # thnx to Sean O'Dell for the suggestion.
370
- #
371
- # sample usage
372
- #
373
- # fa = FieldedArray.new %w(zero one two), [0,1,2]
374
- # p fa['zero'] #=> 0
375
- #
376
- #
377
- class FieldedArray
378
- include Fieldable
379
- class << self
380
- def [](*pairs)
381
- pairs.flatten!
382
- raise ArgumentError, "argument must be key/val pairs" unless
383
- (pairs.size % 2 == 0)
384
- fields, elements = [], []
385
- while((f = pairs.shift) and (e = pairs.shift))
386
- fields << f and elements << e
387
- end
388
- new fields, elements
389
- end
390
- end
391
- def initialize fields = [], array = []
392
- @a = array
393
- self.fields = fields
394
- end
395
- def method_missing(meth, *args, &block)
396
- @a.send(meth, *args, &block)
397
- end
398
- delegates =
399
- %w(
400
- to_s
401
- to_str
402
- inspect
403
- )
404
- delegates.each do |meth|
405
- class_eval "def #{ meth }(*a,&b); @a.#{ meth }(*a,&b);end"
406
- end
407
- end
408
- Fieldedarray = FieldedArray
409
-
410
- class PseudoHash < ::Array
411
- class << self
412
- def [](*pairs)
413
- pairs.flatten!
414
- raise ArgumentError, "argument must be key/val pairs" unless
415
- (pairs.size % 2 == 0 and pairs.size >= 2)
416
- keys, values = [], []
417
- while((k = pairs.shift) and (v = pairs.shift))
418
- keys << k and values << v
419
- end
420
- new keys, values
421
- end
422
- end
423
- def initialize keys = [], values = []
424
- self.fields = keys
425
- self.replace values
426
- end
427
- def to_yaml opts = {}
428
- YAML::quick_emit object_id, opts do |out|
429
- out.map taguri, to_yaml_style do |map|
430
- each_pair{|f,v| map.add f,v}
431
- end
432
- end
433
- end
434
- end
435
- Pseudohash = PseudoHash
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.6.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 *values
312
+ return(send('fields=', *values)) unless values.empty?
313
+ @fieldset and @fieldset.fields
314
+ end
315
+ end
316
+ #
317
+ # Array instances are extened with two methods only: Fieldable#fields= and
318
+ # Fieldable#fields. only when Fieldable#fields= is called will the full set
319
+ # of ArrayFields methods auto-extend the Array instance. the Array class also
320
+ # has added a class generator when the fields are known apriori.
321
+ #
322
+ class Array
323
+ include Fieldable
324
+
325
+ class << self
326
+ def struct *fields
327
+ fields = fields.flatten
328
+ Class.new(self) do
329
+ include ArrayFields
330
+ const_set :FIELDS, ArrayFields::FieldSet.new(fields)
331
+ fields.each do |field|
332
+ field = field.to_s
333
+ if field =~ %r/^[a-zA-Z_][a-zA-Z0-9_]*$/
334
+ begin
335
+ module_eval <<-code
336
+ def #{ field } *a
337
+ a.size == 0 ? self['#{ field }'] : (self.#{ field } = a.shift)
338
+ end
339
+ def #{ field }= value
340
+ self['#{ field }'] = value
341
+ end
342
+ code
343
+ rescue SyntaxError
344
+ :by_ignoring_it
345
+ end
346
+ end
347
+ end
348
+ def initialize *a, &b
349
+ super
350
+ ensure
351
+ @fieldset = self.class.const_get :FIELDS
352
+ end
353
+ def self.[] *elements
354
+ array = new
355
+ array.replace elements
356
+ array
357
+ end
358
+ end
359
+ end
360
+ def fields *fields, &block
361
+ (( array = new(&block) )).fields = fields.map{|x| Enumerable === x ? x.to_a : x}.flatten
362
+ array
363
+ end
364
+ end
365
+ end
366
+ #
367
+ # proxy class that allows an array to be wrapped in a way that still allows #
368
+ # keyword access. also facilitate usage of ArrayFields with arraylike objects.
369
+ # thnx to Sean O'Dell for the suggestion.
370
+ #
371
+ # sample usage
372
+ #
373
+ # fa = FieldedArray.new %w(zero one two), [0,1,2]
374
+ # p fa['zero'] #=> 0
375
+ #
376
+ #
377
+ class FieldedArray
378
+ include Fieldable
379
+ class << self
380
+ def [](*pairs)
381
+ pairs.flatten!
382
+ raise ArgumentError, "argument must be key/val pairs" unless
383
+ (pairs.size % 2 == 0)
384
+ fields, elements = [], []
385
+ while((f = pairs.shift) and (e = pairs.shift))
386
+ fields << f and elements << e
387
+ end
388
+ new fields, elements
389
+ end
390
+ end
391
+ def initialize fields = [], array = []
392
+ @a = array
393
+ self.fields = fields
394
+ end
395
+ def method_missing(meth, *args, &block)
396
+ @a.send(meth, *args, &block)
397
+ end
398
+ delegates =
399
+ %w(
400
+ to_s
401
+ to_str
402
+ inspect
403
+ )
404
+ delegates.each do |meth|
405
+ class_eval "def #{ meth }(*a,&b); @a.#{ meth }(*a,&b);end"
406
+ end
407
+ end
408
+ Fieldedarray = FieldedArray
409
+
410
+ class PseudoHash < ::Array
411
+ class << self
412
+ def [](*pairs)
413
+ pairs.flatten!
414
+ raise ArgumentError, "argument must be key/val pairs" unless
415
+ (pairs.size % 2 == 0 and pairs.size >= 2)
416
+ keys, values = [], []
417
+ while((k = pairs.shift) and (v = pairs.shift))
418
+ keys << k and values << v
419
+ end
420
+ new keys, values
421
+ end
422
+ end
423
+ def initialize keys = [], values = []
424
+ self.fields = keys
425
+ self.replace values
426
+ end
427
+ def to_yaml opts = {}
428
+ YAML::quick_emit object_id, opts do |out|
429
+ out.map taguri, to_yaml_style do |map|
430
+ each_pair{|f,v| map.add f,v}
431
+ end
432
+ end
433
+ end
434
+ end
435
+ Pseudohash = PseudoHash