linked-list 0.0.10 → 0.0.11
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/.travis.yml +2 -2
- data/CHANGELOG.md +17 -0
- data/README.md +4 -1
- data/lib/linked-list/conversions.rb +3 -5
- data/lib/linked-list/list.rb +55 -1
- data/lib/linked-list/version.rb +1 -1
- data/linked-list.gemspec +6 -5
- data/test/list_test.rb +202 -0
- metadata +29 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 203cf979a2f074eaa22dd987096ecf8ec298198344ddf1f8cafafca20be8552b
|
4
|
+
data.tar.gz: e8fc8a7584f411444d4685aa3c9ecc7328a2ba59f1f0e0de55a1abb2130ff63f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4e87238b13c8a4621ff4b30502f6d4295df7f9ad7a219144bfcdbea24c7676b859767f53b3070ac11707576f639a8f1323bd1e96903bcba76403c1a865a2d552
|
7
|
+
data.tar.gz: 9419f5694a938f436084247464b016c213b8914fdbcc3a255eed8fffbe21164938f6b10f27aac2187d985995c1120b6bbc581ea6c295a8fd7da45f5acbe01655
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# 0.0.11 / 2018-04-02
|
2
|
+
|
3
|
+
## Added
|
4
|
+
|
5
|
+
- Added `delete` and `delete_all` methods (mpospelov in [#2](https://github.com/spectator/linked-list/pull/2))
|
6
|
+
|
7
|
+
# 0.0.10 / 2018-04-02
|
8
|
+
|
9
|
+
## Fixed
|
10
|
+
|
11
|
+
- 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))
|
12
|
+
|
13
|
+
[Compare v0.0.9...v0.0.10](https://github.com/spectator/linked-list/compare/v0.0.9...v0.0.10)
|
14
|
+
|
15
|
+
# 0.0.9 / 2013-12-11
|
16
|
+
|
17
|
+
Initial release.
|
data/README.md
CHANGED
@@ -44,6 +44,9 @@ list.shift
|
|
44
44
|
list.reverse
|
45
45
|
list.reverse!
|
46
46
|
|
47
|
+
list.delete(object)
|
48
|
+
list.delete_all(object)
|
49
|
+
|
47
50
|
list.each # Enumerator object
|
48
51
|
list.each { |e| puts e }
|
49
52
|
|
@@ -78,7 +81,7 @@ Please see `LinkedList::List`, `LinkedList::Node`, and
|
|
78
81
|
|
79
82
|
## TODO
|
80
83
|
|
81
|
-
* Insert
|
84
|
+
* Insert in the middle
|
82
85
|
|
83
86
|
## Tests
|
84
87
|
|
@@ -12,8 +12,7 @@ module LinkedList
|
|
12
12
|
# New +Node+ object.
|
13
13
|
#
|
14
14
|
def Node(arg)
|
15
|
-
|
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
|
-
|
35
|
-
when ->(_arg) { _arg.respond_to?(:to_list) }
|
33
|
+
if arg.respond_to?(:to_list)
|
36
34
|
arg.to_list
|
37
|
-
|
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))
|
data/lib/linked-list/list.rb
CHANGED
@@ -4,7 +4,7 @@ module LinkedList
|
|
4
4
|
class List
|
5
5
|
include Conversions
|
6
6
|
|
7
|
-
attr_reader
|
7
|
+
attr_reader :length
|
8
8
|
alias_method :size, :length
|
9
9
|
|
10
10
|
def initialize
|
@@ -69,6 +69,30 @@ module LinkedList
|
|
69
69
|
self
|
70
70
|
end
|
71
71
|
|
72
|
+
# Removes first matched node.data from the the list by passed block or value.
|
73
|
+
#
|
74
|
+
# == Returns:
|
75
|
+
# Deleted node
|
76
|
+
#
|
77
|
+
def delete(val = nil, &block)
|
78
|
+
each_node.find(&__to_matcher(val, &block)).tap do |node_to_delete|
|
79
|
+
return if node_to_delete.blank?
|
80
|
+
__unlink(node_to_delete)
|
81
|
+
end.data
|
82
|
+
end
|
83
|
+
|
84
|
+
# Removes all matched data.data from the the list by passed block or value.
|
85
|
+
#
|
86
|
+
# == Returns:
|
87
|
+
# Array of deleted nodes
|
88
|
+
#
|
89
|
+
def delete_all(val = nil, &block)
|
90
|
+
each_node.select(&__to_matcher(val, &block)).each do |node_to_delete|
|
91
|
+
next if node_to_delete.blank?
|
92
|
+
__unlink(node_to_delete)
|
93
|
+
end.map(&:data)
|
94
|
+
end
|
95
|
+
|
72
96
|
# Removes data from the end of the list.
|
73
97
|
#
|
74
98
|
# == Returns:
|
@@ -136,6 +160,17 @@ module LinkedList
|
|
136
160
|
__each { |node| yield(node.data) }
|
137
161
|
end
|
138
162
|
|
163
|
+
# Iterates over nodes from top to bottom passing node(LinkedList::Node instance)
|
164
|
+
# to the block if given. If no block given, returns +Enumerator+.
|
165
|
+
#
|
166
|
+
# == Returns:
|
167
|
+
# +Enumerator+ or yields list nodes to the block
|
168
|
+
#
|
169
|
+
def each_node
|
170
|
+
return to_enum(__callee__) unless block_given?
|
171
|
+
__each { |node| yield(node) }
|
172
|
+
end
|
173
|
+
|
139
174
|
# Converts list to array.
|
140
175
|
#
|
141
176
|
def to_a
|
@@ -158,6 +193,25 @@ module LinkedList
|
|
158
193
|
|
159
194
|
private
|
160
195
|
|
196
|
+
def __to_matcher(val = nil, &block)
|
197
|
+
raise ArgumentError, 'either value or block should be passed' if val && block_given?
|
198
|
+
block = ->(e) { e == val } unless block_given?
|
199
|
+
-> (node) { block.call(node.data) }
|
200
|
+
end
|
201
|
+
|
202
|
+
def __unlink(node)
|
203
|
+
if node.prev.blank?
|
204
|
+
node.next.prev = nil if node.next
|
205
|
+
@head = node.next
|
206
|
+
elsif node.next.blank?
|
207
|
+
node.prev.next = nil if node.prev
|
208
|
+
@tail = node.prev
|
209
|
+
else
|
210
|
+
node.prev.next, node.next.prev = node.next, node.prev
|
211
|
+
end
|
212
|
+
@length -= 1
|
213
|
+
end
|
214
|
+
|
161
215
|
def __shift
|
162
216
|
head = @head
|
163
217
|
@head = @head.next
|
data/lib/linked-list/version.rb
CHANGED
data/linked-list.gemspec
CHANGED
@@ -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
|
12
|
-
spec.summary = %q
|
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 '
|
22
|
-
spec.add_development_dependency 'bundler', '>= 1.3', '<= 2.0'
|
23
|
-
spec.add_development_dependency 'minitest', '>= 5.0', '<= 6.0'
|
21
|
+
spec.add_development_dependency 'bundler', '>= 1.3', '<= 2.0'
|
24
22
|
spec.add_development_dependency 'coveralls'
|
23
|
+
spec.add_development_dependency 'm', '~> 1.5.0'
|
24
|
+
spec.add_development_dependency 'minitest', '>= 5.0', '<= 6.0'
|
25
|
+
spec.add_development_dependency 'rake'
|
25
26
|
end
|
data/test/list_test.rb
CHANGED
@@ -134,6 +134,193 @@ describe LinkedList::List do
|
|
134
134
|
end
|
135
135
|
end
|
136
136
|
|
137
|
+
|
138
|
+
describe '#delete' do
|
139
|
+
it 'raises error if block and value are passed' do
|
140
|
+
err = assert_raises ArgumentError do
|
141
|
+
assert_nil list.delete('x') { |d| d == 'x' }
|
142
|
+
end
|
143
|
+
assert_equal err.message, 'either value or block should be passed'
|
144
|
+
end
|
145
|
+
|
146
|
+
describe 'by block' do
|
147
|
+
it 'returns nil if list is empty' do
|
148
|
+
assert_nil list.delete { |d| d == 'x' }
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'deletes value in first matching node' do
|
152
|
+
list.push('foo')
|
153
|
+
list.push('foo')
|
154
|
+
list.push('bar')
|
155
|
+
list.push('foo')
|
156
|
+
list.delete { |d| d == 'foo' }
|
157
|
+
assert_equal ['foo', 'bar', 'foo'], list.to_a
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'returns deleted value' do
|
161
|
+
list.push('foo')
|
162
|
+
assert_equal 'foo', list.delete { |d| d == 'foo' }
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'decreases length of list' do
|
166
|
+
list.push('foo')
|
167
|
+
list.push('bar')
|
168
|
+
list.push('foo')
|
169
|
+
list.delete { |d| d == 'foo' }
|
170
|
+
assert_equal 2, list.length
|
171
|
+
assert_equal ['bar', 'foo'], list.to_a
|
172
|
+
end
|
173
|
+
|
174
|
+
describe 'position edge cases' do
|
175
|
+
before do
|
176
|
+
list.push(0)
|
177
|
+
list.push(1)
|
178
|
+
list.push(2)
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'deletes value from head' do
|
182
|
+
list.delete { |d| d == 0 }
|
183
|
+
assert_equal [1, 2], list.to_a
|
184
|
+
assert_equal 1, list.first
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'deletes value from middle' do
|
188
|
+
list.delete { |d| d == 1 }
|
189
|
+
assert_equal [0, 2], list.to_a
|
190
|
+
end
|
191
|
+
|
192
|
+
|
193
|
+
it 'deletes value from tail' do
|
194
|
+
list.delete { |d| d == 2 }
|
195
|
+
assert_equal [0, 1], list.to_a
|
196
|
+
assert_equal 1, list.last
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
describe 'by data equality' do
|
202
|
+
it 'returns nil if list is empty' do
|
203
|
+
assert_nil list.delete('x')
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'deletes value in first node' do
|
207
|
+
list.push('foo')
|
208
|
+
list.push('foo')
|
209
|
+
list.push('bar')
|
210
|
+
list.push('foo')
|
211
|
+
list.delete('foo')
|
212
|
+
assert_equal ['foo', 'bar', 'foo'], list.to_a
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'returns deleted value' do
|
216
|
+
list.push('foo')
|
217
|
+
assert_equal 'foo', list.delete('foo')
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'decreases length of list' do
|
221
|
+
list.push('foo')
|
222
|
+
list.push('bar')
|
223
|
+
list.push('foo')
|
224
|
+
list.delete('foo')
|
225
|
+
assert_equal 2, list.length
|
226
|
+
assert_equal ['bar', 'foo'], list.to_a
|
227
|
+
end
|
228
|
+
|
229
|
+
describe 'position edge cases' do
|
230
|
+
before do
|
231
|
+
list.push(0)
|
232
|
+
list.push(1)
|
233
|
+
list.push(2)
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'deletes value from head' do
|
237
|
+
list.delete(0)
|
238
|
+
assert_equal [1, 2], list.to_a
|
239
|
+
assert_equal 1, list.first
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'deletes value from middle' do
|
243
|
+
list.delete(1)
|
244
|
+
assert_equal [0, 2], list.to_a
|
245
|
+
end
|
246
|
+
|
247
|
+
|
248
|
+
it 'deletes value from tail' do
|
249
|
+
list.delete(2)
|
250
|
+
assert_equal [0, 1], list.to_a
|
251
|
+
assert_equal 1, list.last
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
describe '#delete_all' do
|
258
|
+
it 'raises error if block and value are passed' do
|
259
|
+
err = assert_raises ArgumentError do
|
260
|
+
assert_nil list.delete_all('x') { |d| d == 'x' }
|
261
|
+
end
|
262
|
+
assert_equal err.message, 'either value or block should be passed'
|
263
|
+
end
|
264
|
+
|
265
|
+
describe 'by block' do
|
266
|
+
it 'returns nil if list is empty' do
|
267
|
+
assert_equal list.delete_all { |d| d == 'x' }, []
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'deletes value in first matching node' do
|
271
|
+
list.push('foo')
|
272
|
+
list.push('foo')
|
273
|
+
list.push('bar')
|
274
|
+
list.push('foo')
|
275
|
+
list.delete_all { |d| d == 'foo' }
|
276
|
+
assert_equal ['bar'], list.to_a
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'returns deleted value' do
|
280
|
+
list.push('foo')
|
281
|
+
assert_equal ['foo'], list.delete_all { |d| d == 'foo' }
|
282
|
+
end
|
283
|
+
|
284
|
+
it 'decreases length of list' do
|
285
|
+
list.push('foo')
|
286
|
+
list.push('bar')
|
287
|
+
list.push('foo')
|
288
|
+
list.delete_all { |d| d == 'foo' }
|
289
|
+
assert_equal 1, list.length
|
290
|
+
assert_equal ['bar'], list.to_a
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
describe 'by data equality' do
|
295
|
+
it 'returns nil if list is empty' do
|
296
|
+
assert_nil list.delete('x')
|
297
|
+
end
|
298
|
+
|
299
|
+
it 'deletes all matched values' do
|
300
|
+
list.push('foo')
|
301
|
+
list.push('foo')
|
302
|
+
list.push('bar')
|
303
|
+
list.push('foo')
|
304
|
+
list.delete_all('foo')
|
305
|
+
assert_equal ['bar'], list.to_a
|
306
|
+
end
|
307
|
+
|
308
|
+
it 'returns deleted value' do
|
309
|
+
list.push('foo')
|
310
|
+
assert_equal ['foo'], list.delete_all('foo')
|
311
|
+
end
|
312
|
+
|
313
|
+
it 'decreases length of list' do
|
314
|
+
list.push('foo')
|
315
|
+
list.push('bar')
|
316
|
+
list.push('foo')
|
317
|
+
list.delete_all('foo')
|
318
|
+
assert_equal 1, list.length
|
319
|
+
assert_equal ['bar'], list.to_a
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
137
324
|
describe '#shift' do
|
138
325
|
it 'returns nil if list is empty' do
|
139
326
|
assert_nil list.shift
|
@@ -200,6 +387,21 @@ describe LinkedList::List do
|
|
200
387
|
end
|
201
388
|
end
|
202
389
|
|
390
|
+
describe '#each_node' do
|
391
|
+
it 'returns enumerator if no block given' do
|
392
|
+
assert_instance_of Enumerator, list.each_node
|
393
|
+
end
|
394
|
+
|
395
|
+
it 'pass each node data to the block' do
|
396
|
+
list.push(node_1)
|
397
|
+
list.push(node_2)
|
398
|
+
nodes = []
|
399
|
+
list.each_node { |e| nodes << e }
|
400
|
+
assert_equal %w(foo bar), nodes.map(&:data)
|
401
|
+
assert_equal true, nodes.all? { |n| n.is_a?(LinkedList::Node) }
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
203
405
|
describe '#each' do
|
204
406
|
it 'returns enumerator if no block given' do
|
205
407
|
assert_instance_of Enumerator, list.each
|
metadata
CHANGED
@@ -1,49 +1,63 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: linked-list
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.11
|
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-
|
11
|
+
date: 2018-08-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '1.3'
|
20
|
+
- - "<="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '2.0'
|
20
23
|
type: :development
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
23
26
|
requirements:
|
24
27
|
- - ">="
|
25
28
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
29
|
+
version: '1.3'
|
30
|
+
- - "<="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.0'
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
34
|
+
name: coveralls
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
30
36
|
requirements:
|
31
37
|
- - ">="
|
32
38
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
34
|
-
- - "<="
|
35
|
-
- !ruby/object:Gem::Version
|
36
|
-
version: '2.0'
|
39
|
+
version: '0'
|
37
40
|
type: :development
|
38
41
|
prerelease: false
|
39
42
|
version_requirements: !ruby/object:Gem::Requirement
|
40
43
|
requirements:
|
41
44
|
- - ">="
|
42
45
|
- !ruby/object:Gem::Version
|
43
|
-
version: '
|
44
|
-
|
46
|
+
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: m
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
45
52
|
- !ruby/object:Gem::Version
|
46
|
-
version:
|
53
|
+
version: 1.5.0
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 1.5.0
|
47
61
|
- !ruby/object:Gem::Dependency
|
48
62
|
name: minitest
|
49
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -65,7 +79,7 @@ dependencies:
|
|
65
79
|
- !ruby/object:Gem::Version
|
66
80
|
version: '6.0'
|
67
81
|
- !ruby/object:Gem::Dependency
|
68
|
-
name:
|
82
|
+
name: rake
|
69
83
|
requirement: !ruby/object:Gem::Requirement
|
70
84
|
requirements:
|
71
85
|
- - ">="
|
@@ -89,6 +103,7 @@ extra_rdoc_files: []
|
|
89
103
|
files:
|
90
104
|
- ".gitignore"
|
91
105
|
- ".travis.yml"
|
106
|
+
- CHANGELOG.md
|
92
107
|
- Gemfile
|
93
108
|
- LICENSE.txt
|
94
109
|
- README.md
|