linked 0.2.1 → 0.3.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.
- 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