array-hooked 1.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/CHANGELOG.rdoc +12 -0
- data/README.md +59 -0
- data/lib/array-hooked.rb +2 -0
- data/lib/array/hooked.rb +43 -0
- data/lib/array/hooked/array_interface.rb +1233 -0
- data/lib/array/namespaces.rb +6 -0
- data/lib/array/requires.rb +27 -0
- data/lib/hooked/array.rb +2 -0
- data/lib/hooked_array.rb +6 -0
- data/lib/hooked_array/array_interface.rb +29 -0
- data/spec/array/hooked_spec.rb +758 -0
- data/spec/hooked_array_spec.rb +13 -0
- metadata +74 -0
data/CHANGELOG.rdoc
ADDED
data/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# Hooked Array #
|
2
|
+
|
3
|
+
http://rubygems.org/gems/array-hooked
|
4
|
+
|
5
|
+
# Description #
|
6
|
+
|
7
|
+
Provides ::Array::Hooked and ::HookedArray.
|
8
|
+
|
9
|
+
# Summary #
|
10
|
+
|
11
|
+
A subclass of Array that offers event hooks for pre-insert/pre-set/pre-delete, insert/set/delete. ::HookedArray offers implicit reference to a configuration instance.
|
12
|
+
|
13
|
+
# Install #
|
14
|
+
|
15
|
+
* sudo gem install array-hooked
|
16
|
+
|
17
|
+
# Usage #
|
18
|
+
|
19
|
+
Provides methods that can be overridden that will be called during every corresponding event:
|
20
|
+
|
21
|
+
* pre_set_hook
|
22
|
+
* post_set_hook
|
23
|
+
* pre_get_hook
|
24
|
+
* post_get_hook
|
25
|
+
* pre_delete_hook
|
26
|
+
* post_delete_hook
|
27
|
+
|
28
|
+
As a result, several internal perform methods have been created:
|
29
|
+
|
30
|
+
* perform_set_between_hooks
|
31
|
+
* perform_insert_between_hooks
|
32
|
+
* perform_delete_between_hooks
|
33
|
+
|
34
|
+
Also provides methods corresponding to each already-existing method + '_without_hooks', which causes methods to bypass hooks.
|
35
|
+
|
36
|
+
# License #
|
37
|
+
|
38
|
+
(The MIT License)
|
39
|
+
|
40
|
+
Copyright (c) Asher
|
41
|
+
|
42
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
43
|
+
a copy of this software and associated documentation files (the
|
44
|
+
'Software'), to deal in the Software without restriction, including
|
45
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
46
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
47
|
+
permit persons to whom the Software is furnished to do so, subject to
|
48
|
+
the following conditions:
|
49
|
+
|
50
|
+
The above copyright notice and this permission notice shall be
|
51
|
+
included in all copies or substantial portions of the Software.
|
52
|
+
|
53
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
54
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
55
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
56
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
57
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
58
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
59
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/lib/array-hooked.rb
ADDED
data/lib/array/hooked.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+
require 'identifies_as'
|
3
|
+
|
4
|
+
# namespaces that have to be declared ahead of time for proper load order
|
5
|
+
require_relative './namespaces'
|
6
|
+
|
7
|
+
# source file requires
|
8
|
+
require_relative './requires.rb'
|
9
|
+
|
10
|
+
class ::Array::Hooked < ::Array
|
11
|
+
|
12
|
+
###############################
|
13
|
+
# perform_set_between_hooks #
|
14
|
+
###############################
|
15
|
+
|
16
|
+
# Alias to original :[]= method. Used to perform actual set between hooks.
|
17
|
+
# @param [Fixnum] index Index at which set is taking place.
|
18
|
+
# @param [Object] object Element being set.
|
19
|
+
# @return [Object] Element returned.
|
20
|
+
alias_method :perform_set_between_hooks, :[]=
|
21
|
+
|
22
|
+
##################################
|
23
|
+
# perform_insert_between_hooks #
|
24
|
+
##################################
|
25
|
+
|
26
|
+
# Alias to original :insert method. Used to perform actual insert between hooks.
|
27
|
+
# @param [Fixnum] index Index at which insert is taking place.
|
28
|
+
# @param [Array<Object>] objects Elements being inserted.
|
29
|
+
# @return [Object] Element returned.
|
30
|
+
alias_method :perform_insert_between_hooks, :insert
|
31
|
+
|
32
|
+
##################################
|
33
|
+
# perform_delete_between_hooks #
|
34
|
+
##################################
|
35
|
+
|
36
|
+
# Alias to original :delete method. Used to perform actual delete between hooks.
|
37
|
+
# @param [Fixnum] index Index at which delete is taking place.
|
38
|
+
# @return [Object] Element returned.
|
39
|
+
alias_method :perform_delete_between_hooks, :delete_at
|
40
|
+
|
41
|
+
include ::Array::Hooked::ArrayInterface
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,1233 @@
|
|
1
|
+
|
2
|
+
module ::Array::Hooked::ArrayInterface
|
3
|
+
|
4
|
+
instances_identify_as!( ::Array::Hooked )
|
5
|
+
|
6
|
+
###################################### Subclass Hooks ##########################################
|
7
|
+
|
8
|
+
##################
|
9
|
+
# pre_set_hook #
|
10
|
+
##################
|
11
|
+
|
12
|
+
# A hook that is called before setting a value; return value is used in place of object.
|
13
|
+
# @param [Fixnum] index Index at which set/insert is taking place.
|
14
|
+
# @param [Object] object Element being set/inserted.
|
15
|
+
# @param [true,false] is_insert Whether this set is inserting a new index.
|
16
|
+
# @return [true,false] Return value is used in place of object.
|
17
|
+
def pre_set_hook( index, object, is_insert = false )
|
18
|
+
|
19
|
+
return object
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
###################
|
24
|
+
# post_set_hook #
|
25
|
+
###################
|
26
|
+
|
27
|
+
# A hook that is called after setting a value.
|
28
|
+
# @param [Fixnum] index Index at which set/insert is taking place.
|
29
|
+
# @param [Object] object Element being set/inserted.
|
30
|
+
# @param [true,false] is_insert Whether this set is inserting a new index.
|
31
|
+
# @return [Object] Ignored.
|
32
|
+
def post_set_hook( index, object, is_insert = false )
|
33
|
+
|
34
|
+
return object
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
##################
|
39
|
+
# pre_get_hook #
|
40
|
+
##################
|
41
|
+
|
42
|
+
# A hook that is called before getting a value; if return value is false, get does not occur.
|
43
|
+
# @param [Fixnum] index Index at which set/insert is taking place.
|
44
|
+
# @return [true,false] If return value is false, get does not occur.
|
45
|
+
def pre_get_hook( index )
|
46
|
+
|
47
|
+
# false means get does not take place
|
48
|
+
return true
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
###################
|
53
|
+
# post_get_hook #
|
54
|
+
###################
|
55
|
+
|
56
|
+
# A hook that is called after getting a value.
|
57
|
+
# @param [Fixnum] index Index at which get is taking place.
|
58
|
+
# @param [Object] object Element being set/inserted.
|
59
|
+
# @return [Object] Object returned in place of get result.
|
60
|
+
def post_get_hook( index, object )
|
61
|
+
|
62
|
+
return object
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
#####################
|
67
|
+
# pre_delete_hook #
|
68
|
+
#####################
|
69
|
+
|
70
|
+
# A hook that is called before deleting a value; if return value is false, delete does not occur.
|
71
|
+
# @param [Fixnum] index Index at which delete is taking place.
|
72
|
+
# @return [true,false] If return value is false, delete does not occur.
|
73
|
+
def pre_delete_hook( index )
|
74
|
+
|
75
|
+
# false means delete does not take place
|
76
|
+
return true
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
######################
|
81
|
+
# post_delete_hook #
|
82
|
+
######################
|
83
|
+
|
84
|
+
# A hook that is called after deleting a value.
|
85
|
+
# @param [Fixnum] index Index at which delete took place.
|
86
|
+
# @param [Object] object Element deleted.
|
87
|
+
# @return [Object] Object returned in place of delete result.
|
88
|
+
def post_delete_hook( index, object )
|
89
|
+
|
90
|
+
return object
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
##################################### Self Management ##########################################
|
95
|
+
|
96
|
+
########
|
97
|
+
# [] #
|
98
|
+
########
|
99
|
+
|
100
|
+
def []( index )
|
101
|
+
|
102
|
+
object = nil
|
103
|
+
|
104
|
+
should_get = true
|
105
|
+
|
106
|
+
unless @without_hooks
|
107
|
+
should_get = pre_get_hook( index )
|
108
|
+
end
|
109
|
+
|
110
|
+
if should_get
|
111
|
+
|
112
|
+
object = super( index )
|
113
|
+
|
114
|
+
unless @without_hooks
|
115
|
+
object = post_get_hook( index, object )
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
return object
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
#######################
|
125
|
+
# get_without_hooks #
|
126
|
+
#######################
|
127
|
+
|
128
|
+
# Alias to :[] that bypasses hooks.
|
129
|
+
# @param [Fixnum] index Index at which set is taking place.
|
130
|
+
# @return [Object] Element returned.
|
131
|
+
def get_without_hooks( index )
|
132
|
+
|
133
|
+
@without_hooks = true
|
134
|
+
|
135
|
+
self[ index ] = object
|
136
|
+
|
137
|
+
@without_hooks = false
|
138
|
+
|
139
|
+
return object
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
#########
|
144
|
+
# []= #
|
145
|
+
#########
|
146
|
+
|
147
|
+
def []=( index, object )
|
148
|
+
|
149
|
+
# we are either replacing or adding at the end
|
150
|
+
# if we are replacing we are either replacing a parent element or an element in self
|
151
|
+
# * if replacing parent element, track and exclude parent changes
|
152
|
+
|
153
|
+
unless @without_hooks
|
154
|
+
object = pre_set_hook( index, object, false )
|
155
|
+
end
|
156
|
+
|
157
|
+
perform_set_between_hooks( index, object )
|
158
|
+
|
159
|
+
unless @without_hooks
|
160
|
+
object = post_set_hook( index, object, false )
|
161
|
+
end
|
162
|
+
|
163
|
+
return object
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
#######################
|
168
|
+
# set_without_hooks #
|
169
|
+
#######################
|
170
|
+
|
171
|
+
# Alias to :[]= that bypasses hooks.
|
172
|
+
# @param [Fixnum] index Index at which set is taking place.
|
173
|
+
# @param [Object] object Element being set.
|
174
|
+
# @return [Object] Element returned.
|
175
|
+
def set_without_hooks( index, object )
|
176
|
+
|
177
|
+
@without_hooks = true
|
178
|
+
|
179
|
+
self[ index ] = object
|
180
|
+
|
181
|
+
@without_hooks = false
|
182
|
+
|
183
|
+
return object
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
############
|
188
|
+
# insert #
|
189
|
+
############
|
190
|
+
|
191
|
+
def insert( index, *objects )
|
192
|
+
|
193
|
+
objects_to_insert = nil
|
194
|
+
if @without_hooks
|
195
|
+
objects_to_insert = objects
|
196
|
+
else
|
197
|
+
objects_to_insert = [ ]
|
198
|
+
objects.each_with_index do |this_object, this_index|
|
199
|
+
this_insert_index = index + this_index
|
200
|
+
this_object = pre_set_hook( this_insert_index, this_object, true )
|
201
|
+
objects_to_insert.push( this_object )
|
202
|
+
end
|
203
|
+
end
|
204
|
+
objects = objects_to_insert
|
205
|
+
|
206
|
+
# if we have less elements in self than the index we are inserting at
|
207
|
+
# we need to make sure the nils inserted cascade
|
208
|
+
if index > count
|
209
|
+
nils_created = index - count
|
210
|
+
index -= nils_created
|
211
|
+
nils = [ ]
|
212
|
+
nils_created.times do |this_time|
|
213
|
+
nils.push( nil )
|
214
|
+
end
|
215
|
+
objects = nils.concat( objects )
|
216
|
+
end
|
217
|
+
|
218
|
+
perform_insert_between_hooks( index, *objects )
|
219
|
+
|
220
|
+
unless @without_hooks
|
221
|
+
objects.each_with_index do |this_object, this_index|
|
222
|
+
objects[ this_index ] = post_set_hook( index + this_index, this_object, true )
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
return objects
|
227
|
+
|
228
|
+
end
|
229
|
+
|
230
|
+
##########################
|
231
|
+
# insert_without_hooks #
|
232
|
+
##########################
|
233
|
+
|
234
|
+
# Alias to :insert that bypasses hooks.
|
235
|
+
# @param [Fixnum] index Index at which set is taking place.
|
236
|
+
# @param [Array<Object>] objects Elements being inserted.
|
237
|
+
# @return [Object] Element returned.
|
238
|
+
def insert_without_hooks( index, *objects )
|
239
|
+
|
240
|
+
@without_hooks = true
|
241
|
+
|
242
|
+
super( index, *objects )
|
243
|
+
|
244
|
+
@without_hooks = false
|
245
|
+
|
246
|
+
return objects
|
247
|
+
|
248
|
+
end
|
249
|
+
|
250
|
+
##########
|
251
|
+
# push #
|
252
|
+
##########
|
253
|
+
|
254
|
+
def push( *objects )
|
255
|
+
|
256
|
+
return insert( count, *objects )
|
257
|
+
|
258
|
+
end
|
259
|
+
|
260
|
+
alias_method :<<, :push
|
261
|
+
|
262
|
+
########################
|
263
|
+
# push_without_hooks #
|
264
|
+
########################
|
265
|
+
|
266
|
+
# Alias to :push that bypasses hooks.
|
267
|
+
# @param [Array<Object>] objects Elements being pushed.
|
268
|
+
# @return [Object] Element returned.
|
269
|
+
def push_without_hooks( *objects )
|
270
|
+
|
271
|
+
@without_hooks = true
|
272
|
+
|
273
|
+
push( *objects )
|
274
|
+
|
275
|
+
@without_hooks = false
|
276
|
+
|
277
|
+
return objects
|
278
|
+
|
279
|
+
end
|
280
|
+
|
281
|
+
############
|
282
|
+
# concat #
|
283
|
+
############
|
284
|
+
|
285
|
+
def concat( *arrays )
|
286
|
+
|
287
|
+
arrays.each do |this_array|
|
288
|
+
push( *this_array )
|
289
|
+
end
|
290
|
+
|
291
|
+
return self
|
292
|
+
|
293
|
+
end
|
294
|
+
|
295
|
+
alias_method :+, :concat
|
296
|
+
|
297
|
+
##########################
|
298
|
+
# concat_without_hooks #
|
299
|
+
##########################
|
300
|
+
|
301
|
+
# Alias to :concat that bypasses hooks.
|
302
|
+
# @param [Array<Object>] objects Elements being concatenated.
|
303
|
+
# @return [Object] Element returned.
|
304
|
+
def concat_without_hooks( *arrays )
|
305
|
+
|
306
|
+
@without_hooks = true
|
307
|
+
|
308
|
+
concat( *arrays )
|
309
|
+
|
310
|
+
@without_hooks = false
|
311
|
+
|
312
|
+
return arrays
|
313
|
+
|
314
|
+
end
|
315
|
+
|
316
|
+
############
|
317
|
+
# delete #
|
318
|
+
############
|
319
|
+
|
320
|
+
def delete( object )
|
321
|
+
|
322
|
+
return_value = nil
|
323
|
+
|
324
|
+
if index = index( object )
|
325
|
+
return_value = delete_at( index )
|
326
|
+
end
|
327
|
+
|
328
|
+
return return_value
|
329
|
+
|
330
|
+
end
|
331
|
+
|
332
|
+
##########################
|
333
|
+
# delete_without_hooks #
|
334
|
+
##########################
|
335
|
+
|
336
|
+
# Alias to :delete that bypasses hooks.
|
337
|
+
# @param [Object] object Element being deleted.
|
338
|
+
# @return [Object] Element returned.
|
339
|
+
def delete_without_hooks( object )
|
340
|
+
|
341
|
+
@without_hooks = true
|
342
|
+
|
343
|
+
return_value = delete( object )
|
344
|
+
|
345
|
+
@without_hooks = false
|
346
|
+
|
347
|
+
return return_value
|
348
|
+
|
349
|
+
end
|
350
|
+
|
351
|
+
####################
|
352
|
+
# delete_objects #
|
353
|
+
####################
|
354
|
+
|
355
|
+
def delete_objects( *objects )
|
356
|
+
|
357
|
+
return_value = nil
|
358
|
+
|
359
|
+
indexes = [ ]
|
360
|
+
objects.each do |this_object|
|
361
|
+
this_index = index( this_object )
|
362
|
+
if this_index
|
363
|
+
indexes.push( this_index )
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
unless indexes.empty?
|
368
|
+
return_value = delete_at_indexes( *indexes )
|
369
|
+
end
|
370
|
+
|
371
|
+
return return_value
|
372
|
+
|
373
|
+
end
|
374
|
+
|
375
|
+
##################################
|
376
|
+
# delete_objects_without_hooks #
|
377
|
+
##################################
|
378
|
+
|
379
|
+
# Alias to :delete that bypasses hooks and takes multiple objects.
|
380
|
+
# @param [Array<Object>] objects Elements being deleted.
|
381
|
+
# @return [Object] Element returned.
|
382
|
+
def delete_objects_without_hooks( *objects )
|
383
|
+
|
384
|
+
@without_hooks = true
|
385
|
+
|
386
|
+
return_value = delete_objects( *objects )
|
387
|
+
|
388
|
+
@without_hooks = false
|
389
|
+
|
390
|
+
return return_value
|
391
|
+
|
392
|
+
end
|
393
|
+
|
394
|
+
#######
|
395
|
+
# - #
|
396
|
+
#######
|
397
|
+
|
398
|
+
def -( *arrays )
|
399
|
+
|
400
|
+
arrays.each do |this_array|
|
401
|
+
delete_objects( *this_array )
|
402
|
+
end
|
403
|
+
|
404
|
+
return self
|
405
|
+
|
406
|
+
end
|
407
|
+
|
408
|
+
###############
|
409
|
+
# delete_at #
|
410
|
+
###############
|
411
|
+
|
412
|
+
def delete_at( index )
|
413
|
+
|
414
|
+
deleted_object = nil
|
415
|
+
|
416
|
+
if @without_hooks
|
417
|
+
pre_delete_hook_result = true
|
418
|
+
else
|
419
|
+
pre_delete_hook_result = pre_delete_hook( index )
|
420
|
+
end
|
421
|
+
|
422
|
+
if pre_delete_hook_result
|
423
|
+
|
424
|
+
deleted_object = perform_delete_between_hooks( index )
|
425
|
+
|
426
|
+
unless @without_hooks
|
427
|
+
deleted_object = post_delete_hook( index, deleted_object )
|
428
|
+
end
|
429
|
+
|
430
|
+
end
|
431
|
+
|
432
|
+
return deleted_object
|
433
|
+
|
434
|
+
end
|
435
|
+
|
436
|
+
#############################
|
437
|
+
# delete_at_without_hooks #
|
438
|
+
#############################
|
439
|
+
|
440
|
+
# Alias to :delete_at that bypasses hooks.
|
441
|
+
# @param [Fixnum] index Index to delete.
|
442
|
+
# @return [Object] Deleted element.
|
443
|
+
def delete_at_without_hooks( index )
|
444
|
+
|
445
|
+
@without_hooks = true
|
446
|
+
|
447
|
+
object = delete_at( index )
|
448
|
+
|
449
|
+
@without_hooks = false
|
450
|
+
|
451
|
+
return object
|
452
|
+
|
453
|
+
end
|
454
|
+
|
455
|
+
#######################
|
456
|
+
# delete_at_indexes #
|
457
|
+
#######################
|
458
|
+
|
459
|
+
def delete_at_indexes( *indexes )
|
460
|
+
|
461
|
+
indexes = indexes.sort.uniq.reverse
|
462
|
+
|
463
|
+
objects = [ ]
|
464
|
+
|
465
|
+
indexes.each do |this_index|
|
466
|
+
objects.push( delete_at( this_index ) )
|
467
|
+
end
|
468
|
+
|
469
|
+
return objects
|
470
|
+
|
471
|
+
end
|
472
|
+
|
473
|
+
#####################################
|
474
|
+
# delete_at_indexes_without_hooks #
|
475
|
+
#####################################
|
476
|
+
|
477
|
+
# Alias to :delete_at that bypasses hooks and takes multiple indexes.
|
478
|
+
# @param [Array<Fixnum>] index Index to delete.
|
479
|
+
# @return [Object] Deleted element.
|
480
|
+
def delete_at_indexes_without_hooks( *indexes )
|
481
|
+
|
482
|
+
@without_hooks = true
|
483
|
+
|
484
|
+
objects = delete_at_indexes( *indexes )
|
485
|
+
|
486
|
+
@without_hooks = false
|
487
|
+
|
488
|
+
return objects
|
489
|
+
|
490
|
+
end
|
491
|
+
|
492
|
+
###############
|
493
|
+
# delete_if #
|
494
|
+
###############
|
495
|
+
|
496
|
+
def delete_if
|
497
|
+
|
498
|
+
return to_enum unless block_given?
|
499
|
+
|
500
|
+
indexes = [ ]
|
501
|
+
|
502
|
+
self.each_with_index do |this_object, index|
|
503
|
+
if yield( this_object )
|
504
|
+
indexes.push( index )
|
505
|
+
end
|
506
|
+
end
|
507
|
+
|
508
|
+
delete_at_indexes( *indexes )
|
509
|
+
|
510
|
+
return self
|
511
|
+
|
512
|
+
end
|
513
|
+
|
514
|
+
#############################
|
515
|
+
# delete_if_without_hooks #
|
516
|
+
#############################
|
517
|
+
|
518
|
+
# Alias to :delete_if that bypasses hooks.
|
519
|
+
# @yield Block passed to :delete_if.
|
520
|
+
# @return [Object] Deleted element.
|
521
|
+
def delete_if_without_hooks( & block )
|
522
|
+
|
523
|
+
@without_hooks = true
|
524
|
+
|
525
|
+
delete_if( & block )
|
526
|
+
|
527
|
+
@without_hooks = false
|
528
|
+
|
529
|
+
return self
|
530
|
+
|
531
|
+
end
|
532
|
+
|
533
|
+
#############
|
534
|
+
# keep_if #
|
535
|
+
#############
|
536
|
+
|
537
|
+
def keep_if
|
538
|
+
|
539
|
+
indexes = [ ]
|
540
|
+
|
541
|
+
self.each_with_index do |this_object, index|
|
542
|
+
unless yield( this_object )
|
543
|
+
indexes.push( index )
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
delete_at_indexes( *indexes )
|
548
|
+
|
549
|
+
return self
|
550
|
+
|
551
|
+
end
|
552
|
+
|
553
|
+
###########################
|
554
|
+
# keep_if_without_hooks #
|
555
|
+
###########################
|
556
|
+
|
557
|
+
# Alias to :keep_if that bypasses hooks.
|
558
|
+
# @yield Block passed to :keep_if.
|
559
|
+
# @return [Object] Deleted element.
|
560
|
+
def keep_if_without_hooks( & block )
|
561
|
+
|
562
|
+
@without_hooks = true
|
563
|
+
|
564
|
+
keep_if( & block )
|
565
|
+
|
566
|
+
@without_hooks = false
|
567
|
+
|
568
|
+
return self
|
569
|
+
|
570
|
+
end
|
571
|
+
|
572
|
+
##############
|
573
|
+
# compact! #
|
574
|
+
##############
|
575
|
+
|
576
|
+
def compact!
|
577
|
+
|
578
|
+
return keep_if do |object|
|
579
|
+
object != nil
|
580
|
+
end
|
581
|
+
|
582
|
+
end
|
583
|
+
|
584
|
+
############################
|
585
|
+
# compact_without_hooks! #
|
586
|
+
############################
|
587
|
+
|
588
|
+
# Alias to :compact that bypasses hooks.
|
589
|
+
# @return [Object] Self.
|
590
|
+
def compact_without_hooks!
|
591
|
+
|
592
|
+
@without_hooks = true
|
593
|
+
|
594
|
+
compact!
|
595
|
+
|
596
|
+
@without_hooks = false
|
597
|
+
|
598
|
+
return self
|
599
|
+
|
600
|
+
end
|
601
|
+
|
602
|
+
##############
|
603
|
+
# flatten! #
|
604
|
+
##############
|
605
|
+
|
606
|
+
def flatten!
|
607
|
+
|
608
|
+
return_value = nil
|
609
|
+
|
610
|
+
indexes = [ ]
|
611
|
+
|
612
|
+
self.each_with_index do |this_object, index|
|
613
|
+
if this_object.is_a?( Array )
|
614
|
+
indexes.push( index )
|
615
|
+
end
|
616
|
+
end
|
617
|
+
|
618
|
+
unless indexes.empty?
|
619
|
+
indexes.sort!.reverse!
|
620
|
+
indexes.each do |this_index|
|
621
|
+
this_array = delete_at( this_index )
|
622
|
+
insert( this_index, *this_array )
|
623
|
+
end
|
624
|
+
return_value = self
|
625
|
+
end
|
626
|
+
|
627
|
+
return return_value
|
628
|
+
|
629
|
+
end
|
630
|
+
|
631
|
+
############################
|
632
|
+
# flatten_without_hooks! #
|
633
|
+
############################
|
634
|
+
|
635
|
+
# Alias to :flatten that bypasses hooks.
|
636
|
+
# @return [Object] Self.
|
637
|
+
def flatten_without_hooks!
|
638
|
+
|
639
|
+
@without_hooks = true
|
640
|
+
|
641
|
+
return_value = flatten!
|
642
|
+
|
643
|
+
@without_hooks = false
|
644
|
+
|
645
|
+
return return_value
|
646
|
+
|
647
|
+
end
|
648
|
+
|
649
|
+
#############
|
650
|
+
# reject! #
|
651
|
+
#############
|
652
|
+
|
653
|
+
def reject!
|
654
|
+
|
655
|
+
return to_enum unless block_given?
|
656
|
+
|
657
|
+
return_value = nil
|
658
|
+
|
659
|
+
deleted_objects = 0
|
660
|
+
|
661
|
+
iteration_dup = dup
|
662
|
+
iteration_dup.each_with_index do |this_object, index|
|
663
|
+
if yield( this_object )
|
664
|
+
delete_at( index - deleted_objects )
|
665
|
+
deleted_objects += 1
|
666
|
+
end
|
667
|
+
end
|
668
|
+
|
669
|
+
if deleted_objects > 0
|
670
|
+
return_value = self
|
671
|
+
end
|
672
|
+
|
673
|
+
return return_value
|
674
|
+
|
675
|
+
end
|
676
|
+
|
677
|
+
###########################
|
678
|
+
# reject_without_hooks! #
|
679
|
+
###########################
|
680
|
+
|
681
|
+
# Alias to :reject that bypasses hooks.
|
682
|
+
# @yield Block passed to :keep_if.
|
683
|
+
# @return [Object] Self.
|
684
|
+
def reject_without_hooks!( & block )
|
685
|
+
|
686
|
+
@without_hooks = true
|
687
|
+
|
688
|
+
reject!( & block )
|
689
|
+
|
690
|
+
@without_hooks = false
|
691
|
+
|
692
|
+
return return_value
|
693
|
+
|
694
|
+
end
|
695
|
+
|
696
|
+
#############
|
697
|
+
# replace #
|
698
|
+
#############
|
699
|
+
|
700
|
+
def replace( other_array )
|
701
|
+
|
702
|
+
clear
|
703
|
+
|
704
|
+
other_array.each_with_index do |this_object, index|
|
705
|
+
unless self[ index ] == this_object
|
706
|
+
self[ index ] = this_object
|
707
|
+
end
|
708
|
+
end
|
709
|
+
|
710
|
+
return self
|
711
|
+
|
712
|
+
end
|
713
|
+
|
714
|
+
###########################
|
715
|
+
# replace_without_hooks #
|
716
|
+
###########################
|
717
|
+
|
718
|
+
# Alias to :replace that bypasses hooks.
|
719
|
+
# @param [Array] other_array Other array to replace self with.
|
720
|
+
# @return [Object] Self.
|
721
|
+
def replace_without_hooks( other_array )
|
722
|
+
|
723
|
+
@without_hooks = true
|
724
|
+
|
725
|
+
replace( other_array )
|
726
|
+
|
727
|
+
@without_hooks = false
|
728
|
+
|
729
|
+
return self
|
730
|
+
|
731
|
+
end
|
732
|
+
|
733
|
+
##############
|
734
|
+
# reverse! #
|
735
|
+
##############
|
736
|
+
|
737
|
+
def reverse!
|
738
|
+
|
739
|
+
reversed_array = reverse
|
740
|
+
|
741
|
+
clear
|
742
|
+
|
743
|
+
reversed_array.each_with_index do |this_object, index|
|
744
|
+
self[ index ] = this_object
|
745
|
+
end
|
746
|
+
|
747
|
+
return self
|
748
|
+
|
749
|
+
end
|
750
|
+
|
751
|
+
############################
|
752
|
+
# reverse_without_hooks! #
|
753
|
+
############################
|
754
|
+
|
755
|
+
# Alias to :reverse that bypasses hooks.
|
756
|
+
# @return [Object] Self.
|
757
|
+
def reverse_without_hooks!
|
758
|
+
|
759
|
+
@without_hooks = true
|
760
|
+
|
761
|
+
reverse!
|
762
|
+
|
763
|
+
@without_hooks = false
|
764
|
+
|
765
|
+
return self
|
766
|
+
|
767
|
+
end
|
768
|
+
|
769
|
+
#############
|
770
|
+
# rotate! #
|
771
|
+
#############
|
772
|
+
|
773
|
+
def rotate!( rotate_count = 1 )
|
774
|
+
|
775
|
+
reversed_array = rotate( rotate_count )
|
776
|
+
|
777
|
+
clear
|
778
|
+
|
779
|
+
reversed_array.each_with_index do |this_object, index|
|
780
|
+
self[ index ] = this_object
|
781
|
+
end
|
782
|
+
|
783
|
+
return self
|
784
|
+
|
785
|
+
end
|
786
|
+
|
787
|
+
###########################
|
788
|
+
# rotate_without_hooks! #
|
789
|
+
###########################
|
790
|
+
|
791
|
+
# Alias to :rotate that bypasses hooks.
|
792
|
+
# @param [Fixnum] rotate_count Integer count of how many elements to rotate.
|
793
|
+
# @return [Object] Self.
|
794
|
+
def rotate_without_hooks!( rotate_count = 1 )
|
795
|
+
|
796
|
+
@without_hooks = true
|
797
|
+
|
798
|
+
rotate!( rotate_count )
|
799
|
+
|
800
|
+
@without_hooks = false
|
801
|
+
|
802
|
+
return self
|
803
|
+
|
804
|
+
end
|
805
|
+
|
806
|
+
#############
|
807
|
+
# select! #
|
808
|
+
#############
|
809
|
+
|
810
|
+
def select!
|
811
|
+
|
812
|
+
return to_enum unless block_given?
|
813
|
+
|
814
|
+
deleted_objects = 0
|
815
|
+
|
816
|
+
iteration_dup = dup
|
817
|
+
iteration_dup.each_with_index do |this_object, index|
|
818
|
+
unless yield( this_object )
|
819
|
+
delete_at( index - deleted_objects )
|
820
|
+
deleted_objects += 1
|
821
|
+
end
|
822
|
+
end
|
823
|
+
|
824
|
+
return self
|
825
|
+
|
826
|
+
end
|
827
|
+
|
828
|
+
###########################
|
829
|
+
# select_without_hooks! #
|
830
|
+
###########################
|
831
|
+
|
832
|
+
# Alias to :select that bypasses hooks.
|
833
|
+
# @yield Block passed to :select!.
|
834
|
+
# @return [Object] Self.
|
835
|
+
def select_without_hooks!( & block )
|
836
|
+
|
837
|
+
@without_hooks = true
|
838
|
+
|
839
|
+
select!( & block )
|
840
|
+
|
841
|
+
@without_hooks = false
|
842
|
+
|
843
|
+
return self
|
844
|
+
|
845
|
+
end
|
846
|
+
|
847
|
+
##############
|
848
|
+
# shuffle! #
|
849
|
+
##############
|
850
|
+
|
851
|
+
def shuffle!( random_number_generator = nil )
|
852
|
+
|
853
|
+
shuffled_array = shuffle( random: random_number_generator )
|
854
|
+
|
855
|
+
clear
|
856
|
+
|
857
|
+
shuffled_array.each_with_index do |this_object, index|
|
858
|
+
self[ index ] = this_object
|
859
|
+
end
|
860
|
+
|
861
|
+
return self
|
862
|
+
|
863
|
+
end
|
864
|
+
|
865
|
+
############################
|
866
|
+
# shuffle_without_hooks! #
|
867
|
+
############################
|
868
|
+
|
869
|
+
# Alias to :shuffle that bypasses hooks.
|
870
|
+
# @param [Object] random_number_generator Random number generator passed to :shuffle!.
|
871
|
+
# @return [Object] Self.
|
872
|
+
def shuffle_without_hooks!( random_number_generator = nil )
|
873
|
+
|
874
|
+
@without_hooks = true
|
875
|
+
|
876
|
+
shuffle!( random_number_generator )
|
877
|
+
|
878
|
+
@without_hooks = false
|
879
|
+
|
880
|
+
return self
|
881
|
+
|
882
|
+
end
|
883
|
+
|
884
|
+
##############
|
885
|
+
# collect! #
|
886
|
+
# map! #
|
887
|
+
##############
|
888
|
+
|
889
|
+
def collect!
|
890
|
+
|
891
|
+
return to_enum unless block_given?
|
892
|
+
|
893
|
+
self.each_with_index do |this_object, index|
|
894
|
+
replacement_object = yield( this_object )
|
895
|
+
self[ index ] = replacement_object
|
896
|
+
end
|
897
|
+
|
898
|
+
return self
|
899
|
+
|
900
|
+
end
|
901
|
+
|
902
|
+
alias_method :map!, :collect!
|
903
|
+
|
904
|
+
############################
|
905
|
+
# collect_without_hooks! #
|
906
|
+
# map_without_hooks! #
|
907
|
+
############################
|
908
|
+
|
909
|
+
# Alias to :select that bypasses hooks.
|
910
|
+
# @yield Block passed to :collect!.
|
911
|
+
# @return [Object] Self.
|
912
|
+
def collect_without_hooks!( & block )
|
913
|
+
|
914
|
+
@without_hooks = true
|
915
|
+
|
916
|
+
collect!( & block )
|
917
|
+
|
918
|
+
@without_hooks = false
|
919
|
+
|
920
|
+
return self
|
921
|
+
|
922
|
+
end
|
923
|
+
|
924
|
+
alias_method :map_without_hooks!, :collect_without_hooks!
|
925
|
+
|
926
|
+
###########
|
927
|
+
# sort! #
|
928
|
+
###########
|
929
|
+
|
930
|
+
def sort!( & block )
|
931
|
+
|
932
|
+
sorted_array = sort( & block )
|
933
|
+
|
934
|
+
unless sorted_array == self
|
935
|
+
|
936
|
+
replace( sorted_array )
|
937
|
+
|
938
|
+
end
|
939
|
+
|
940
|
+
return self
|
941
|
+
|
942
|
+
end
|
943
|
+
|
944
|
+
#########################
|
945
|
+
# sort_without_hooks! #
|
946
|
+
#########################
|
947
|
+
|
948
|
+
# Alias to :sort that bypasses hooks.
|
949
|
+
# @yield Block passed to :sort!.
|
950
|
+
# @return [Object] Self.
|
951
|
+
def sort_without_hooks!( & block )
|
952
|
+
|
953
|
+
@without_hooks = true
|
954
|
+
|
955
|
+
sort!
|
956
|
+
|
957
|
+
@without_hooks = false
|
958
|
+
|
959
|
+
return self
|
960
|
+
|
961
|
+
end
|
962
|
+
|
963
|
+
##############
|
964
|
+
# sort_by! #
|
965
|
+
##############
|
966
|
+
|
967
|
+
def sort_by!( & block )
|
968
|
+
|
969
|
+
return to_enum unless block_given?
|
970
|
+
|
971
|
+
sorted_array = sort_by( & block )
|
972
|
+
|
973
|
+
unless sorted_array == self
|
974
|
+
|
975
|
+
replace( sorted_array )
|
976
|
+
|
977
|
+
end
|
978
|
+
|
979
|
+
return self
|
980
|
+
|
981
|
+
end
|
982
|
+
|
983
|
+
############################
|
984
|
+
# sort_by_without_hooks! #
|
985
|
+
############################
|
986
|
+
|
987
|
+
# Alias to :sort_by! that bypasses hooks.
|
988
|
+
# @yield Block passed to :sort_by!.
|
989
|
+
# @return [Object] Self.
|
990
|
+
def sort_by_without_hooks!( & block )
|
991
|
+
|
992
|
+
@without_hooks = true
|
993
|
+
|
994
|
+
sort_by!( & block )
|
995
|
+
|
996
|
+
@without_hooks = false
|
997
|
+
|
998
|
+
return self
|
999
|
+
|
1000
|
+
end
|
1001
|
+
|
1002
|
+
###########
|
1003
|
+
# uniq! #
|
1004
|
+
###########
|
1005
|
+
|
1006
|
+
def uniq!
|
1007
|
+
|
1008
|
+
return_value = nil
|
1009
|
+
|
1010
|
+
uniq_array = uniq
|
1011
|
+
|
1012
|
+
unless uniq_array == self
|
1013
|
+
|
1014
|
+
clear
|
1015
|
+
|
1016
|
+
replace( uniq_array )
|
1017
|
+
|
1018
|
+
end
|
1019
|
+
|
1020
|
+
return return_value
|
1021
|
+
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
#########################
|
1025
|
+
# uniq_without_hooks! #
|
1026
|
+
#########################
|
1027
|
+
|
1028
|
+
# Alias to :uniq! that bypasses hooks.
|
1029
|
+
# @return [Object] Self.
|
1030
|
+
def uniq_without_hooks!
|
1031
|
+
|
1032
|
+
@without_hooks = true
|
1033
|
+
|
1034
|
+
return_value = uniq!
|
1035
|
+
|
1036
|
+
@without_hooks = false
|
1037
|
+
|
1038
|
+
return return_value
|
1039
|
+
|
1040
|
+
end
|
1041
|
+
|
1042
|
+
#############
|
1043
|
+
# unshift #
|
1044
|
+
#############
|
1045
|
+
|
1046
|
+
def unshift( object )
|
1047
|
+
|
1048
|
+
insert( 0, object )
|
1049
|
+
|
1050
|
+
return self
|
1051
|
+
|
1052
|
+
end
|
1053
|
+
|
1054
|
+
###########################
|
1055
|
+
# unshift_without_hooks #
|
1056
|
+
###########################
|
1057
|
+
|
1058
|
+
# Alias to :unshift that bypasses hooks.
|
1059
|
+
# @param [Object] object Object to unshift onto self.
|
1060
|
+
# @return [Object] Self.
|
1061
|
+
def unshift_without_hooks( object )
|
1062
|
+
|
1063
|
+
@without_hooks = true
|
1064
|
+
|
1065
|
+
unshift( object )
|
1066
|
+
|
1067
|
+
@without_hooks = false
|
1068
|
+
|
1069
|
+
return self
|
1070
|
+
|
1071
|
+
end
|
1072
|
+
|
1073
|
+
#########
|
1074
|
+
# pop #
|
1075
|
+
#########
|
1076
|
+
|
1077
|
+
def pop
|
1078
|
+
|
1079
|
+
object = delete_at( count - 1 )
|
1080
|
+
|
1081
|
+
return object
|
1082
|
+
|
1083
|
+
end
|
1084
|
+
|
1085
|
+
#######################
|
1086
|
+
# pop_without_hooks #
|
1087
|
+
#######################
|
1088
|
+
|
1089
|
+
# Alias to :pop that bypasses hooks.
|
1090
|
+
# @return [Object] Self.
|
1091
|
+
def pop_without_hooks
|
1092
|
+
|
1093
|
+
@without_hooks = true
|
1094
|
+
|
1095
|
+
object = pop
|
1096
|
+
|
1097
|
+
@without_hooks = false
|
1098
|
+
|
1099
|
+
return object
|
1100
|
+
|
1101
|
+
end
|
1102
|
+
|
1103
|
+
###########
|
1104
|
+
# shift #
|
1105
|
+
###########
|
1106
|
+
|
1107
|
+
def shift
|
1108
|
+
|
1109
|
+
object = delete_at( 0 )
|
1110
|
+
|
1111
|
+
return object
|
1112
|
+
|
1113
|
+
end
|
1114
|
+
|
1115
|
+
#########################
|
1116
|
+
# shift_without_hooks #
|
1117
|
+
#########################
|
1118
|
+
|
1119
|
+
# Alias to :shift that bypasses hooks.
|
1120
|
+
# @return [Object] Self.
|
1121
|
+
def shift_without_hooks
|
1122
|
+
|
1123
|
+
@without_hooks = true
|
1124
|
+
|
1125
|
+
object = shift
|
1126
|
+
|
1127
|
+
@without_hooks = false
|
1128
|
+
|
1129
|
+
return object
|
1130
|
+
|
1131
|
+
end
|
1132
|
+
|
1133
|
+
############
|
1134
|
+
# slice! #
|
1135
|
+
############
|
1136
|
+
|
1137
|
+
def slice!( index_start_or_range, length = nil )
|
1138
|
+
|
1139
|
+
slice = nil
|
1140
|
+
|
1141
|
+
start_index = nil
|
1142
|
+
end_index = nil
|
1143
|
+
|
1144
|
+
if index_start_or_range.is_a?( Range )
|
1145
|
+
|
1146
|
+
start_index = index_start_or_range.begin
|
1147
|
+
end_index = index_start_or_range.end
|
1148
|
+
|
1149
|
+
elsif length
|
1150
|
+
|
1151
|
+
start_index = index_start_or_range
|
1152
|
+
end_index = index_start_or_range + length
|
1153
|
+
|
1154
|
+
end
|
1155
|
+
|
1156
|
+
if end_index
|
1157
|
+
|
1158
|
+
indexes = [ ]
|
1159
|
+
|
1160
|
+
( end_index - start_index ).times do |this_time|
|
1161
|
+
indexes.push( end_index - this_time - 1 )
|
1162
|
+
end
|
1163
|
+
|
1164
|
+
slice = delete_at_indexes( *indexes )
|
1165
|
+
|
1166
|
+
else
|
1167
|
+
|
1168
|
+
slice = delete_at( start_index )
|
1169
|
+
|
1170
|
+
end
|
1171
|
+
|
1172
|
+
|
1173
|
+
return slice
|
1174
|
+
|
1175
|
+
end
|
1176
|
+
|
1177
|
+
##########################
|
1178
|
+
# slice_without_hooks! #
|
1179
|
+
##########################
|
1180
|
+
|
1181
|
+
# Alias to :slice! that bypasses hooks.
|
1182
|
+
# @param [Fixnum] index_start_or_range Index at which to begin slice.
|
1183
|
+
# @param [Fixnum] length Length of slice.
|
1184
|
+
# @return [Object] Self.
|
1185
|
+
def slice_without_hooks!( index_start_or_range, length = nil )
|
1186
|
+
|
1187
|
+
@without_hooks = true
|
1188
|
+
|
1189
|
+
slice = slice!( index_start_or_range, length )
|
1190
|
+
|
1191
|
+
@without_hooks = false
|
1192
|
+
|
1193
|
+
return slice
|
1194
|
+
|
1195
|
+
end
|
1196
|
+
|
1197
|
+
###########
|
1198
|
+
# clear #
|
1199
|
+
###########
|
1200
|
+
|
1201
|
+
def clear
|
1202
|
+
|
1203
|
+
indexes = [ ]
|
1204
|
+
|
1205
|
+
count.times do |this_time|
|
1206
|
+
indexes.push( count - this_time - 1 )
|
1207
|
+
end
|
1208
|
+
|
1209
|
+
delete_at_indexes( *indexes )
|
1210
|
+
|
1211
|
+
return self
|
1212
|
+
|
1213
|
+
end
|
1214
|
+
|
1215
|
+
#########################
|
1216
|
+
# clear_without_hooks #
|
1217
|
+
#########################
|
1218
|
+
|
1219
|
+
# Alias to :clear that bypasses hooks.
|
1220
|
+
# @return [Object] Self.
|
1221
|
+
def clear_without_hooks
|
1222
|
+
|
1223
|
+
@without_hooks = true
|
1224
|
+
|
1225
|
+
clear
|
1226
|
+
|
1227
|
+
@without_hooks = false
|
1228
|
+
|
1229
|
+
return self
|
1230
|
+
|
1231
|
+
end
|
1232
|
+
|
1233
|
+
end
|