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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fefa402916a5d9db25add5e34a0d95cfbfe1440f
4
- data.tar.gz: 3f17115bffeb8777ba904292f98c8fffbed1b34b
3
+ metadata.gz: 128756e7bd9d7a135b08f43d8318d94960aa109a
4
+ data.tar.gz: 1ab7cd3ac051d2beffb1ef345ba45784b0396310
5
5
  SHA512:
6
- metadata.gz: 6dbf54c87e2ca417d725e40f12eff566439fc9212c5f13c12bd2c089c0018a09cf671de635c2aa800151e3d6474de793e6b3991ab51c7e7fa3f224903ad34cb2
7
- data.tar.gz: 83a352fb6f3f00e5bb7245075d47609521dbeb7c508a1ea066acb2fb120e6affdbc2ed9c54cbcc15c881353b7c716653976eec02e138f7b8131e51c6699ac7c9
6
+ metadata.gz: e7cdc70d3062ec1e70cb854bb5e52f05f7621e6a8225a9c6a3816ae2b57ad0fdfd9d165dd61d48bf9c0f1ad15f27f5d0027ff7a67b09f91673ce56cf064f3a01
7
+ data.tar.gz: b7439ec77d5db6122b2fc0f230a7eea8ac9d0043fec80674d392e192977354a5f2ea7338284916b720249dd251f0f125f44ceef7c609e1ea21147dba0f6a4f55
@@ -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
- # sibling - the item to append, or an arbitrary object to be wraped in a new
275
- # item.
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
- first_item = last_item = self.class.new object
285
- first_item.list = @list
286
- @list.send :grow if @list
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
- # sibling - the item to prepend. or an arbitrary object to be wraped in a
312
- # new item.
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
- first_item = last_item = self.class.new object
322
- first_item.list = @list
323
- @list.send :grow, 1 if @list
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
@@ -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 Item,
171
- # or a decendant of Item, it will be treated as a value. Depending on the
172
- # state of the list the value will be
173
- # a) wraped in a new instance of Item if the list is empty or
174
- # b) wraped in an object of the same class as the last item in the list.
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
- # item - the item to insert, or an arbitrary value.
176
+ # object - the item to insert, or an arbitrary object.
177
177
  #
178
178
  # Returns self.
179
179
 
180
- def push(item)
181
- eol.append item
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
- # Item, or a decendant of Item, it will be treated as a value. Depending on
198
- # the state of the list the value will be
199
- # a) wraped in a new instance of Item if the list is empty or
200
- # b) wraped in an object of the same class as the last item in the list.
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
- # item - the item to insert, or an arbitrary value.
202
+ # object - the item to insert, or an arbitrary object.
203
203
  #
204
204
  # Returns self.
205
205
 
206
- def unshift(item)
207
- eol.prepend item
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, either in normal or reverse order. If
233
- # a block is not given an enumerator is returned.
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(reverse: false, &block)
239
- if reverse
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
@@ -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. If the given object is
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
- # sibling - the item or value to be appended.
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(sibling)
53
- if @prev == self
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. If the given
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
- # sibling - the item or value to be prepended.
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
- # Returns the item that was prepended. In case of a string of items the
70
- # first one is returned.
59
+ # Return true if the chain is empty, otherwise nil.
71
60
 
72
- def prepend(sibling)
73
- if @next == self
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Linked
4
- VERSION = '0.2.1'
4
+ VERSION = '0.3.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: linked
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastian Lindberg