skn_utils 3.3.5 → 3.3.6
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/README.md +37 -5
- data/lib/skn_utils/lists/circular_linked_list.rb +8 -163
- data/lib/skn_utils/lists/doubly_linked_list.rb +18 -180
- data/lib/skn_utils/lists/link_node.rb +37 -1
- data/lib/skn_utils/lists/linked_commons.rb +202 -0
- data/lib/skn_utils/lists/linked_list.rb +19 -183
- data/lib/skn_utils/version.rb +1 -1
- data/lib/skn_utils.rb +1 -0
- data/spec/lib/skn_utils/lists/node_based_linked_list_spec.rb +85 -0
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1fd1ca93fc5fbcbdf6d22f5c45851fcd36e19e88
|
4
|
+
data.tar.gz: 0aeaade9f44e5a69c701946d24542c9c88f2995e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a934d2d35f6680f15b923df769e3da95795d122317fe15bb49b26aa5917b077c7fa81040b02ef637a26d4bef15791cc447538c663c187b83681e5c698dc6627
|
7
|
+
data.tar.gz: a05eae70e269463828a96e6c8e714cd214bacb5bf1256caee2220cdf1c62d634bc58a61e7f42f556e08c2a4254ae27547149186cbf3cd632b85ca871b1c6b1da
|
data/README.md
CHANGED
@@ -17,8 +17,8 @@ Ruby Gem containing a Ruby PORO (Plain Old Ruby Object) that can be instantiated
|
|
17
17
|
|
18
18
|
## New Features
|
19
19
|
08/2017 V3.3.0
|
20
|
-
Added Linked List classes which implement
|
21
|
-
|
20
|
+
Added Linked List classes which implement Single, Double, and Circular linked lists patterns. LinkedLists are implemented
|
21
|
+
with method results returning node values or the nodes themselves.
|
22
22
|
|
23
23
|
07/2017 V3.1.5
|
24
24
|
Added SknSettings class for use as a replacement to the popular, but obsolete, Config.gem
|
@@ -70,9 +70,13 @@ Ruby Gem containing a Ruby PORO (Plain Old Ruby Object) that can be instantiated
|
|
70
70
|
|
71
71
|
|
72
72
|
## Public Methods: SknUtils::Lists::LinkedList, SknUtils::Lists::DoublyLinkedList, and SknUtils::Lists::CircularLinkedList
|
73
|
-
|
74
|
-
|
73
|
+
#### Each concrete Class supports the following methods: Value based interface
|
74
|
+
Value based interface presumes a direct reference to the object is maintained and the following methods will be called on that
|
75
|
+
object instance as needed. Each method will generally return the value contained in the node, Nil, or the int number of nodes
|
76
|
+
remaining.
|
77
|
+
|
75
78
|
Navigation: return related value from relative positon in list, stops on first/last node for Single/Double, wraps for Circular.
|
79
|
+
|
76
80
|
#first -- returns first value in list
|
77
81
|
#next -- returns next value from current position
|
78
82
|
#current -- returns current value
|
@@ -94,6 +98,7 @@ Ruby Gem containing a Ruby PORO (Plain Old Ruby Object) that can be instantiated
|
|
94
98
|
block format is: {|a,b| a >= b }; example: 'll.sort(:default) {|a,b| a <= b}'
|
95
99
|
|
96
100
|
Modification: returns number of elements in the list after the operation
|
101
|
+
|
97
102
|
#insert(value) -- inserts value after node at current positon, or appends
|
98
103
|
#append(value) -- inserts value after node at current positon
|
99
104
|
#prepend(value) -- inserts value before node at current positon
|
@@ -102,9 +107,36 @@ Ruby Gem containing a Ruby PORO (Plain Old Ruby Object) that can be instantiated
|
|
102
107
|
#remove(value) -- finds first node matching value, then destroys it
|
103
108
|
|
104
109
|
Initialization: optional &block to identify data key
|
110
|
+
|
105
111
|
#new(*vargs, &block) -- Instansiates new list and optionally creates nodes from each comma-seperated value;
|
106
112
|
also, assigns &block as default value identifier for find and sort operations
|
107
|
-
|
113
|
+
returns a class instance.
|
114
|
+
compare_key_block example: instance = LinkedList.new({:key=>"Z"},{:key=>"S"},{:key=>"N"}) {|a| a[:key]}
|
115
|
+
|
116
|
+
#### Each concrete Class supports the following methods: Node based interface
|
117
|
+
Node based interface presumes a node is retrieved from the LinkedList, then using that/any available node all other methods
|
118
|
+
may be used. Methods in play will include the LinkedNode (#next, #value, and #prev), along with all public methods from
|
119
|
+
the main class.
|
120
|
+
|
121
|
+
Navigation: return related Node from relative positon in list, stops on first/last node for Single/Double, wraps for Circular.
|
122
|
+
|
123
|
+
#first_node -- returns first node
|
124
|
+
#next_node -- returns next node from current position
|
125
|
+
#current_node -- returns current or last accessed node
|
126
|
+
#prev_node -- returns previous node from current position (*not supported in Single)
|
127
|
+
#last_node -- returns last node in list
|
128
|
+
#node_value -- returns value of the current/receiver node: $ receiver.node_value
|
129
|
+
#node_request(method_sym, *vargs, &block)
|
130
|
+
-- executes any method on the Value based Interface, returning a node
|
131
|
+
#node_value_request(method_sym, *vargs, &block)
|
132
|
+
-- executes any method on the Value based Interface, returning result value
|
133
|
+
|
134
|
+
Initialization: optional &block to identify data key
|
135
|
+
|
136
|
+
#call(*vargs, &block) -- Instansiates new list and optionally creates nodes from each comma-seperated value;
|
137
|
+
also, assigns &block as default value identifier for find and sort operations
|
138
|
+
returns the first node when initialized with vargs -- else class instance
|
139
|
+
compare_key_block example: node = LinkedList.call({:key=>"Z"},{:key=>"S"},{:key=>"N"}) {|a| a[:key]}
|
108
140
|
|
109
141
|
|
110
142
|
## Public Methods: SknSettings ONLY
|
@@ -27,54 +27,24 @@ module SknUtils
|
|
27
27
|
# Circularly Linked List
|
28
28
|
# Forward (#next) and Backwards (#prev) navigation
|
29
29
|
# No Head or Tail
|
30
|
-
class CircularLinkedList
|
31
|
-
attr_accessor :size
|
32
30
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
@match_value = block_given? ? compare_key_proc : lambda {|obj| obj }
|
40
|
-
@sort_ascending = lambda {|a_obj,b_obj| @match_value.call(a_obj) >= @match_value.call(b_obj)}
|
41
|
-
@sort_descending = lambda {|a_obj,b_obj| @match_value.call(a_obj) <= @match_value.call(b_obj)}
|
42
|
-
@sort_condition = @sort_ascending
|
43
|
-
|
44
|
-
vargs.each {|value| insert(value) }
|
45
|
-
first if vargs.size > 1
|
46
|
-
end
|
31
|
+
# LinkedCommons provides;
|
32
|
+
# - #initialize, #first, #next, #current, #last, #at_index,
|
33
|
+
# #insert, #prepend, #append, #empty?, #clear,
|
34
|
+
# #each, #to_a, and #sort!
|
35
|
+
#
|
36
|
+
class CircularLinkedList < LinkedCommons
|
47
37
|
|
48
38
|
#
|
49
39
|
# Navigation
|
50
40
|
#
|
51
41
|
|
52
|
-
# return values and position current to last node accessed
|
53
|
-
# prevent @current from nil assignment
|
54
|
-
def first
|
55
|
-
@current = self.head if self.head
|
56
|
-
@current.value rescue nil
|
57
|
-
end
|
58
|
-
|
59
|
-
def next
|
60
|
-
@current = @current.next if @current and @current.next
|
61
|
-
@current.value rescue nil
|
62
|
-
end
|
63
|
-
|
64
|
-
def current
|
65
|
-
@current.value rescue nil
|
66
|
-
end
|
67
42
|
|
68
43
|
def prev
|
69
44
|
@current = @current.prev if @current and @current.prev
|
70
45
|
@current.value rescue nil
|
71
46
|
end
|
72
47
|
|
73
|
-
def last
|
74
|
-
@current = self.tail if self.tail
|
75
|
-
@current.value rescue nil
|
76
|
-
end
|
77
|
-
|
78
48
|
# -+ int position from current node
|
79
49
|
def nth(index)
|
80
50
|
node = @current
|
@@ -97,41 +67,14 @@ module SknUtils
|
|
97
67
|
current
|
98
68
|
end
|
99
69
|
|
100
|
-
# return node at positive index from head
|
101
|
-
def at_index(index)
|
102
|
-
find_by_index(index)
|
103
|
-
current
|
104
|
-
end
|
105
|
-
|
106
|
-
def empty?
|
107
|
-
self.size == 0
|
108
|
-
end
|
109
|
-
|
110
70
|
#
|
111
71
|
# Modifications
|
112
72
|
#
|
113
73
|
|
114
|
-
# return new size
|
115
|
-
def insert(value)
|
116
|
-
temp = @current.value rescue nil
|
117
|
-
insert_after(temp, value)
|
118
|
-
end
|
119
|
-
|
120
|
-
# return new size
|
121
|
-
def prepend(value)
|
122
|
-
temp = self.head.value rescue nil
|
123
|
-
insert_before(temp, value)
|
124
|
-
end
|
125
|
-
# return new size
|
126
|
-
def append(value)
|
127
|
-
temp = self.tail.value rescue nil
|
128
|
-
insert_after(temp, value)
|
129
|
-
end
|
130
|
-
|
131
74
|
# return new size
|
132
75
|
def insert_before(position_value, value)
|
133
76
|
target = find_by_value(position_value)
|
134
|
-
node = LinkNode.new(value, target, :circle_before, &@match_value)
|
77
|
+
node = LinkNode.new(value, target, :circle_before, self, &@match_value)
|
135
78
|
@current = node
|
136
79
|
if self.size == 0 # only
|
137
80
|
self.head = node
|
@@ -151,7 +94,7 @@ module SknUtils
|
|
151
94
|
# return new size
|
152
95
|
def insert_after(position_value, value)
|
153
96
|
target = find_by_value(position_value)
|
154
|
-
node = LinkNode.new(value, target, :circle_after, &@match_value)
|
97
|
+
node = LinkNode.new(value, target, :circle_after, self, &@match_value)
|
155
98
|
@current = node
|
156
99
|
if self.size == 0 # only
|
157
100
|
self.head = node
|
@@ -197,83 +140,8 @@ module SknUtils
|
|
197
140
|
end
|
198
141
|
|
199
142
|
|
200
|
-
# return number cleared
|
201
|
-
def clear
|
202
|
-
rc = 0
|
203
|
-
node = self.head
|
204
|
-
position = node
|
205
|
-
while node do
|
206
|
-
node = node.remove!
|
207
|
-
rc += 1
|
208
|
-
break if position.equal?(node)
|
209
|
-
end
|
210
|
-
|
211
|
-
@current = nil
|
212
|
-
self.head = nil
|
213
|
-
self.tail = nil
|
214
|
-
self.size = 0
|
215
|
-
rc
|
216
|
-
end
|
217
|
-
|
218
|
-
#
|
219
|
-
# Enumerate
|
220
|
-
#
|
221
|
-
|
222
|
-
# perform each() or return enumerator
|
223
|
-
def each(&block)
|
224
|
-
@current = self.head
|
225
|
-
position = self.head
|
226
|
-
if block_given?
|
227
|
-
while position do
|
228
|
-
block.call( position.value.dup )
|
229
|
-
position = position.next
|
230
|
-
break if position === @current
|
231
|
-
end
|
232
|
-
else
|
233
|
-
Enumerator.new do |yielder|
|
234
|
-
while position do
|
235
|
-
yielder << position.value.dup
|
236
|
-
position = position.next
|
237
|
-
break if position === @current
|
238
|
-
end
|
239
|
-
end
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
# convert self to a value array
|
244
|
-
def to_a
|
245
|
-
@current = self.head
|
246
|
-
position = self.head
|
247
|
-
result = []
|
248
|
-
while position do
|
249
|
-
result << position.value.dup
|
250
|
-
position = position.next
|
251
|
-
break if position.equal?(@current)
|
252
|
-
end
|
253
|
-
result
|
254
|
-
end
|
255
|
-
|
256
|
-
# block format: sort condition : {|a_obj,b_obj| a_obj >= b_obj}
|
257
|
-
def sort!(direction_sym=:default, &compare_sort_proc)
|
258
|
-
@active_sort_condition = block_given? ? compare_sort_proc :
|
259
|
-
case direction_sym
|
260
|
-
when :asc
|
261
|
-
@sort_ascending
|
262
|
-
when :desc
|
263
|
-
@sort_descending
|
264
|
-
else
|
265
|
-
@sort_condition
|
266
|
-
end
|
267
|
-
sorted = merge_sort(self.to_a)
|
268
|
-
clear
|
269
|
-
sorted.each {|item| insert(item) }
|
270
|
-
self.size
|
271
|
-
end
|
272
|
-
|
273
143
|
protected
|
274
144
|
|
275
|
-
attr_accessor :head, :tail
|
276
|
-
|
277
145
|
def find_by_value(value)
|
278
146
|
return nil if value.nil? || self.size == 0
|
279
147
|
stop_node = self.head
|
@@ -295,29 +163,6 @@ module SknUtils
|
|
295
163
|
node
|
296
164
|
end
|
297
165
|
|
298
|
-
# Merged Sort via Ref: http://rubyalgorithms.com/merge_sort.html
|
299
|
-
# arr is Array to be sorted, sort_cond is Proc expecting a/b params returning true/false
|
300
|
-
def merge_sort(arr)
|
301
|
-
return arr if arr.size < 2
|
302
|
-
middle = arr.size / 2
|
303
|
-
left = merge_sort(arr[0...middle])
|
304
|
-
right = merge_sort(arr[middle..arr.size])
|
305
|
-
merge(left, right)
|
306
|
-
end
|
307
|
-
|
308
|
-
def merge(left, right)
|
309
|
-
sorted = []
|
310
|
-
while left.any? && right.any?
|
311
|
-
if @active_sort_condition.call(left.first, right.first)
|
312
|
-
sorted.push right.shift
|
313
|
-
else
|
314
|
-
sorted.push left.shift
|
315
|
-
end
|
316
|
-
end
|
317
|
-
|
318
|
-
sorted + left + right
|
319
|
-
end
|
320
|
-
|
321
166
|
end # end class
|
322
167
|
end # module
|
323
168
|
end # end module
|
@@ -28,54 +28,23 @@ module SknUtils
|
|
28
28
|
# Forward (#next) and Backwards (#prev) navigation
|
29
29
|
# Head when (prev == nil)
|
30
30
|
# Tail when (next == nil)
|
31
|
-
class DoublyLinkedList
|
32
|
-
attr_accessor :size
|
33
31
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
@match_value = block_given? ? compare_key_proc : lambda {|obj| obj }
|
41
|
-
@sort_ascending = lambda {|a_obj,b_obj| @match_value.call(a_obj) >= @match_value.call(b_obj)}
|
42
|
-
@sort_descending = lambda {|a_obj,b_obj| @match_value.call(a_obj) <= @match_value.call(b_obj)}
|
43
|
-
@sort_condition = @sort_ascending
|
44
|
-
|
45
|
-
vargs.each {|value| insert(value) }
|
46
|
-
first if vargs.size > 1
|
47
|
-
end
|
32
|
+
# LinkedCommons provides;
|
33
|
+
# - #initialize, #first, #next, #current, #last, #at_index,
|
34
|
+
# #insert, #prepend, #append, #empty?, #clear,
|
35
|
+
# #each, #to_a, and #sort!
|
36
|
+
#
|
37
|
+
class DoublyLinkedList < LinkedCommons
|
48
38
|
|
49
39
|
#
|
50
40
|
# Navigation
|
51
41
|
#
|
52
42
|
|
53
|
-
# return values and position current to last node accessed
|
54
|
-
# prevent @current from nil assignment
|
55
|
-
def first
|
56
|
-
@current = head if head
|
57
|
-
@current.value rescue nil
|
58
|
-
end
|
59
|
-
|
60
|
-
def next
|
61
|
-
@current = @current.next if @current and @current.next
|
62
|
-
@current.value rescue nil
|
63
|
-
end
|
64
|
-
|
65
|
-
def current
|
66
|
-
@current.value rescue nil
|
67
|
-
end
|
68
|
-
|
69
43
|
def prev
|
70
44
|
@current = @current.prev if @current and @current.prev
|
71
45
|
@current.value rescue nil
|
72
46
|
end
|
73
47
|
|
74
|
-
def last
|
75
|
-
@current = tail if tail
|
76
|
-
@current.value rescue nil
|
77
|
-
end
|
78
|
-
|
79
48
|
# -+ int position from current node
|
80
49
|
def nth(index)
|
81
50
|
node = @current
|
@@ -95,54 +64,27 @@ module SknUtils
|
|
95
64
|
current
|
96
65
|
end
|
97
66
|
|
98
|
-
# return node at positive index from head
|
99
|
-
def at_index(index)
|
100
|
-
find_by_index(index)
|
101
|
-
current
|
102
|
-
end
|
103
|
-
|
104
|
-
def empty?
|
105
|
-
size == 0
|
106
|
-
end
|
107
|
-
|
108
67
|
#
|
109
68
|
# Modifications
|
110
69
|
#
|
111
70
|
|
112
|
-
# return new size
|
113
|
-
def insert(value)
|
114
|
-
temp = @current.value rescue nil
|
115
|
-
insert_after(temp, value)
|
116
|
-
end
|
117
|
-
|
118
|
-
# return new size
|
119
|
-
def prepend(value)
|
120
|
-
temp = head.value rescue nil
|
121
|
-
insert_before(temp, value)
|
122
|
-
end
|
123
|
-
# return new size
|
124
|
-
def append(value)
|
125
|
-
temp = tail.value rescue nil
|
126
|
-
insert_after(temp, value)
|
127
|
-
end
|
128
|
-
|
129
71
|
# return new size
|
130
72
|
def insert_before(position_value, value)
|
131
73
|
target = find_by_value(position_value)
|
132
|
-
node = LinkNode.new(value, target, :before, &@match_value)
|
74
|
+
node = LinkNode.new(value, target, :before, self, &@match_value)
|
133
75
|
@current = node if target
|
134
|
-
self.head = node if head === target
|
135
|
-
self.tail = node if tail.nil?
|
76
|
+
self.head = node if self.head === target
|
77
|
+
self.tail = node if self.tail.nil?
|
136
78
|
self.size += 1
|
137
79
|
end
|
138
80
|
|
139
81
|
# return new size
|
140
82
|
def insert_after(position_value, value)
|
141
83
|
target = find_by_value(position_value)
|
142
|
-
node = LinkNode.new(value, target, :after, &@match_value)
|
84
|
+
node = LinkNode.new(value, target, :after, self, &@match_value)
|
143
85
|
@current = node
|
144
|
-
self.head = node if head.nil?
|
145
|
-
self.tail = node if tail === target
|
86
|
+
self.head = node if self.head.nil?
|
87
|
+
self.tail = node if self.tail === target
|
146
88
|
self.size += 1
|
147
89
|
end
|
148
90
|
|
@@ -150,7 +92,7 @@ module SknUtils
|
|
150
92
|
def remove(value)
|
151
93
|
target_node = find_by_value(value)
|
152
94
|
if target_node
|
153
|
-
if size == 1 # will become zero
|
95
|
+
if self.size == 1 # will become zero
|
154
96
|
@current = nil
|
155
97
|
self.head = nil
|
156
98
|
self.tail = nil
|
@@ -172,86 +114,11 @@ module SknUtils
|
|
172
114
|
end
|
173
115
|
end
|
174
116
|
|
175
|
-
|
176
|
-
def clear
|
177
|
-
rc = 0
|
178
|
-
node = head
|
179
|
-
position = head
|
180
|
-
while node do
|
181
|
-
node = node.remove!
|
182
|
-
rc += 1
|
183
|
-
break if position === node
|
184
|
-
end
|
185
|
-
|
186
|
-
@current = nil
|
187
|
-
self.head = nil
|
188
|
-
self.tail = nil
|
189
|
-
self.size = 0
|
190
|
-
rc
|
191
|
-
end
|
192
|
-
|
193
|
-
#
|
194
|
-
# Enumerate
|
195
|
-
#
|
196
|
-
|
197
|
-
# perform each() or return enumerator
|
198
|
-
def each(&block)
|
199
|
-
@current = head
|
200
|
-
position = head
|
201
|
-
if block_given?
|
202
|
-
while position do
|
203
|
-
block.call( position.value.dup )
|
204
|
-
position = position.next
|
205
|
-
break if position === @current
|
206
|
-
end
|
207
|
-
else
|
208
|
-
Enumerator.new do |yielder|
|
209
|
-
while position do
|
210
|
-
yielder << position.value.dup
|
211
|
-
position = position.next
|
212
|
-
break if position === @current
|
213
|
-
end
|
214
|
-
end
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
# convert self to a value array
|
219
|
-
def to_a
|
220
|
-
@current = head
|
221
|
-
position = head
|
222
|
-
result = []
|
223
|
-
while position do
|
224
|
-
result << position.value.dup
|
225
|
-
position = position.next
|
226
|
-
break if position === @current
|
227
|
-
end
|
228
|
-
result
|
229
|
-
end
|
230
|
-
|
231
|
-
# block format: sort condition : {|a_obj,b_obj| a_obj >= b_obj}
|
232
|
-
def sort!(direction_sym=:default, &compare_sort_proc)
|
233
|
-
@active_sort_condition = block_given? ? compare_sort_proc :
|
234
|
-
case direction_sym
|
235
|
-
when :asc
|
236
|
-
@sort_ascending
|
237
|
-
when :desc
|
238
|
-
@sort_descending
|
239
|
-
else
|
240
|
-
@sort_condition
|
241
|
-
end
|
242
|
-
sorted = merge_sort(to_a)
|
243
|
-
clear
|
244
|
-
sorted.each {|item| insert(item) }
|
245
|
-
size
|
246
|
-
end
|
247
|
-
|
248
|
-
private
|
249
|
-
|
250
|
-
attr_accessor :head, :tail
|
117
|
+
protected
|
251
118
|
|
252
119
|
def find_by_value(value)
|
253
|
-
return nil if head.nil? || value.nil? || size == 0
|
254
|
-
prior = head
|
120
|
+
return nil if self.head.nil? || value.nil? || self.size == 0
|
121
|
+
prior = self.head
|
255
122
|
target = prior
|
256
123
|
while target and not target.match_by_value(value)
|
257
124
|
prior = target
|
@@ -261,42 +128,13 @@ module SknUtils
|
|
261
128
|
end
|
262
129
|
|
263
130
|
def find_by_index(index)
|
264
|
-
return nil if head.nil? or index < 1 or index > size
|
265
|
-
node = head
|
131
|
+
return nil if self.head.nil? or index < 1 or index > self.size
|
132
|
+
node = self.head
|
266
133
|
node = node.next while ((index -= 1) > 0 and node.next)
|
267
134
|
@current = node if node
|
268
135
|
node
|
269
136
|
end
|
270
137
|
|
271
|
-
# Merged Sort via Ref: http://rubyalgorithms.com/merge_sort.html
|
272
|
-
# arr is Array to be sorted, sort_cond is Proc expecting a/b params returning true/false
|
273
|
-
def merge_sort(arr)
|
274
|
-
return arr if arr.size < 2
|
275
|
-
|
276
|
-
middle = arr.size / 2
|
277
|
-
|
278
|
-
left = merge_sort(arr[0...middle])
|
279
|
-
right = merge_sort(arr[middle..arr.size])
|
280
|
-
|
281
|
-
merge(left, right)
|
282
|
-
end
|
283
|
-
|
284
|
-
def merge(left, right)
|
285
|
-
sorted = []
|
286
|
-
|
287
|
-
while left.any? && right.any?
|
288
|
-
|
289
|
-
if @active_sort_condition.call(left.first, right.first)
|
290
|
-
sorted.push right.shift
|
291
|
-
else
|
292
|
-
sorted.push left.shift
|
293
|
-
end
|
294
|
-
|
295
|
-
end
|
296
|
-
|
297
|
-
sorted + left + right
|
298
|
-
end
|
299
|
-
|
300
138
|
end # end class
|
301
139
|
end # module
|
302
140
|
end # end module
|
@@ -8,10 +8,11 @@ module SknUtils
|
|
8
8
|
class LinkNode
|
9
9
|
attr_accessor :prev, :next, :value
|
10
10
|
|
11
|
-
def initialize(val, anchor_node=nil, strategy=:after, &cmp_key)
|
11
|
+
def initialize(val, anchor_node=nil, strategy=:after, mgr=nil, &cmp_key)
|
12
12
|
@value = val
|
13
13
|
@prev = nil
|
14
14
|
@next = nil
|
15
|
+
@provider = mgr
|
15
16
|
@cmp_proc = block_given? ? cmp_key : lambda {|a| a }
|
16
17
|
|
17
18
|
case strategy
|
@@ -55,6 +56,41 @@ module SknUtils
|
|
55
56
|
def to_s
|
56
57
|
"Node with value: #{@value}"
|
57
58
|
end
|
59
|
+
|
60
|
+
# Reverse API to Parent Linked List Class
|
61
|
+
def node_value
|
62
|
+
node_request.value
|
63
|
+
end
|
64
|
+
def first_node
|
65
|
+
node_request(:first)
|
66
|
+
end
|
67
|
+
def next_node
|
68
|
+
node_request(:next)
|
69
|
+
end
|
70
|
+
def current_node
|
71
|
+
node_request(:current)
|
72
|
+
end
|
73
|
+
def prev_node
|
74
|
+
node_request(:prev)
|
75
|
+
end
|
76
|
+
def last_node
|
77
|
+
node_request(:last)
|
78
|
+
end
|
79
|
+
|
80
|
+
protected()
|
81
|
+
|
82
|
+
def respond_to_missing?(method, include_private=false)
|
83
|
+
@provider && @provider.protected_methods(true).include?(method) || super
|
84
|
+
end
|
85
|
+
|
86
|
+
def method_missing(method, *args, &block)
|
87
|
+
if @provider and @provider.protected_methods(true).include?(method)
|
88
|
+
block_given? ? @provider.send(method, *args, block) :
|
89
|
+
(args.size == 0 ? @provider.send(method) : @provider.send(method, *args))
|
90
|
+
else
|
91
|
+
super
|
92
|
+
end
|
93
|
+
end
|
58
94
|
end
|
59
95
|
end # module
|
60
96
|
end
|
@@ -0,0 +1,202 @@
|
|
1
|
+
##
|
2
|
+
# File <SknUtils>/lib/skn_utils/lists/linked_commons.rb
|
3
|
+
#
|
4
|
+
# Common routines for Linked List:
|
5
|
+
# #initialize, #first, #next, #current, #last, #at_index,
|
6
|
+
# #insert, #prepend, #append, #empty?, #clear,
|
7
|
+
# #each, #to_a, and #sort!
|
8
|
+
##
|
9
|
+
|
10
|
+
module SknUtils
|
11
|
+
module Lists
|
12
|
+
|
13
|
+
class LinkedCommons
|
14
|
+
attr_accessor :size
|
15
|
+
|
16
|
+
# Initialize and return first node if nodes are available
|
17
|
+
def self.call(*vargs, &compare_key_proc)
|
18
|
+
target = self.new(*vargs, &compare_key_proc)
|
19
|
+
return target.instance_variable_get(:@current) if vargs.size > 1
|
20
|
+
target
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(*vargs, &compare_key_proc)
|
24
|
+
@current = nil
|
25
|
+
@head = nil
|
26
|
+
@tail = nil
|
27
|
+
@size = 0
|
28
|
+
|
29
|
+
@match_value = block_given? ? compare_key_proc : lambda {|obj| obj }
|
30
|
+
@sort_ascending = lambda {|a_obj,b_obj| @match_value.call(a_obj) >= @match_value.call(b_obj)}
|
31
|
+
@sort_descending = lambda {|a_obj,b_obj| @match_value.call(a_obj) <= @match_value.call(b_obj)}
|
32
|
+
@sort_condition = @sort_ascending
|
33
|
+
|
34
|
+
vargs.each {|value| insert(value) }
|
35
|
+
first if vargs.size > 1
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
# return values and position current to last node accessed
|
40
|
+
# prevent @current from nil assignment
|
41
|
+
def first
|
42
|
+
@current = self.head if self.head
|
43
|
+
@current.value rescue nil
|
44
|
+
end
|
45
|
+
|
46
|
+
def next
|
47
|
+
@current = @current.next if @current and @current.next
|
48
|
+
@current.value rescue nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def current
|
52
|
+
@current.value rescue nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def last
|
56
|
+
@current = self.tail if self.tail
|
57
|
+
@current.value rescue nil
|
58
|
+
end
|
59
|
+
|
60
|
+
# return node at positive index from head
|
61
|
+
def at_index(index)
|
62
|
+
find_by_index(index)
|
63
|
+
current
|
64
|
+
end
|
65
|
+
|
66
|
+
def empty?
|
67
|
+
self.size == 0
|
68
|
+
end
|
69
|
+
|
70
|
+
# return number cleared
|
71
|
+
def clear
|
72
|
+
rc = 0
|
73
|
+
node = self.head
|
74
|
+
position = node
|
75
|
+
while node do
|
76
|
+
node = node.remove!
|
77
|
+
rc += 1
|
78
|
+
break if position.equal?(node)
|
79
|
+
end
|
80
|
+
|
81
|
+
@current = nil
|
82
|
+
self.head = nil
|
83
|
+
self.tail = nil
|
84
|
+
self.size = 0
|
85
|
+
rc
|
86
|
+
end
|
87
|
+
|
88
|
+
# return new size
|
89
|
+
def insert(value)
|
90
|
+
temp = @current.value rescue nil
|
91
|
+
insert_after(temp, value)
|
92
|
+
end
|
93
|
+
|
94
|
+
# return new size
|
95
|
+
def prepend(value)
|
96
|
+
temp = self.head.value rescue nil
|
97
|
+
insert_before(temp, value)
|
98
|
+
end
|
99
|
+
# return new size
|
100
|
+
def append(value)
|
101
|
+
temp = self.tail.value rescue nil
|
102
|
+
insert_after(temp, value)
|
103
|
+
end
|
104
|
+
|
105
|
+
#
|
106
|
+
# Enumerate
|
107
|
+
#
|
108
|
+
|
109
|
+
# perform each() or return enumerator
|
110
|
+
def each(&block)
|
111
|
+
@current = self.head
|
112
|
+
position = self.head
|
113
|
+
if block_given?
|
114
|
+
while position do
|
115
|
+
block.call( position.value.dup )
|
116
|
+
position = position.next
|
117
|
+
break if position === @current
|
118
|
+
end
|
119
|
+
else
|
120
|
+
Enumerator.new do |yielder|
|
121
|
+
while position do
|
122
|
+
yielder << position.value.dup
|
123
|
+
position = position.next
|
124
|
+
break if position === @current
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# convert self to a value array
|
131
|
+
def to_a
|
132
|
+
@current = self.head
|
133
|
+
position = self.head
|
134
|
+
result = []
|
135
|
+
while position do
|
136
|
+
result << position.value.dup
|
137
|
+
position = position.next
|
138
|
+
break if position.equal?(@current)
|
139
|
+
end
|
140
|
+
result
|
141
|
+
end
|
142
|
+
|
143
|
+
# block format: sort condition : {|a_obj,b_obj| a_obj >= b_obj}
|
144
|
+
def sort!(direction_sym=:default, &compare_sort_proc)
|
145
|
+
@active_sort_condition = block_given? ? compare_sort_proc :
|
146
|
+
case direction_sym
|
147
|
+
when :asc
|
148
|
+
@sort_ascending
|
149
|
+
when :desc
|
150
|
+
@sort_descending
|
151
|
+
else
|
152
|
+
@sort_condition
|
153
|
+
end
|
154
|
+
sorted = merge_sort(self.to_a)
|
155
|
+
clear
|
156
|
+
sorted.each {|item| insert(item) }
|
157
|
+
self.size
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
protected
|
162
|
+
|
163
|
+
attr_accessor :head, :tail
|
164
|
+
|
165
|
+
# Merged Sort via Ref: http://rubyalgorithms.com/merge_sort.html
|
166
|
+
# arr is Array to be sorted, sort_cond is Proc expecting a/b params returning true/false
|
167
|
+
def merge_sort(arr)
|
168
|
+
return arr if arr.size < 2
|
169
|
+
middle = arr.size / 2
|
170
|
+
left = merge_sort(arr[0...middle])
|
171
|
+
right = merge_sort(arr[middle..arr.size])
|
172
|
+
merge(left, right)
|
173
|
+
end
|
174
|
+
|
175
|
+
def merge(left, right)
|
176
|
+
sorted = []
|
177
|
+
while left.any? && right.any?
|
178
|
+
if @active_sort_condition.call(left.first, right.first)
|
179
|
+
sorted.push right.shift
|
180
|
+
else
|
181
|
+
sorted.push left.shift
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
sorted + left + right
|
186
|
+
end
|
187
|
+
|
188
|
+
# Retrieves requested node, not value
|
189
|
+
def node_request(method_sym=:current, *vargs, &block)
|
190
|
+
position_value = block_given? ? send(method_sym, *vargs, block) :
|
191
|
+
(vargs.size == 0 ? send(method_sym) : send(method_sym, *vargs))
|
192
|
+
@current
|
193
|
+
end
|
194
|
+
# Retrieves requested value, not node
|
195
|
+
def node_value_request(method_sym=:current, *vargs, &block)
|
196
|
+
position_value = block_given? ? send(method_sym, *vargs, block) :
|
197
|
+
(vargs.size == 0 ? send(method_sym) : send(method_sym, *vargs))
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
end # module
|
202
|
+
end
|
@@ -28,51 +28,18 @@ module SknUtils
|
|
28
28
|
# Forward or #next navigation only
|
29
29
|
# Head is absolute via #first
|
30
30
|
# Tail when (next == nil)
|
31
|
-
class LinkedList
|
32
|
-
attr_accessor :size
|
33
31
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
@tail = nil
|
41
|
-
@size = 0
|
42
|
-
|
43
|
-
@match_value = block_given? ? compare_key_proc : lambda {|obj| obj }
|
44
|
-
@sort_ascending = lambda {|a_obj,b_obj| @match_value.call(a_obj) >= @match_value.call(b_obj)}
|
45
|
-
@sort_descending = lambda {|a_obj,b_obj| @match_value.call(a_obj) <= @match_value.call(b_obj)}
|
46
|
-
@sort_condition = @sort_ascending
|
47
|
-
|
48
|
-
vargs.each {|value| insert(value) }
|
49
|
-
first if vargs.size > 1
|
50
|
-
end
|
32
|
+
# LinkedCommons provides;
|
33
|
+
# - #initialize, #first, #next, #current, #last, #at_index,
|
34
|
+
# #insert, #prepend, #append, #empty?, #clear,
|
35
|
+
# #each, #to_a, and #sort!
|
36
|
+
#
|
37
|
+
class LinkedList < LinkedCommons
|
51
38
|
|
52
39
|
#
|
53
40
|
# Navigation
|
54
41
|
#
|
55
42
|
|
56
|
-
# return values and position current to last node accessed
|
57
|
-
def first
|
58
|
-
@current = head if head
|
59
|
-
@current.value rescue nil
|
60
|
-
end
|
61
|
-
|
62
|
-
def next
|
63
|
-
@current = @current.next if @current and @current.next
|
64
|
-
@current.value rescue nil
|
65
|
-
end
|
66
|
-
|
67
|
-
def current
|
68
|
-
@current.value rescue nil
|
69
|
-
end
|
70
|
-
|
71
|
-
def last
|
72
|
-
@current = tail if tail
|
73
|
-
@current.value rescue nil
|
74
|
-
end
|
75
|
-
|
76
43
|
# +int position from current node
|
77
44
|
def nth(index)
|
78
45
|
node = @current
|
@@ -85,45 +52,17 @@ module SknUtils
|
|
85
52
|
current
|
86
53
|
end
|
87
54
|
|
88
|
-
# return node at positive index from head
|
89
|
-
def at_index(index)
|
90
|
-
find_by_index(index)
|
91
|
-
current
|
92
|
-
end
|
93
|
-
|
94
|
-
def empty?
|
95
|
-
size == 0
|
96
|
-
end
|
97
|
-
|
98
55
|
#
|
99
56
|
# Modifications
|
100
57
|
#
|
101
58
|
|
102
|
-
# return new size
|
103
|
-
def insert(value)
|
104
|
-
temp = @current.value rescue nil
|
105
|
-
insert_after(temp, value)
|
106
|
-
end
|
107
|
-
|
108
|
-
# return new size
|
109
|
-
def prepend(value)
|
110
|
-
temp = head.value rescue nil
|
111
|
-
insert_before(temp, value)
|
112
|
-
end
|
113
|
-
|
114
|
-
# return new size
|
115
|
-
def append(value)
|
116
|
-
temp = tail.value rescue nil
|
117
|
-
insert_after(temp, value)
|
118
|
-
end
|
119
|
-
|
120
59
|
# return new size
|
121
60
|
def insert_before(position_value, value)
|
122
61
|
prior, target = find_by_value(position_value)
|
123
|
-
node = LinkNode.new(value, prior, :single, &@match_value)
|
62
|
+
node = LinkNode.new(value, prior, :single, self, &@match_value)
|
124
63
|
node.next = target if target
|
125
|
-
self.head = node if head === target
|
126
|
-
self.tail = node if tail.nil?
|
64
|
+
self.head = node if self.head === target
|
65
|
+
self.tail = node if self.tail.nil?
|
127
66
|
@current = node
|
128
67
|
self.size += 1
|
129
68
|
end
|
@@ -131,9 +70,9 @@ module SknUtils
|
|
131
70
|
# return new size
|
132
71
|
def insert_after(position_value, value)
|
133
72
|
prior, target = find_by_value(position_value)
|
134
|
-
node = LinkNode.new(value, target, :single, &@match_value)
|
135
|
-
self.head = node if head.nil?
|
136
|
-
self.tail = node if tail === target
|
73
|
+
node = LinkNode.new(value, target, :single, self, &@match_value)
|
74
|
+
self.head = node if self.head.nil?
|
75
|
+
self.tail = node if self.tail === target
|
137
76
|
@current = node
|
138
77
|
self.size += 1
|
139
78
|
end
|
@@ -143,90 +82,16 @@ module SknUtils
|
|
143
82
|
prior, target_node = find_by_value(value)
|
144
83
|
@current = prior.nil? ? target_node.next : prior
|
145
84
|
@current.next = target_node.remove! if @current && target_node
|
146
|
-
self.tail = @current.next if @current && tail === target_node
|
147
|
-
self.head = @current.next if @current && head === target_node
|
85
|
+
self.tail = @current.next if @current && self.tail === target_node
|
86
|
+
self.head = @current.next if @current && self.head === target_node
|
148
87
|
self.size -= 1
|
149
88
|
end
|
150
89
|
|
151
|
-
|
152
|
-
def clear
|
153
|
-
rc = 0
|
154
|
-
node = head
|
155
|
-
position = head
|
156
|
-
while node do
|
157
|
-
node = node.remove!
|
158
|
-
rc += 1
|
159
|
-
break if position === node
|
160
|
-
end
|
161
|
-
|
162
|
-
@current = nil
|
163
|
-
self.head = nil
|
164
|
-
self.tail = nil
|
165
|
-
self.size = 0
|
166
|
-
rc
|
167
|
-
end
|
168
|
-
|
169
|
-
#
|
170
|
-
# Enumerate
|
171
|
-
#
|
172
|
-
|
173
|
-
# perform each() or return enumerator
|
174
|
-
def each(&block)
|
175
|
-
@current = head
|
176
|
-
position = head
|
177
|
-
if block_given?
|
178
|
-
while position do
|
179
|
-
block.call(position.value.dup )
|
180
|
-
position = position.next
|
181
|
-
end
|
182
|
-
else
|
183
|
-
Enumerator.new do |yielder|
|
184
|
-
while position do
|
185
|
-
yielder << position.value.dup
|
186
|
-
position = position.next
|
187
|
-
end
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
# convert self to a value array
|
193
|
-
def to_a
|
194
|
-
@current = head
|
195
|
-
position = head
|
196
|
-
result = []
|
197
|
-
while position do
|
198
|
-
result << position.value.dup
|
199
|
-
position = position.next
|
200
|
-
break if position === @current
|
201
|
-
end
|
202
|
-
result
|
203
|
-
end
|
204
|
-
|
205
|
-
# block format: sort condition : {|a_obj,b_obj| a_obj >= b_obj}
|
206
|
-
def sort!(direction_sym=:default, &compare_sort_proc)
|
207
|
-
@active_sort_condition = block_given? ? compare_sort_proc :
|
208
|
-
case direction_sym
|
209
|
-
when :asc
|
210
|
-
@sort_ascending
|
211
|
-
when :desc
|
212
|
-
@sort_descending
|
213
|
-
else
|
214
|
-
@sort_condition
|
215
|
-
end
|
216
|
-
|
217
|
-
sorted = merge_sort(to_a)
|
218
|
-
clear
|
219
|
-
sorted.each {|item| insert(item) }
|
220
|
-
size
|
221
|
-
end
|
222
|
-
|
223
|
-
private
|
224
|
-
|
225
|
-
attr_accessor :head, :tail
|
90
|
+
protected
|
226
91
|
|
227
92
|
def find_by_value(value)
|
228
|
-
return [@current, nil] if head.nil? || value.nil?
|
229
|
-
prior = head
|
93
|
+
return [@current, nil] if self.head.nil? || value.nil?
|
94
|
+
prior = self.head
|
230
95
|
target = prior
|
231
96
|
while target and not target.match_by_value(value)
|
232
97
|
prior = target
|
@@ -237,42 +102,13 @@ module SknUtils
|
|
237
102
|
end
|
238
103
|
|
239
104
|
def find_by_index(index)
|
240
|
-
return nil if head.nil? || index < 1 || index > size
|
241
|
-
node = head
|
105
|
+
return nil if self.head.nil? || index < 1 || index > self.size
|
106
|
+
node = self.head
|
242
107
|
node = node.next while ((index -= 1) > 0 and node.next)
|
243
108
|
@current = node if node
|
244
109
|
node
|
245
110
|
end
|
246
111
|
|
247
|
-
# Merged Sort via Ref: http://rubyalgorithms.com/merge_sort.html
|
248
|
-
# arr is Array to be sorted, sort_cond is Proc expecting a/b params returning true/false
|
249
|
-
def merge_sort(arr)
|
250
|
-
return arr if arr.size < 2
|
251
|
-
|
252
|
-
middle = arr.size / 2
|
253
|
-
|
254
|
-
left = merge_sort(arr[0...middle])
|
255
|
-
right = merge_sort(arr[middle..arr.size])
|
256
|
-
|
257
|
-
merge(left, right)
|
258
|
-
end
|
259
|
-
|
260
|
-
def merge(left, right)
|
261
|
-
sorted = []
|
262
|
-
|
263
|
-
while left.any? && right.any?
|
264
|
-
|
265
|
-
if @active_sort_condition.call(left.first, right.first)
|
266
|
-
sorted.push right.shift
|
267
|
-
else
|
268
|
-
sorted.push left.shift
|
269
|
-
end
|
270
|
-
|
271
|
-
end
|
272
|
-
|
273
|
-
sorted + left + right
|
274
|
-
end
|
275
|
-
|
276
112
|
end # end class
|
277
113
|
end # end module
|
278
114
|
end # end module
|
data/lib/skn_utils/version.rb
CHANGED
data/lib/skn_utils.rb
CHANGED
@@ -5,6 +5,7 @@ require 'skn_utils/page_controls'
|
|
5
5
|
require 'skn_utils/null_object'
|
6
6
|
require 'skn_utils/notifier_base'
|
7
7
|
require 'skn_utils/skn_configuration'
|
8
|
+
require 'skn_utils/lists/linked_commons'
|
8
9
|
require 'skn_utils/lists/link_node'
|
9
10
|
require 'skn_utils/lists/linked_list'
|
10
11
|
require 'skn_utils/lists/doubly_linked_list'
|
@@ -0,0 +1,85 @@
|
|
1
|
+
##
|
2
|
+
# spec/lib/skn_utils/node_based_linked_list_spec.rb
|
3
|
+
#
|
4
|
+
|
5
|
+
RSpec.describe SknUtils::Lists::DoublyLinkedList, "DoublyLinkedList using node interface " do
|
6
|
+
|
7
|
+
context "Node Interface Edge Cases " do
|
8
|
+
let(:node) { described_class.call(10,20, 30, 40, 50, 60, 70, 80, 90, 100) {|a| a} }
|
9
|
+
|
10
|
+
context "Node Retrieval " do
|
11
|
+
|
12
|
+
it "#node_request(:first) returns a LinkedNode object." do
|
13
|
+
expect(node.send(:node_request,:first)).to be_a SknUtils::Lists::LinkNode
|
14
|
+
end
|
15
|
+
it "#first_node returns a LinkedNode object." do
|
16
|
+
expect(node.first_node).to be_a SknUtils::Lists::LinkNode
|
17
|
+
end
|
18
|
+
it "#next_node returns a LinkedNode object." do
|
19
|
+
expect(node.next_node).to be_a SknUtils::Lists::LinkNode
|
20
|
+
end
|
21
|
+
it "#current_node returns a LinkedNode object." do
|
22
|
+
expect(node.current_node).to be_a SknUtils::Lists::LinkNode
|
23
|
+
end
|
24
|
+
it "#prev_node returns a LinkedNode object." do
|
25
|
+
expect(node.prev_node).to be_a SknUtils::Lists::LinkNode
|
26
|
+
end
|
27
|
+
it "#last_node returns a LinkedNode object." do
|
28
|
+
expect(node.last_node).to be_a SknUtils::Lists::LinkNode
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "Node Values " do
|
33
|
+
|
34
|
+
it "#methods with params are supported through #{}node_request() interface. " do
|
35
|
+
expect(node.first_node.node_value_request(:at_index, 5)).to eq(50)
|
36
|
+
end
|
37
|
+
it "First node has the expected value. " do
|
38
|
+
expect(node.first_node.value).to eq(10)
|
39
|
+
end
|
40
|
+
it "Next node has the expected value. " do
|
41
|
+
expect(node.next_node.value).to eq(20)
|
42
|
+
end
|
43
|
+
it "Current node has the expected value. " do
|
44
|
+
3.times { node.next_node }
|
45
|
+
expect(node.current_node.value).to eq(40)
|
46
|
+
end
|
47
|
+
it "Last node has the expected value. " do
|
48
|
+
expect(node.last_node.value).to eq(100)
|
49
|
+
end
|
50
|
+
it "#node_value collected match #to_a output. " do
|
51
|
+
nav_ary = []
|
52
|
+
node.node_value_request(:size).times do
|
53
|
+
nav_ary << node.node_value
|
54
|
+
node.next_node
|
55
|
+
end
|
56
|
+
|
57
|
+
expect(nav_ary).to eq(node.node_value_request(:to_a))
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "Node Navigation " do
|
62
|
+
|
63
|
+
it "Can navigate to each mode in list, forward. " do
|
64
|
+
node.node_value_request(:size).times do
|
65
|
+
expect(node.next_node).to be_a SknUtils::Lists::LinkNode
|
66
|
+
end
|
67
|
+
end
|
68
|
+
it "Can navigate to each mode in list, backward. " do
|
69
|
+
node.last_node.node_value_request(:size).times do
|
70
|
+
expect(node.prev_node).to be_a SknUtils::Lists::LinkNode
|
71
|
+
end
|
72
|
+
end
|
73
|
+
it "Values collected match #to_a output. " do
|
74
|
+
nav_ary = []
|
75
|
+
node.node_value_request(:size).times do
|
76
|
+
nav_ary << node.node_value
|
77
|
+
node.next_node
|
78
|
+
end
|
79
|
+
|
80
|
+
expect(node.node_value_request(:to_a)).to eq(nav_ary)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: skn_utils
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.3.
|
4
|
+
version: 3.3.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Scott Jr
|
@@ -140,6 +140,7 @@ files:
|
|
140
140
|
- lib/skn_utils/lists/circular_linked_list.rb
|
141
141
|
- lib/skn_utils/lists/doubly_linked_list.rb
|
142
142
|
- lib/skn_utils/lists/link_node.rb
|
143
|
+
- lib/skn_utils/lists/linked_commons.rb
|
143
144
|
- lib/skn_utils/lists/linked_list.rb
|
144
145
|
- lib/skn_utils/nested_result.rb
|
145
146
|
- lib/skn_utils/notifier_base.rb
|
@@ -159,6 +160,7 @@ files:
|
|
159
160
|
- spec/lib/skn_utils/lists/Circular_linked_list_spec.rb
|
160
161
|
- spec/lib/skn_utils/lists/doubly_linked_list_spec.rb
|
161
162
|
- spec/lib/skn_utils/lists/linked_list_spec.rb
|
163
|
+
- spec/lib/skn_utils/lists/node_based_linked_list_spec.rb
|
162
164
|
- spec/lib/skn_utils/nested_result_spec.rb
|
163
165
|
- spec/lib/skn_utils/notifier_base_spec.rb
|
164
166
|
- spec/lib/skn_utils/null_object_spec.rb
|
@@ -204,6 +206,7 @@ test_files:
|
|
204
206
|
- spec/lib/skn_utils/lists/Circular_linked_list_spec.rb
|
205
207
|
- spec/lib/skn_utils/lists/doubly_linked_list_spec.rb
|
206
208
|
- spec/lib/skn_utils/lists/linked_list_spec.rb
|
209
|
+
- spec/lib/skn_utils/lists/node_based_linked_list_spec.rb
|
207
210
|
- spec/lib/skn_utils/nested_result_spec.rb
|
208
211
|
- spec/lib/skn_utils/notifier_base_spec.rb
|
209
212
|
- spec/lib/skn_utils/null_object_spec.rb
|