linked 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/linked/item.rb +50 -98
- data/lib/linked/list.rb +46 -40
- data/lib/linked/list/eol.rb +15 -31
- data/lib/linked/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 128756e7bd9d7a135b08f43d8318d94960aa109a
|
4
|
+
data.tar.gz: 1ab7cd3ac051d2beffb1ef345ba45784b0396310
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e7cdc70d3062ec1e70cb854bb5e52f05f7621e6a8225a9c6a3816ae2b57ad0fdfd9d165dd61d48bf9c0f1ad15f27f5d0027ff7a67b09f91673ce56cf064f3a01
|
7
|
+
data.tar.gz: b7439ec77d5db6122b2fc0f230a7eea8ac9d0043fec80674d392e192977354a5f2ea7338284916b720249dd251f0f125f44ceef7c609e1ea21147dba0f6a4f55
|
data/lib/linked/item.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# TODO: Think about moving some of basic functionallity of Item into Item::Base.
|
4
|
+
|
3
5
|
module Linked
|
4
6
|
# Item
|
5
7
|
#
|
@@ -84,33 +86,33 @@ module Linked
|
|
84
86
|
end
|
85
87
|
super
|
86
88
|
end
|
87
|
-
|
89
|
+
|
88
90
|
# Identity method that simply return the item. This method mirrors List#item
|
89
91
|
# and allows other methods that work on Item objects to easily and
|
90
92
|
# interchangebly accept both lists and items as arguments.
|
91
93
|
#
|
92
94
|
# Returns the item itself.
|
93
|
-
|
95
|
+
|
94
96
|
def item
|
95
97
|
self
|
96
98
|
end
|
97
|
-
|
99
|
+
|
98
100
|
# Access the list that the item is part of. If the item is not in a list a
|
99
101
|
# NoMethodError will be raised. This mirrors the behaviour of List#list and
|
100
102
|
# allows other methods that work on List objects to easily and
|
101
103
|
# interchangeably accept both lists and items as arguments.
|
102
104
|
#
|
103
105
|
# Returns the list that the item is part of.
|
104
|
-
|
106
|
+
|
105
107
|
def list
|
106
108
|
raise NoMethodError unless @list
|
107
109
|
@list
|
108
110
|
end
|
109
|
-
|
111
|
+
|
110
112
|
# Check it the item is part of a list.
|
111
113
|
#
|
112
114
|
# Returns true if the item is in a list.
|
113
|
-
|
115
|
+
|
114
116
|
def in_list?
|
115
117
|
@list ? true : false
|
116
118
|
end
|
@@ -132,7 +134,7 @@ module Linked
|
|
132
134
|
def last?
|
133
135
|
@next.nil?
|
134
136
|
end
|
135
|
-
|
137
|
+
|
136
138
|
# Check if the item is in the given list.
|
137
139
|
#
|
138
140
|
# list - any object.
|
@@ -196,66 +198,6 @@ module Linked
|
|
196
198
|
|
197
199
|
alias previous! prev!
|
198
200
|
|
199
|
-
# Split the chain of items in two. If the chain belongs to a list this item
|
200
|
-
# and all that stay connected to it will continue to belong to it, while the
|
201
|
-
# rest are removed from it.
|
202
|
-
#
|
203
|
-
# By default all items followng this one will be kept together, but if given
|
204
|
-
# the argument after: true, the split will instead happen after this item
|
205
|
-
# and it will instead be kept with those before it.
|
206
|
-
#
|
207
|
-
# Example for the chain (A <> B <> C)
|
208
|
-
#
|
209
|
-
# B.split(after: false) => (A), (B <> C)
|
210
|
-
# B.split(after: true) => (A <> B), (C)
|
211
|
-
#
|
212
|
-
# after - determine wheter to split the chain before or after this item.
|
213
|
-
#
|
214
|
-
# Returns self.
|
215
|
-
|
216
|
-
def split after: false
|
217
|
-
warn '[DEPRECATION] this method will be removed in the next major update. Please use #delete_before and #delete_after instead'
|
218
|
-
if after
|
219
|
-
unless last?
|
220
|
-
if @list
|
221
|
-
item = self
|
222
|
-
count = 1 + loop.count do
|
223
|
-
item = item.next
|
224
|
-
item.list = nil
|
225
|
-
end
|
226
|
-
|
227
|
-
tail = @list.tail
|
228
|
-
tail.prev = self
|
229
|
-
@next = tail
|
230
|
-
@list.shrink count
|
231
|
-
else
|
232
|
-
@next.prev = nil
|
233
|
-
@next = nil
|
234
|
-
end
|
235
|
-
end
|
236
|
-
else
|
237
|
-
unless first?
|
238
|
-
if @list
|
239
|
-
item = self
|
240
|
-
count = 1 + loop.count do
|
241
|
-
item = item.prev
|
242
|
-
item.list = nil
|
243
|
-
end
|
244
|
-
|
245
|
-
head = @list.head
|
246
|
-
head.next = self
|
247
|
-
@prev = head
|
248
|
-
@list.shrink count
|
249
|
-
else
|
250
|
-
@prev.next = nil
|
251
|
-
@prev = nil
|
252
|
-
end
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
self
|
257
|
-
end
|
258
|
-
|
259
201
|
# Inserts the given item between this one and the one after it (if any). If
|
260
202
|
# the given item is part of a chain, all items following it will be moved to
|
261
203
|
# this one, and added to the list if one is set.
|
@@ -271,8 +213,9 @@ module Linked
|
|
271
213
|
# number of added items as an argument. Should it also be the last item
|
272
214
|
# #prev= will be called on the list tail.
|
273
215
|
#
|
274
|
-
#
|
275
|
-
#
|
216
|
+
# object - the item to append, or an arbitrary object to be wraped in a new
|
217
|
+
# item. If in a list it will be asked to create the new item via
|
218
|
+
# List#create_item.
|
276
219
|
#
|
277
220
|
# Returns the last item that was appended.
|
278
221
|
|
@@ -281,15 +224,19 @@ module Linked
|
|
281
224
|
first_item = object.item
|
282
225
|
last_item = first_item.send :extract_beginning_with, @list
|
283
226
|
else
|
284
|
-
|
285
|
-
|
286
|
-
|
227
|
+
if @list
|
228
|
+
first_item = last_item = @list.send :create_item, object
|
229
|
+
first_item.list = @list
|
230
|
+
@list.send :grow
|
231
|
+
else
|
232
|
+
first_item = last_item = self.class.new object
|
233
|
+
end
|
287
234
|
end
|
288
|
-
|
235
|
+
|
289
236
|
first_item.prev = self
|
290
237
|
@next.prev = last_item if @next
|
291
238
|
@next, last_item.next = first_item, @next
|
292
|
-
|
239
|
+
|
293
240
|
last_item
|
294
241
|
end
|
295
242
|
|
@@ -308,8 +255,9 @@ module Linked
|
|
308
255
|
# number of added items as an argument. Should it also be the first item
|
309
256
|
# #next= will be called on the list head.
|
310
257
|
#
|
311
|
-
#
|
312
|
-
#
|
258
|
+
# object - the item to prepend. or an arbitrary object to be wraped in a
|
259
|
+
# new item. If in a list it will be asked to create the new item
|
260
|
+
# via List#create_item.
|
313
261
|
#
|
314
262
|
# Returns the last item that was prepended.
|
315
263
|
|
@@ -318,18 +266,22 @@ module Linked
|
|
318
266
|
last_item = object.item
|
319
267
|
first_item = last_item.send :extract_ending_with, @list
|
320
268
|
else
|
321
|
-
|
322
|
-
|
323
|
-
|
269
|
+
if @list
|
270
|
+
first_item = last_item = @list.send :create_item, object
|
271
|
+
first_item.list = @list
|
272
|
+
@list.send :grow
|
273
|
+
else
|
274
|
+
first_item = last_item = self.class.new object
|
275
|
+
end
|
324
276
|
end
|
325
|
-
|
277
|
+
|
326
278
|
last_item.next = self
|
327
279
|
@prev.next = first_item if @prev
|
328
280
|
@prev, first_item.prev = last_item, @prev
|
329
|
-
|
281
|
+
|
330
282
|
first_item
|
331
283
|
end
|
332
|
-
|
284
|
+
|
333
285
|
# Remove an item from the chain. If this item is part of a list and is
|
334
286
|
# either first, last or both in that list, #next= and #prev= will be called
|
335
287
|
# on the list head and tail respectivly.
|
@@ -346,23 +298,23 @@ module Linked
|
|
346
298
|
@next = @prev = @list = nil
|
347
299
|
self
|
348
300
|
end
|
349
|
-
|
301
|
+
|
350
302
|
# Remove all items before this one in the chain. If the items are part of a
|
351
303
|
# list they will be removed from it.
|
352
304
|
#
|
353
305
|
# Returns the last item in the chain that was just deleted, or nil if this
|
354
306
|
# is the first item.
|
355
|
-
|
307
|
+
|
356
308
|
def delete_before
|
357
309
|
@prev.send :extract_ending_with unless first?
|
358
310
|
end
|
359
|
-
|
311
|
+
|
360
312
|
# Remove all items after this one in the chain. If the items are part of a
|
361
313
|
# list they will be removed from it.
|
362
314
|
#
|
363
315
|
# Returns the last item in the chain that was just deleted, or nil if this
|
364
316
|
# is the first item.
|
365
|
-
|
317
|
+
|
366
318
|
def delete_after
|
367
319
|
@next.send :extract_beginning_with unless last?
|
368
320
|
end
|
@@ -420,7 +372,7 @@ module Linked
|
|
420
372
|
output = format '%s:0x%0x', self.class.name, object_id
|
421
373
|
value ? output + " value=#{value.inspect}" : output
|
422
374
|
end
|
423
|
-
|
375
|
+
|
424
376
|
# PRIVATE DANGEROUS METHOD. This method should never be called directly
|
425
377
|
# since it may leave the extracted item chain in an invalid state.
|
426
378
|
#
|
@@ -439,7 +391,7 @@ module Linked
|
|
439
391
|
# be left in an invalid state.
|
440
392
|
#
|
441
393
|
# Returns the last item of the chain.
|
442
|
-
|
394
|
+
|
443
395
|
private def extract_beginning_with(new_list = nil)
|
444
396
|
old_list = @list
|
445
397
|
# Count items and move them to the new list
|
@@ -448,7 +400,7 @@ module Linked
|
|
448
400
|
last_item.list = new_list
|
449
401
|
last_item = last_item.next
|
450
402
|
end
|
451
|
-
|
403
|
+
|
452
404
|
# Make sure the old list is in a valid state
|
453
405
|
if old_list
|
454
406
|
if first?
|
@@ -463,16 +415,16 @@ module Linked
|
|
463
415
|
# Disconnect the item directly after the chain
|
464
416
|
@prev.next = nil unless first?
|
465
417
|
end
|
466
|
-
|
418
|
+
|
467
419
|
# Disconnect the chain from the list
|
468
420
|
@prev = last_item.next = nil
|
469
|
-
|
421
|
+
|
470
422
|
# Preemptivly tell the new list to grow
|
471
423
|
new_list.send :grow, count if new_list
|
472
|
-
|
424
|
+
|
473
425
|
last_item
|
474
426
|
end
|
475
|
-
|
427
|
+
|
476
428
|
# PRIVATE DANGEROUS METHOD. This method should never be called directly
|
477
429
|
# since it may leave the extracted item chain in an invalid state.
|
478
430
|
#
|
@@ -482,7 +434,7 @@ module Linked
|
|
482
434
|
# effects from calling this method.
|
483
435
|
#
|
484
436
|
# Returns the first item in the chain.
|
485
|
-
|
437
|
+
|
486
438
|
private def extract_ending_with(new_list = nil)
|
487
439
|
old_list = @list
|
488
440
|
# Count items and move them to the new list
|
@@ -491,7 +443,7 @@ module Linked
|
|
491
443
|
first_item.list = new_list
|
492
444
|
first_item = first_item.prev
|
493
445
|
end
|
494
|
-
|
446
|
+
|
495
447
|
# Make sure the old list is in a valid state
|
496
448
|
if old_list
|
497
449
|
if last?
|
@@ -506,13 +458,13 @@ module Linked
|
|
506
458
|
# Disconnect the item directly after the chain
|
507
459
|
@next.prev = nil unless last?
|
508
460
|
end
|
509
|
-
|
461
|
+
|
510
462
|
# Disconnect the chain from the list
|
511
463
|
first_item.prev = @next = nil
|
512
|
-
|
464
|
+
|
513
465
|
# Preemptivly tell the new list to grow
|
514
466
|
new_list.send :grow, count if new_list
|
515
|
-
|
467
|
+
|
516
468
|
first_item
|
517
469
|
end
|
518
470
|
end
|
data/lib/linked/list.rb
CHANGED
@@ -62,24 +62,24 @@ module Linked
|
|
62
62
|
|
63
63
|
super
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
# Identity method that simply return the list. This method mirrors Item#list
|
67
67
|
# and allows other methods that work on List objects to easily and
|
68
68
|
# interchangebly accept both lists and items as arguments.
|
69
69
|
#
|
70
70
|
# Returns the list itself.
|
71
|
-
|
71
|
+
|
72
72
|
def list
|
73
73
|
self
|
74
74
|
end
|
75
|
-
|
75
|
+
|
76
76
|
# Access the first item in the list. If the list is empty a NoMethodError
|
77
77
|
# will be raised. This mirrors the behaviour of Item#item and allows other
|
78
78
|
# methods that work on List objects to easily and interchangeably accept
|
79
79
|
# both lists and items as arguments.
|
80
80
|
#
|
81
81
|
# Returns the first item in the list.
|
82
|
-
|
82
|
+
|
83
83
|
def item
|
84
84
|
raise NoMethodError if empty?
|
85
85
|
eol.next
|
@@ -167,18 +167,18 @@ module Linked
|
|
167
167
|
@item_count == 0
|
168
168
|
end
|
169
169
|
|
170
|
-
# Insert an item at the end of the list. If the given object is not an
|
171
|
-
#
|
172
|
-
#
|
173
|
-
#
|
174
|
-
#
|
170
|
+
# Insert an item at the end of the list. If the given object is not an
|
171
|
+
# object responding to #item it will be treated as a value. The value will
|
172
|
+
# be wraped in a new Item create by #create_item.
|
173
|
+
#
|
174
|
+
# See Item#append for more details.
|
175
175
|
#
|
176
|
-
#
|
176
|
+
# object - the item to insert, or an arbitrary object.
|
177
177
|
#
|
178
178
|
# Returns self.
|
179
179
|
|
180
|
-
def push(
|
181
|
-
eol.append
|
180
|
+
def push(object)
|
181
|
+
eol.append object
|
182
182
|
self
|
183
183
|
end
|
184
184
|
|
@@ -194,17 +194,17 @@ module Linked
|
|
194
194
|
end
|
195
195
|
|
196
196
|
# Insert an item at the beginning of the list. If the given object is not an
|
197
|
-
#
|
198
|
-
#
|
199
|
-
#
|
200
|
-
#
|
197
|
+
# object responding to #item it will be treated as a value. The value will
|
198
|
+
# be wraped in a new Item create by #create_item.
|
199
|
+
#
|
200
|
+
# See Item#prepend for more details.
|
201
201
|
#
|
202
|
-
#
|
202
|
+
# object - the item to insert, or an arbitrary object.
|
203
203
|
#
|
204
204
|
# Returns self.
|
205
205
|
|
206
|
-
def unshift(
|
207
|
-
eol.prepend
|
206
|
+
def unshift(object)
|
207
|
+
eol.prepend object
|
208
208
|
self
|
209
209
|
end
|
210
210
|
|
@@ -216,32 +216,24 @@ module Linked
|
|
216
216
|
return nil if empty?
|
217
217
|
first.delete
|
218
218
|
end
|
219
|
-
|
219
|
+
|
220
220
|
# Check if an item is in the list.
|
221
221
|
#
|
222
222
|
# item - Item, or any object that may be in the list.
|
223
223
|
#
|
224
224
|
# Returns true if the given item is in the list, otherwise false.
|
225
|
-
|
225
|
+
|
226
226
|
def include?(item)
|
227
227
|
item.in? self
|
228
228
|
rescue NoMethodError
|
229
229
|
false
|
230
230
|
end
|
231
231
|
|
232
|
-
# Iterates over each item in the list
|
233
|
-
#
|
234
|
-
#
|
235
|
-
# reverse - flips the iteration order if true. Note that this option is
|
236
|
-
# depricated and will be removed in the next major release.
|
232
|
+
# Iterates over each item in the list If a block is not given an enumerator
|
233
|
+
# is returned.
|
237
234
|
|
238
|
-
def each_item(
|
239
|
-
|
240
|
-
warn '[DEPRECATION] the option `reverse: true` will be removed in a future release. Please call `reverse_each_item` instead.'
|
241
|
-
eol.before(&block)
|
242
|
-
else
|
243
|
-
eol.after(&block)
|
244
|
-
end
|
235
|
+
def each_item(&block)
|
236
|
+
eol.after(&block)
|
245
237
|
end
|
246
238
|
|
247
239
|
alias each each_item
|
@@ -285,6 +277,20 @@ module Linked
|
|
285
277
|
res.join("\n")
|
286
278
|
end
|
287
279
|
|
280
|
+
# Protected factory method for creating items compatible with the list. This
|
281
|
+
# method is called whenever an arbitrary object is pushed or unshifted onto
|
282
|
+
# the list and need to be wraped inside an Item.
|
283
|
+
#
|
284
|
+
# This method can be overridden to suport different Item types.
|
285
|
+
#
|
286
|
+
# args - any arguments will be passed on to Item.new.
|
287
|
+
#
|
288
|
+
# Returns a new Item.
|
289
|
+
|
290
|
+
protected def create_item(*args)
|
291
|
+
Item.new(*args)
|
292
|
+
end
|
293
|
+
|
288
294
|
# Internal method to grow the list with n elements. Never call this method
|
289
295
|
# without also inserting the n elements.
|
290
296
|
#
|
@@ -306,17 +312,17 @@ module Linked
|
|
306
312
|
private def shrink(n = 1)
|
307
313
|
@item_count -= n
|
308
314
|
end
|
309
|
-
|
315
|
+
|
310
316
|
# Private method to clear the list. Never call this method without also
|
311
317
|
# modifying the items in the list, as this operation leavs them in an
|
312
318
|
# inconsistant state. If the list items are kept, make sure to
|
313
319
|
# a) clear the `prev` pointer of the first item and
|
314
320
|
# b) clear the `next` pointer of the last item.
|
315
|
-
|
321
|
+
|
316
322
|
private def clear
|
317
323
|
head.send :next=, tail
|
318
324
|
tail.send :prev=, head
|
319
|
-
|
325
|
+
|
320
326
|
@item_count = 0
|
321
327
|
end
|
322
328
|
|
@@ -342,7 +348,7 @@ module Linked
|
|
342
348
|
return nil if n == 0
|
343
349
|
return n > 1 ? [] : nil if item.next!.nil?
|
344
350
|
return item.next if n == 1
|
345
|
-
|
351
|
+
|
346
352
|
n = items_left if n > items_left
|
347
353
|
|
348
354
|
arr = Array.new n
|
@@ -376,18 +382,18 @@ module Linked
|
|
376
382
|
return item.prev if n == 1
|
377
383
|
|
378
384
|
n = items_left if n > items_left
|
379
|
-
|
385
|
+
|
380
386
|
arr = Array.new n
|
381
387
|
(n - 1).downto(0) { |i| arr[i] = item = item.prev }
|
382
388
|
arr
|
383
389
|
rescue StopIteration
|
384
390
|
arr.compact! || arr
|
385
391
|
end
|
386
|
-
|
392
|
+
|
387
393
|
# This method is called whenever the module is included somewhere. In the
|
388
394
|
# special case when List is included in an Item the #item method must be
|
389
395
|
# changed to return self.
|
390
|
-
|
396
|
+
|
391
397
|
def self.included(klass)
|
392
398
|
klass.send(:define_method, :item) { self } if klass < Item
|
393
399
|
end
|
data/lib/linked/list/eol.rb
CHANGED
@@ -38,44 +38,28 @@ module Linked
|
|
38
38
|
true
|
39
39
|
end
|
40
40
|
|
41
|
-
# Inserts one or more items at the end of the list.
|
42
|
-
# not an Item, or a decendant of Item, it will be treated as a value.
|
43
|
-
# Depending on the state of the list the value will be
|
44
|
-
# a) wraped in a new instance of Item if the list is empty or
|
45
|
-
# b) wraped in an object of the same class as the last item in the list.
|
41
|
+
# Inserts one or more items at the end of the list.
|
46
42
|
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
# Returns the item that was appended. In case of a string of items the
|
50
|
-
# last one is returned.
|
43
|
+
# See Item#append for more details.
|
51
44
|
|
52
|
-
def append(
|
53
|
-
|
54
|
-
sibling = Item.new sibling unless sibling.is_a? Item
|
55
|
-
super sibling
|
56
|
-
else
|
57
|
-
@prev.append sibling
|
58
|
-
end
|
45
|
+
def append(object)
|
46
|
+
empty? ? super : @prev.append(object)
|
59
47
|
end
|
60
48
|
|
61
|
-
# Inserts one or more items at the beginning of the list.
|
62
|
-
# object is not an Item, or a decendant of Item, it will be treated as a
|
63
|
-
# value. Depending on the state of the list the value will be
|
64
|
-
# a) wraped in a new instance of Item if the list is empty or
|
65
|
-
# b) wraped in an object of the same class as the last item in the list.
|
49
|
+
# Inserts one or more items at the beginning of the list.
|
66
50
|
#
|
67
|
-
#
|
51
|
+
# See Item#append for more details.
|
52
|
+
|
53
|
+
def prepend(object)
|
54
|
+
empty? ? super : @next.prepend(object)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Private helper to check if the item chain is empty.
|
68
58
|
#
|
69
|
-
#
|
70
|
-
# first one is returned.
|
59
|
+
# Return true if the chain is empty, otherwise nil.
|
71
60
|
|
72
|
-
def
|
73
|
-
|
74
|
-
sibling = Item.new sibling unless sibling.is_a? Item
|
75
|
-
super sibling
|
76
|
-
else
|
77
|
-
@next.prepend sibling
|
78
|
-
end
|
61
|
+
private def empty?
|
62
|
+
@prev == self
|
79
63
|
end
|
80
64
|
end
|
81
65
|
end
|
data/lib/linked/version.rb
CHANGED