linked-list 0.0.10 → 0.0.15

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
  SHA256:
3
- metadata.gz: 15032f04d676c41f8dedbb0d911c82a35944826d5469c3a32530548fc55efa5c
4
- data.tar.gz: 3f8b4bab1f5d9dca9f88b2e4e9baa78b2e9120eaf41ad7c3095e4072b7609be9
3
+ metadata.gz: a70c658176bc2e924764731304a3f8dbb376306e35b9e016d41896a7b5790463
4
+ data.tar.gz: cde342c544b41d53f5c52eb3d592deed28a6bf79736b6a0f2dbb1ef2d78319a7
5
5
  SHA512:
6
- metadata.gz: c174a97b29c738a4224025639b744c97f086f0cc80afe21f20678ea708be29ff956fd8e81feb4f606d7a1ac9376f2fb334afe7bd730e3b8263af69107255bc50
7
- data.tar.gz: 0eeb55908b8b9ddeb7f477262899e1a8d990e013af21d0c723c64a9c92248b4a1964e48450f379de1642906c0f68e08ea4a7f20dda360e45346a4ce9dd057a4d
6
+ metadata.gz: db29d3d0ec5195c12937ae63332a8dbb3ac891f6510441762f5a42d1acfce8de826d9a20a6af308e9b39a5fe33fcf92527c26d1ffd757c6814fb2c09ed4c34a4
7
+ data.tar.gz: 7723a09dc0858687eaf4ff6668e024ba8b7efd00cc202ab6eb067baffc52f645f6138d286cec946ccb30896b372345f91b601db5e8dee8900c65582ffe61577b
@@ -1,5 +1,6 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.9.3
4
- - 2.0.0
3
+ - 2.7
5
4
  cache: bundler
5
+ env:
6
+ CI: true
@@ -0,0 +1,59 @@
1
+ # 0.0.x / Unreleased
2
+
3
+
4
+ # 0.0.15 / 2020-05-26
5
+
6
+ ## Fixed
7
+
8
+ - Fixed bug when deleting the last node of the list. The @tail value was not updated if the @head value was updated.
9
+
10
+ [Compare v0.0.14...v0.0.15](https://github.com/spectator/linked-list/compare/v0.0.14...v0.0.15)
11
+
12
+ # 0.0.14 / 2020-04-17
13
+
14
+ ## Fixed
15
+
16
+ Forced minimal rake version in gemspec to skip rake versions with security issues.
17
+
18
+ [Compare v0.0.13...v0.0.14](https://github.com/spectator/linked-list/compare/v0.0.13...v0.0.14)
19
+
20
+ # 0.0.13 / 2018-11-27
21
+
22
+ ## Fixed
23
+
24
+ - Delete duplicate method definitions (nex3 in [#7](https://github.com/spectator/linked-list/pull/7))
25
+
26
+ ## Added
27
+
28
+ - Allow `List#delete` to delete a `Node` in O(1) time (nex3 in [#6](https://github.com/spectator/linked-list/pull/6))
29
+
30
+ [Compare v0.0.12...v0.0.13](https://github.com/spectator/linked-list/compare/v0.0.12...v0.0.13)
31
+
32
+ # 0.0.12 / 2018-09-04
33
+
34
+ ## Added
35
+
36
+ - Added `insert`, `insert_before` and `insert_after` methods (mpospelov in [#3](https://github.com/spectator/linked-list/pull/3))
37
+ - Added `reverse_each` and `reverse_each_node` methods (mpospelov in [#4](https://github.com/spectator/linked-list/pull/4))
38
+
39
+ [Compare v0.0.11...v0.0.12](https://github.com/spectator/linked-list/compare/v0.0.11...v0.0.12)
40
+
41
+ # 0.0.11 / 2018-08-23
42
+
43
+ ## Added
44
+
45
+ - Added `delete` and `delete_all` methods (mpospelov in [#2](https://github.com/spectator/linked-list/pull/2))
46
+
47
+ [Compare v0.0.10...v0.0.11](https://github.com/spectator/linked-list/compare/v0.0.10...v0.0.11)
48
+
49
+ # 0.0.10 / 2018-04-02
50
+
51
+ ## Fixed
52
+
53
+ - Fixed bug when `@tail.prev` was mistekenly set to `nil` instead of `@tail.next` when popping elements off the list (Sonna in [#1](https://github.com/spectator/linked-list/pull/1))
54
+
55
+ [Compare v0.0.9...v0.0.10](https://github.com/spectator/linked-list/compare/v0.0.9...v0.0.10)
56
+
57
+ # 0.0.9 / 2013-12-11
58
+
59
+ Initial release.
data/README.md CHANGED
@@ -41,17 +41,38 @@ list.unshift(object)
41
41
  list.pop
42
42
  list.shift
43
43
 
44
+ list.insert(object, before: object)
45
+ list.insert(object, before: ->(n) { n == 'foo' })
46
+
47
+ list.insert(object, after: object)
48
+ list.insert(object, after: ->(n) { n == 'foo' })
49
+
50
+ list.insert_before(object, node)
51
+ list.insert_after(object, node)
52
+
44
53
  list.reverse
45
54
  list.reverse!
46
55
 
47
- list.each # Enumerator object
56
+ list.delete(object)
57
+ list.delete { |n| n == 'foo' }
58
+
59
+ list.delete_all(object)
60
+ list.delete_all { |n| n == 'foo' }
61
+
62
+ list.each # Enumerator object
48
63
  list.each { |e| puts e }
49
64
 
50
- list.first # head of the list
51
- list.last # tail of the list
65
+ list.reverse_each # Enumerator object
66
+ list.reverse_each { |e| puts e }
67
+
68
+ list.reverse_each_node # Enumerator object
69
+ list.reverse_each_node { |node| puts node.data }
70
+
71
+ list.first # head of the list
72
+ list.last # tail of the list
52
73
 
53
74
  list.length
54
- list.size # same as `length`
75
+ list.size # same as `length`
55
76
 
56
77
  list.to_a
57
78
  ```
@@ -76,10 +97,6 @@ List([object, object]) # will return new `List` object with two `Node` objects
76
97
  Please see `LinkedList::List`, `LinkedList::Node`, and
77
98
  `LinkedList::Conversions` for details.
78
99
 
79
- ## TODO
80
-
81
- * Insert / delete in the middle
82
-
83
100
  ## Tests
84
101
 
85
102
  Run test with
@@ -12,8 +12,7 @@ module LinkedList
12
12
  # New +Node+ object.
13
13
  #
14
14
  def Node(arg)
15
- case arg
16
- when ->(_arg) { _arg.respond_to?(:to_node) }
15
+ if arg.respond_to?(:to_node)
17
16
  arg.to_node
18
17
  else
19
18
  Node.new(arg)
@@ -31,10 +30,9 @@ module LinkedList
31
30
  # New +List+ object.
32
31
  #
33
32
  def List(arg)
34
- case arg
35
- when ->(_arg) { _arg.respond_to?(:to_list) }
33
+ if arg.respond_to?(:to_list)
36
34
  arg.to_list
37
- when ->(_arg) { _arg.respond_to?(:to_ary) }
35
+ elsif arg.respond_to?(:to_ary)
38
36
  arg.to_ary.each_with_object(List.new) { |n, l| l.push(Node(n)) }
39
37
  else
40
38
  List.new.push(Node(arg))
@@ -4,7 +4,7 @@ module LinkedList
4
4
  class List
5
5
  include Conversions
6
6
 
7
- attr_reader :length
7
+ attr_reader :length
8
8
  alias_method :size, :length
9
9
 
10
10
  def initialize
@@ -69,6 +69,98 @@ module LinkedList
69
69
  self
70
70
  end
71
71
 
72
+ # Inserts after or before first matched node.data from the the list by passed block or value.
73
+ #
74
+ # == Returns:
75
+ # Inserted node data
76
+ #
77
+ def insert(to_add, after: nil, before: nil)
78
+ if after && before || !after && !before
79
+ raise ArgumentError, 'either :after or :before keys should be passed'
80
+ end
81
+ matcher = after || before
82
+ matcher_proc = if matcher.is_a?(Proc)
83
+ __to_matcher(&matcher)
84
+ else
85
+ __to_matcher(matcher)
86
+ end
87
+ node = each_node.find(&matcher_proc)
88
+ return unless node
89
+ new_node = after ? insert_after_node(to_add, node) : insert_before_node(to_add, node)
90
+ new_node.data
91
+ end
92
+
93
+ # Inserts data after first matched node.data.
94
+ #
95
+ # == Returns:
96
+ # Inserted node
97
+ #
98
+ def insert_after_node(data, node)
99
+ Node(data).tap do |new_node|
100
+ new_node.prev = node
101
+ new_node.next = node.next
102
+ if node.next
103
+ node.next.prev = new_node
104
+ else
105
+ @tail = new_node
106
+ end
107
+ node.next = new_node
108
+ @length += 1
109
+ end
110
+ end
111
+
112
+ # Inserts data before first matched node.data.
113
+ #
114
+ # == Returns:
115
+ # Inserted node
116
+ #
117
+ def insert_before_node(data, node)
118
+ Node(data).tap do |new_node|
119
+ new_node.next = node
120
+ new_node.prev = node.prev
121
+ if node.prev
122
+ node.prev.next = new_node
123
+ else
124
+ @head = new_node
125
+ end
126
+ node.prev = new_node
127
+ @length += 1
128
+ end
129
+ end
130
+
131
+ # Removes first matched node.data from the the list by passed block or value.
132
+ #
133
+ # If +val+ is a +Node+, removes that node from the list. Behavior is
134
+ # undefined if +val+ is a +Node+ that's not a member of this list.
135
+ #
136
+ # == Returns:
137
+ # Deleted node's data
138
+ #
139
+ def delete(val = nil, &block)
140
+ if val.respond_to?(:to_node)
141
+ node = val.to_node
142
+ __unlink_node(node)
143
+ return node.data
144
+ end
145
+
146
+ each_node.find(&__to_matcher(val, &block)).tap do |node_to_delete|
147
+ return unless node_to_delete
148
+ __unlink_node(node_to_delete)
149
+ end.data
150
+ end
151
+
152
+ # Removes all matched data.data from the the list by passed block or value.
153
+ #
154
+ # == Returns:
155
+ # Array of deleted nodes
156
+ #
157
+ def delete_all(val = nil, &block)
158
+ each_node.select(&__to_matcher(val, &block)).each do |node_to_delete|
159
+ next unless node_to_delete
160
+ __unlink_node(node_to_delete)
161
+ end.map(&:data)
162
+ end
163
+
72
164
  # Removes data from the end of the list.
73
165
  #
74
166
  # == Returns:
@@ -136,6 +228,41 @@ module LinkedList
136
228
  __each { |node| yield(node.data) }
137
229
  end
138
230
 
231
+ # Iterates over nodes from top to bottom passing node(LinkedList::Node instance)
232
+ # to the block if given. If no block given, returns +Enumerator+.
233
+ #
234
+ # == Returns:
235
+ # +Enumerator+ or yields list nodes to the block
236
+ #
237
+ def each_node
238
+ return to_enum(__callee__) unless block_given?
239
+ __each { |node| yield(node) }
240
+ end
241
+
242
+
243
+ # Iterates over nodes from bottom to top passing node data to the block if
244
+ # given. If no block given, returns +Enumerator+.
245
+ #
246
+ # == Returns:
247
+ # +Enumerator+ or yields data to the block stored in every node on the
248
+ # list.
249
+ #
250
+ def reverse_each
251
+ return to_enum(__callee__) unless block_given?
252
+ __reverse_each { |node| yield(node.data) }
253
+ end
254
+
255
+ # Iterates over nodes from bottom to top passing node(LinkedList::Node instance)
256
+ # to the block if given. If no block given, returns +Enumerator+.
257
+ #
258
+ # == Returns:
259
+ # +Enumerator+ or yields list nodes to the block
260
+ #
261
+ def reverse_each_node
262
+ return to_enum(__callee__) unless block_given?
263
+ __reverse_each { |node| yield(node) }
264
+ end
265
+
139
266
  # Converts list to array.
140
267
  #
141
268
  def to_a
@@ -158,6 +285,26 @@ module LinkedList
158
285
 
159
286
  private
160
287
 
288
+ def __unlink_node(node)
289
+ @head = node.next if node.prev.nil?
290
+ @tail = node.prev if node.next.nil?
291
+
292
+ if node.prev.nil?
293
+ node.next.prev = nil if node.next
294
+ elsif node.next.nil?
295
+ node.prev.next = nil if node.prev
296
+ else
297
+ node.prev.next, node.next.prev = node.next, node.prev
298
+ end
299
+ @length -= 1
300
+ end
301
+
302
+ def __to_matcher(val = nil, &block)
303
+ raise ArgumentError, 'either value or block should be passed' if val && block_given?
304
+ block = ->(e) { e == val } unless block_given?
305
+ ->(node) { block.call(node.data) }
306
+ end
307
+
161
308
  def __shift
162
309
  head = @head
163
310
  @head = @head.next
@@ -172,6 +319,14 @@ module LinkedList
172
319
  tail
173
320
  end
174
321
 
322
+ def __reverse_each
323
+ curr_node = @tail
324
+ while(curr_node)
325
+ yield curr_node
326
+ curr_node = curr_node.prev
327
+ end
328
+ end
329
+
175
330
  def __each
176
331
  curr_node = @head
177
332
  while(curr_node)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Linked
4
4
  module List
5
- VERSION = '0.0.10'
5
+ VERSION = '0.0.15'
6
6
  end
7
7
  end
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Linked::List::VERSION
9
9
  spec.authors = ['Yury Velikanau']
10
10
  spec.email = ['yury.velikanau@gmail.com']
11
- spec.description = %q{Ruby implementation of Doubly Linked List, following some Ruby idioms.}
12
- spec.summary = %q{Ruby implementation of Doubly Linked List, following some Ruby idioms.}
11
+ spec.description = %q(Ruby implementation of Doubly Linked List, following some Ruby idioms.)
12
+ spec.summary = %q(Ruby implementation of Doubly Linked List, following some Ruby idioms.)
13
13
  spec.homepage = 'https://github.com/spectator/linked-list'
14
14
  spec.license = 'MIT'
15
15
 
@@ -18,8 +18,9 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ['lib']
20
20
 
21
- spec.add_development_dependency 'rake'
22
- spec.add_development_dependency 'bundler', '>= 1.3', '<= 2.0'
21
+ spec.add_development_dependency 'bundler', '>= 2.0', '< 3.0'
22
+ spec.add_development_dependency 'coveralls', '~> 0'
23
+ spec.add_development_dependency 'm', '~> 1.5', '>= 1.5.0'
23
24
  spec.add_development_dependency 'minitest', '>= 5.0', '<= 6.0'
24
- spec.add_development_dependency 'coveralls'
25
+ spec.add_development_dependency 'rake', '>= 12.3.3'
25
26
  end
@@ -4,6 +4,7 @@ describe LinkedList::List do
4
4
  let(:list) { create_list }
5
5
  let(:node_1) { create_node('foo') }
6
6
  let(:node_2) { create_node('bar') }
7
+ let(:node_3) { create_node('baz') }
7
8
 
8
9
  describe 'instantiation' do
9
10
  it 'assigns first to nil' do
@@ -134,6 +135,486 @@ describe LinkedList::List do
134
135
  end
135
136
  end
136
137
 
138
+ describe '#insert' do
139
+ it 'raises error if after and before are passed' do
140
+ err = assert_raises ArgumentError do
141
+ assert_nil list.insert(1, after: 'x', before: 'y')
142
+ end
143
+ assert_equal err.message, 'either :after or :before keys should be passed'
144
+ end
145
+
146
+ it 'raises error if no after nore before are passed' do
147
+ err = assert_raises ArgumentError do
148
+ assert_nil list.insert(1)
149
+ end
150
+ assert_equal err.message, 'either :after or :before keys should be passed'
151
+ end
152
+
153
+ describe 'after:' do
154
+ describe 'by block' do
155
+ it 'does not add value if insert after not found' do
156
+ list.push('foo')
157
+ assert_nil list.insert(1, after: ->(d) { d == 'foo1' })
158
+ assert_equal ['foo'], list.to_a
159
+ end
160
+
161
+ it 'inserts value after first matching node by block' do
162
+ list.push('foo')
163
+ list.push('bar')
164
+ assert_equal 1, list.insert(1, after: ->(d) { d == 'foo' })
165
+ assert_equal ['foo', 1, 'bar'], list.to_a
166
+ assert_equal 3, list.length
167
+ end
168
+
169
+ describe 'position edge cases' do
170
+ before do
171
+ list.push(0)
172
+ list.push(1)
173
+ list.push(2)
174
+ end
175
+
176
+ it 'inserts after in the middle' do
177
+ list.insert('foo', after: ->(d) { d == 0 })
178
+ assert_equal [0, 'foo', 1, 2], list.to_a
179
+ end
180
+
181
+ it 'inserts after the tail' do
182
+ list.insert('foo', after: ->(d) { d == 2 })
183
+ assert_equal [0, 1, 2, 'foo'], list.to_a
184
+ assert_equal 'foo', list.last
185
+ end
186
+ end
187
+ end
188
+
189
+ describe 'by value' do
190
+ it 'does not add value if insert after not found' do
191
+ list.push('foo')
192
+ assert_nil list.insert(1, after: 'foo1')
193
+ assert_equal ['foo'], list.to_a
194
+ end
195
+
196
+ it 'inserts value after first matching node by block' do
197
+ list.push('foo')
198
+ list.push('bar')
199
+ assert_equal 1, list.insert(1, after: 'foo')
200
+ assert_equal ['foo', 1, 'bar'], list.to_a
201
+ assert_equal 3, list.length
202
+ end
203
+
204
+ describe 'position edge cases' do
205
+ before do
206
+ list.push(0)
207
+ list.push(1)
208
+ list.push(2)
209
+ end
210
+
211
+ it 'inserts after in the middle' do
212
+ list.insert('foo', after: 0)
213
+ assert_equal [0, 'foo', 1, 2], list.to_a
214
+ end
215
+
216
+ it 'inserts after the tail' do
217
+ list.insert('foo', after: 2)
218
+ assert_equal [0, 1, 2, 'foo'], list.to_a
219
+ assert_equal 'foo', list.last
220
+ end
221
+ end
222
+ end
223
+ end
224
+
225
+ describe ':before' do
226
+ describe 'by block' do
227
+ it 'does not add value if insert before not found' do
228
+ list.push('foo')
229
+ assert_nil list.insert(1, before: ->(d) { d == 'foo1' })
230
+ assert_equal ['foo'], list.to_a
231
+ end
232
+
233
+ it 'inserts value before first matching node by block' do
234
+ list.push('foo')
235
+ list.push('bar')
236
+ assert_equal 1, list.insert(1, before: ->(d) { d == 'foo' })
237
+ assert_equal [1, 'foo', 'bar'], list.to_a
238
+ assert_equal 3, list.length
239
+ end
240
+
241
+ describe 'position edge cases' do
242
+ before do
243
+ list.push(0)
244
+ list.push(1)
245
+ list.push(2)
246
+ end
247
+
248
+ it 'inserts before head' do
249
+ list.insert('foo', before: ->(d) { d == 0 })
250
+ assert_equal ['foo', 0, 1, 2], list.to_a
251
+ assert_equal 'foo', list.first
252
+ end
253
+
254
+ it 'inserts before in the middle' do
255
+ list.insert('foo', before: ->(d) { d == 2 })
256
+ assert_equal [0, 1, 'foo', 2], list.to_a
257
+ end
258
+ end
259
+ end
260
+
261
+ describe 'by value' do
262
+ it 'does not add value if insert before not found' do
263
+ list.push('foo')
264
+ assert_nil list.insert(1, before: 'foo1')
265
+ assert_equal ['foo'], list.to_a
266
+ end
267
+
268
+ it 'inserts value before first' do
269
+ list.push('foo')
270
+ list.push('bar')
271
+ assert_equal 1, list.insert(1, before: 'foo')
272
+ assert_equal [1, 'foo', 'bar'], list.to_a
273
+ assert_equal 3, list.length
274
+ end
275
+
276
+ describe 'position edge cases' do
277
+ before do
278
+ list.push(0)
279
+ list.push(1)
280
+ list.push(2)
281
+ end
282
+
283
+ it 'inserts before head' do
284
+ list.insert('foo', before: 0)
285
+ assert_equal ['foo', 0, 1, 2], list.to_a
286
+ assert_equal 'foo', list.first
287
+ end
288
+
289
+ it 'inserts before in the middle' do
290
+ list.insert('foo', before: 2)
291
+ assert_equal [0, 1, 'foo', 2], list.to_a
292
+ end
293
+ end
294
+ end
295
+ end
296
+ end
297
+
298
+ describe '#insert_after_node' do
299
+ it 'inserts value after passed node' do
300
+ list.push('foo')
301
+ list.push('bar')
302
+ node = list.each_node.find { |n| n.data == 'foo' }
303
+ assert_equal 1, list.insert_after_node(1, node).data
304
+ assert_equal ['foo', 1, 'bar'], list.to_a
305
+ assert_equal 3, list.length
306
+ end
307
+
308
+ describe 'position edge cases' do
309
+ before do
310
+ list.push(0)
311
+ list.push(1)
312
+ list.push(2)
313
+ end
314
+
315
+ it 'inserts after in the middle' do
316
+ node = list.each_node.find { |n| n.data == 0 }
317
+ list.insert_after_node('foo', node)
318
+ assert_equal [0, 'foo', 1, 2], list.to_a
319
+ end
320
+
321
+ it 'inserts after the tail' do
322
+ node = list.each_node.find { |n| n.data == 2 }
323
+ list.insert_after_node('foo', node)
324
+ assert_equal [0, 1, 2, 'foo'], list.to_a
325
+ assert_equal 'foo', list.last
326
+ end
327
+ end
328
+ end
329
+
330
+ describe '#insert_after_node' do
331
+ it 'inserts value before first' do
332
+ list.push('foo')
333
+ list.push('bar')
334
+ node = list.each_node.find { |n| n.data == 'foo' }
335
+ assert_equal 1, list.insert_before_node(1, node).data
336
+ assert_equal [1, 'foo', 'bar'], list.to_a
337
+ assert_equal 3, list.length
338
+ end
339
+
340
+ describe 'position edge cases' do
341
+ before do
342
+ list.push(0)
343
+ list.push(1)
344
+ list.push(2)
345
+ end
346
+
347
+ it 'inserts before head' do
348
+ node = list.each_node.find { |n| n.data == 0 }
349
+ list.insert_before_node('foo', node)
350
+ assert_equal ['foo', 0, 1, 2], list.to_a
351
+ assert_equal 'foo', list.first
352
+ end
353
+
354
+ it 'inserts before in the middle' do
355
+ node = list.each_node.find { |n| n.data == 2 }
356
+ list.insert_before_node('foo', node)
357
+ assert_equal [0, 1, 'foo', 2], list.to_a
358
+ end
359
+ end
360
+ end
361
+
362
+ describe '#delete' do
363
+ it 'raises error if block and value are passed' do
364
+ err = assert_raises ArgumentError do
365
+ assert_nil list.delete('x') { |d| d == 'x' }
366
+ end
367
+ assert_equal err.message, 'either value or block should be passed'
368
+ end
369
+
370
+ describe 'by block' do
371
+ it 'returns nil if list is empty' do
372
+ assert_nil list.delete { |d| d == 'x' }
373
+ end
374
+
375
+ it 'deletes value in first matching node' do
376
+ calls_count = 0
377
+ list.push('foo')
378
+ list.push('foo')
379
+ list.push('bar')
380
+ list.push('foo')
381
+ list.delete { |d| calls_count += 1;d == 'bar' }
382
+ assert_equal ['foo', 'foo', 'foo'], list.to_a
383
+ assert_equal 3, calls_count
384
+ end
385
+
386
+ it 'returns deleted value' do
387
+ list.push('foo')
388
+ assert_equal 'foo', list.delete { |d| d == 'foo' }
389
+ end
390
+
391
+ it 'decreases length of list' do
392
+ list.push('foo')
393
+ list.push('bar')
394
+ list.push('foo')
395
+ list.delete { |d| d == 'foo' }
396
+ assert_equal 2, list.length
397
+ assert_equal ['bar', 'foo'], list.to_a
398
+ end
399
+
400
+ describe 'position edge cases' do
401
+ before do
402
+ list.push(0)
403
+ list.push(1)
404
+ list.push(2)
405
+ end
406
+
407
+ it 'deletes value from head' do
408
+ list.delete { |d| d == 0 }
409
+ assert_equal [1, 2], list.to_a
410
+ assert_equal 1, list.first
411
+ end
412
+
413
+ it 'deletes value from middle' do
414
+ list.delete { |d| d == 1 }
415
+ assert_equal [0, 2], list.to_a
416
+ end
417
+
418
+ it 'deletes value from tail' do
419
+ list.delete { |d| d == 2 }
420
+ assert_equal [0, 1], list.to_a
421
+ assert_equal 1, list.last
422
+ end
423
+ end
424
+ end
425
+
426
+ describe 'by data equality' do
427
+ it 'returns nil if list is empty' do
428
+ assert_nil list.delete('x')
429
+ end
430
+
431
+ it 'deletes value in first node' do
432
+ list.push('foo')
433
+ list.push('foo')
434
+ list.push('bar')
435
+ list.push('foo')
436
+ list.delete('foo')
437
+ assert_equal ['foo', 'bar', 'foo'], list.to_a
438
+ end
439
+
440
+ it 'returns deleted value' do
441
+ list.push('foo')
442
+ assert_equal 'foo', list.delete('foo')
443
+ end
444
+
445
+ it 'decreases length of list' do
446
+ list.push('foo')
447
+ list.push('bar')
448
+ list.push('foo')
449
+ list.delete('foo')
450
+ assert_equal 2, list.length
451
+ assert_equal ['bar', 'foo'], list.to_a
452
+ end
453
+
454
+ describe 'position edge cases' do
455
+ before do
456
+ list.push(0)
457
+ list.push(1)
458
+ list.push(2)
459
+ end
460
+
461
+ it 'deletes value from head' do
462
+ list.delete(0)
463
+ assert_equal [1, 2], list.to_a
464
+ assert_equal 1, list.first
465
+ end
466
+
467
+ it 'deletes value from middle' do
468
+ list.delete(1)
469
+ assert_equal [0, 2], list.to_a
470
+ end
471
+
472
+
473
+ it 'deletes value from tail' do
474
+ list.delete(2)
475
+ assert_equal [0, 1], list.to_a
476
+ assert_equal 1, list.last
477
+ end
478
+ end
479
+ end
480
+
481
+ describe 'by node' do
482
+ it 'deletes first node' do
483
+ list.push(node_1)
484
+ list.push(node_2)
485
+ list.push(node_3)
486
+ list.delete(node_1)
487
+ assert_equal ['bar', 'baz'], list.to_a
488
+ end
489
+
490
+ it 'returns deleted value' do
491
+ list.push(node_1)
492
+ list.delete(node_1)
493
+ assert_equal node_1.data, list.delete(node_1)
494
+ end
495
+
496
+ it 'decreases length of list' do
497
+ list.push('foo')
498
+ list.push('bar')
499
+ list.push('baz')
500
+ list.delete('foo')
501
+ assert_equal 2, list.length
502
+ end
503
+
504
+ describe 'position edge cases' do
505
+ before do
506
+ list.push(node_1)
507
+ list.push(node_2)
508
+ list.push(node_3)
509
+ end
510
+
511
+ it 'deletes value from head' do
512
+ list.delete(node_1)
513
+ assert_equal [node_2.data, node_3.data], list.to_a
514
+ assert_equal node_2.data, list.first
515
+ assert_equal node_3.data, list.last
516
+ end
517
+
518
+ it 'deletes value from middle' do
519
+ list.delete(node_2)
520
+ assert_equal [node_1.data, node_3.data], list.to_a
521
+ assert_equal node_1.data, list.first
522
+ assert_equal node_3.data, list.last
523
+ end
524
+
525
+
526
+ it 'deletes value from tail' do
527
+ list.delete(node_3)
528
+ assert_equal [node_1.data, node_2.data], list.to_a
529
+ assert_equal node_1.data, list.first
530
+ assert_equal node_2.data, list.last
531
+ end
532
+ end
533
+
534
+ describe 'delete edge cases' do
535
+ it 'resets original list state when deleting the last node of the list' do
536
+ assert_nil list.first
537
+ assert_nil list.last
538
+
539
+ list.push(node_1)
540
+ assert_equal node_1.data, list.first
541
+ assert_equal node_1.data, list.last
542
+
543
+ list.delete(node_1)
544
+ assert_nil list.first
545
+ assert_nil list.last
546
+ end
547
+ end
548
+ end
549
+ end
550
+
551
+ describe '#delete_all' do
552
+ it 'raises error if block and value are passed' do
553
+ err = assert_raises ArgumentError do
554
+ assert_nil list.delete_all('x') { |d| d == 'x' }
555
+ end
556
+ assert_equal err.message, 'either value or block should be passed'
557
+ end
558
+
559
+ describe 'by block' do
560
+ it 'returns nil if list is empty' do
561
+ assert_equal list.delete_all { |d| d == 'x' }, []
562
+ end
563
+
564
+ it 'deletes value in first matching node' do
565
+ list.push('foo')
566
+ list.push('foo')
567
+ list.push('bar')
568
+ list.push('foo')
569
+ list.delete_all { |d| d == 'foo' }
570
+ assert_equal ['bar'], list.to_a
571
+ end
572
+
573
+ it 'returns deleted value' do
574
+ list.push('foo')
575
+ assert_equal ['foo'], list.delete_all { |d| d == 'foo' }
576
+ end
577
+
578
+ it 'decreases length of list' do
579
+ list.push('foo')
580
+ list.push('bar')
581
+ list.push('foo')
582
+ list.delete_all { |d| d == 'foo' }
583
+ assert_equal 1, list.length
584
+ assert_equal ['bar'], list.to_a
585
+ end
586
+ end
587
+
588
+ describe 'by data equality' do
589
+ it 'returns nil if list is empty' do
590
+ assert_nil list.delete('x')
591
+ end
592
+
593
+ it 'deletes all matched values' do
594
+ list.push('foo')
595
+ list.push('foo')
596
+ list.push('bar')
597
+ list.push('foo')
598
+ list.delete_all('foo')
599
+ assert_equal ['bar'], list.to_a
600
+ end
601
+
602
+ it 'returns deleted value' do
603
+ list.push('foo')
604
+ assert_equal ['foo'], list.delete_all('foo')
605
+ end
606
+
607
+ it 'decreases length of list' do
608
+ list.push('foo')
609
+ list.push('bar')
610
+ list.push('foo')
611
+ list.delete_all('foo')
612
+ assert_equal 1, list.length
613
+ assert_equal ['bar'], list.to_a
614
+ end
615
+ end
616
+ end
617
+
137
618
  describe '#shift' do
138
619
  it 'returns nil if list is empty' do
139
620
  assert_nil list.shift
@@ -200,6 +681,21 @@ describe LinkedList::List do
200
681
  end
201
682
  end
202
683
 
684
+ describe '#each_node' do
685
+ it 'returns enumerator if no block given' do
686
+ assert_instance_of Enumerator, list.each_node
687
+ end
688
+
689
+ it 'pass each node data to the block' do
690
+ list.push(node_1)
691
+ list.push(node_2)
692
+ nodes = []
693
+ list.each_node { |e| nodes << e }
694
+ assert_equal %w(foo bar), nodes.map(&:data)
695
+ assert_equal true, nodes.all? { |n| n.is_a?(LinkedList::Node) }
696
+ end
697
+ end
698
+
203
699
  describe '#each' do
204
700
  it 'returns enumerator if no block given' do
205
701
  assert_instance_of Enumerator, list.each
@@ -214,6 +710,48 @@ describe LinkedList::List do
214
710
  end
215
711
  end
216
712
 
713
+ describe '#each_node' do
714
+ it 'returns enumerator if no block given' do
715
+ assert_instance_of Enumerator, list.each
716
+ end
717
+
718
+ it 'pass each node data to the block' do
719
+ list.push(node_1)
720
+ list.push(node_2)
721
+ nodes = []
722
+ list.each_node { |e| nodes << e }
723
+ assert_equal %w(foo bar), nodes.map(&:data)
724
+ end
725
+ end
726
+
727
+ describe '#reverse_each' do
728
+ it 'returns enumerator if no block given' do
729
+ assert_instance_of Enumerator, list.each
730
+ end
731
+
732
+ it 'pass each node data to the block' do
733
+ list.push(node_1)
734
+ list.push(node_2)
735
+ nodes = []
736
+ list.reverse_each { |e| nodes << e }
737
+ assert_equal %w(bar foo), nodes
738
+ end
739
+ end
740
+
741
+ describe '#reverse_each_node' do
742
+ it 'returns enumerator if no block given' do
743
+ assert_instance_of Enumerator, list.each
744
+ end
745
+
746
+ it 'pass each node data to the block' do
747
+ list.push(node_1)
748
+ list.push(node_2)
749
+ nodes = []
750
+ list.reverse_each_node { |e| nodes << e }
751
+ assert_equal %w(bar foo), nodes.map(&:data)
752
+ end
753
+ end
754
+
217
755
  describe '#inspect' do
218
756
  it 'includes class name' do
219
757
  assert_match(/LinkedList::List/, list.inspect)
@@ -1,5 +1,7 @@
1
- require 'coveralls'
2
- Coveralls.wear!
1
+ if ENV['CI']
2
+ require 'coveralls'
3
+ Coveralls.wear!
4
+ end
3
5
 
4
6
  require 'linked-list'
5
7
 
metadata CHANGED
@@ -1,49 +1,69 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: linked-list
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.10
4
+ version: 0.0.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yury Velikanau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-03 00:00:00.000000000 Z
11
+ date: 2020-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rake
14
+ name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '2.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '3.0'
20
23
  type: :development
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '2.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '3.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: coveralls
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
25
45
  - !ruby/object:Gem::Version
26
46
  version: '0'
27
47
  - !ruby/object:Gem::Dependency
28
- name: bundler
48
+ name: m
29
49
  requirement: !ruby/object:Gem::Requirement
30
50
  requirements:
31
- - - ">="
51
+ - - "~>"
32
52
  - !ruby/object:Gem::Version
33
- version: '1.3'
34
- - - "<="
53
+ version: '1.5'
54
+ - - ">="
35
55
  - !ruby/object:Gem::Version
36
- version: '2.0'
56
+ version: 1.5.0
37
57
  type: :development
38
58
  prerelease: false
39
59
  version_requirements: !ruby/object:Gem::Requirement
40
60
  requirements:
41
- - - ">="
61
+ - - "~>"
42
62
  - !ruby/object:Gem::Version
43
- version: '1.3'
44
- - - "<="
63
+ version: '1.5'
64
+ - - ">="
45
65
  - !ruby/object:Gem::Version
46
- version: '2.0'
66
+ version: 1.5.0
47
67
  - !ruby/object:Gem::Dependency
48
68
  name: minitest
49
69
  requirement: !ruby/object:Gem::Requirement
@@ -65,19 +85,19 @@ dependencies:
65
85
  - !ruby/object:Gem::Version
66
86
  version: '6.0'
67
87
  - !ruby/object:Gem::Dependency
68
- name: coveralls
88
+ name: rake
69
89
  requirement: !ruby/object:Gem::Requirement
70
90
  requirements:
71
91
  - - ">="
72
92
  - !ruby/object:Gem::Version
73
- version: '0'
93
+ version: 12.3.3
74
94
  type: :development
75
95
  prerelease: false
76
96
  version_requirements: !ruby/object:Gem::Requirement
77
97
  requirements:
78
98
  - - ">="
79
99
  - !ruby/object:Gem::Version
80
- version: '0'
100
+ version: 12.3.3
81
101
  description: Ruby implementation of Doubly Linked List, following some Ruby idioms.
82
102
  email:
83
103
  - yury.velikanau@gmail.com
@@ -89,6 +109,7 @@ extra_rdoc_files: []
89
109
  files:
90
110
  - ".gitignore"
91
111
  - ".travis.yml"
112
+ - CHANGELOG.md
92
113
  - Gemfile
93
114
  - LICENSE.txt
94
115
  - README.md
@@ -124,8 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
145
  - !ruby/object:Gem::Version
125
146
  version: '0'
126
147
  requirements: []
127
- rubyforge_project:
128
- rubygems_version: 2.7.6
148
+ rubygems_version: 3.1.2
129
149
  signing_key:
130
150
  specification_version: 4
131
151
  summary: Ruby implementation of Doubly Linked List, following some Ruby idioms.