doubly_linked_list 0.0.5 → 0.0.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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0872378b46d546aec11ec96d3675082b099fe887
|
4
|
+
data.tar.gz: 0922c01e2fd25b855c904824152d7cf99b9f5bca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 018b32fc622f2ed204602a51a90cc9a94360f6357efe20dd89e0756f127570264ad1ff2ad62cf410d92b3e952a38ee54c822c0055b27e65a6397ec4b32e44a2a
|
7
|
+
data.tar.gz: 98fbb16c4415b0dbed687b3e9e1076fa6289d7237c2b036c8ec6d6c7ddf0f7fbd76b537e7b7b9c833bc176d5eb6e555909e413aa4b102c5c151cca8eb62f3302
|
data/doubly_linked_list.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = 'doubly_linked_list'
|
7
|
-
spec.version = '0.0.
|
7
|
+
spec.version = '0.0.6'
|
8
8
|
spec.authors = ["E. Lynette Rayle"]
|
9
9
|
spec.email = ["elr37@cornell.edu"]
|
10
10
|
spec.platform = Gem::Platform::RUBY
|
data/lib/doubly_linked_list.rb
CHANGED
@@ -19,15 +19,64 @@ class DoublyLinkedList
|
|
19
19
|
attr_accessor :list_info
|
20
20
|
# attr_writer :node_update_callback # TODO Add callback to update node info
|
21
21
|
|
22
|
+
@clear_first = nil # ( list_info ) returns nothing
|
23
|
+
@clear_last = nil # ( list_info ) returns nothing
|
24
|
+
@update_first = nil # ( list_info, list ) returns nothing
|
25
|
+
@update_last = nil # ( list_info, list ) returns nothing
|
26
|
+
|
27
|
+
@clear_next = nil # ( list, item_idx ) returns nothing
|
28
|
+
@clear_prev = nil # ( list, item_idx ) returns nothing
|
29
|
+
@update_next = nil # ( list, item_idx ) returns nothing
|
30
|
+
@update_prev = nil # ( list, item_idx ) returns nothing
|
31
|
+
|
32
|
+
@find_first = nil # ( list_info, list ) returns instance of item in list
|
33
|
+
@find_last = nil # ( list_info, list ) returns instance of item in list
|
34
|
+
@find_next = nil # ( list, current_item ) returns instance of item in list
|
35
|
+
@find_prev = nil # ( list, current_item ) returns instance of item in list
|
36
|
+
|
22
37
|
def initialize(*args)
|
23
38
|
@list = []
|
24
|
-
@list = args[0][:items] if ! args.empty? && args[0].is_a?(Hash) && args[0].key?(:items)
|
25
|
-
raise ArgumentError, "items list must be an Array" unless @list.kind_of?(Array)
|
26
39
|
@list_info = nil
|
27
|
-
|
40
|
+
|
41
|
+
if !args.empty? && args[0].is_a?(Hash)
|
42
|
+
@list = args[0][:items] if args[0].key?(:items)
|
43
|
+
@list_info = args[0][:list_info] if args[0].key?(:list_info)
|
44
|
+
|
45
|
+
# set callbacks
|
46
|
+
@clear_first = args[0][:clear_first_callback] if args[0].key?(:clear_first_callback)
|
47
|
+
@clear_last = args[0][:clear_last_callback] if args[0].key?(:clear_last_callback)
|
48
|
+
@update_first = args[0][:update_first_callback] if args[0].key?(:update_first_callback)
|
49
|
+
@update_last = args[0][:update_last_callback] if args[0].key?(:update_last_callback)
|
50
|
+
|
51
|
+
@clear_next = args[0][:clear_next_callback] if args[0].key?(:clear_next_callback)
|
52
|
+
@clear_prev = args[0][:clear_prev_callback] if args[0].key?(:clear_prev_callback)
|
53
|
+
@update_next = args[0][:update_next_callback] if args[0].key?(:update_next_callback)
|
54
|
+
@update_prev = args[0][:update_prev_callback] if args[0].key?(:update_prev_callback)
|
55
|
+
|
56
|
+
@find_first = args[0][:find_first_callback] if args[0].key?(:find_first_callback)
|
57
|
+
@find_last = args[0][:find_last_callback] if args[0].key?(:find_last_callback)
|
58
|
+
@find_next = args[0][:find_next_callback] if args[0].key?(:find_next_callback)
|
59
|
+
@find_prev = args[0][:find_prev_callback] if args[0].key?(:find_prev_callback)
|
60
|
+
|
61
|
+
unless @list.empty?
|
62
|
+
@list = organize_list
|
63
|
+
update_first_in_listinfo
|
64
|
+
update_last_in_listinfo
|
65
|
+
end
|
66
|
+
end
|
67
|
+
raise ArgumentError, "items list must be an Array" unless @list.kind_of?(Array)
|
28
68
|
self
|
29
69
|
end
|
30
70
|
|
71
|
+
##
|
72
|
+
# Get the number of items in the list.
|
73
|
+
#
|
74
|
+
# @return the number of items
|
75
|
+
def size
|
76
|
+
@list.size
|
77
|
+
end
|
78
|
+
alias_method :count, :size
|
79
|
+
|
31
80
|
##
|
32
81
|
# Get the first element of the list.
|
33
82
|
#
|
@@ -53,7 +102,17 @@ class DoublyLinkedList
|
|
53
102
|
#
|
54
103
|
# @return position where added
|
55
104
|
def add_last(data)
|
105
|
+
raise ArgumentError 'data must have non-nil value' unless data
|
56
106
|
@list << data
|
107
|
+
if @list.size > 1
|
108
|
+
update_next_in_listitem(tail-1)
|
109
|
+
update_prev_in_listitem(tail)
|
110
|
+
else
|
111
|
+
clear_prev_in_listitem(tail)
|
112
|
+
update_first_in_listinfo
|
113
|
+
end
|
114
|
+
clear_next_in_listitem(tail)
|
115
|
+
update_last_in_listinfo
|
57
116
|
@list.size
|
58
117
|
end
|
59
118
|
alias_method :<<, :add_last
|
@@ -65,7 +124,17 @@ class DoublyLinkedList
|
|
65
124
|
#
|
66
125
|
# @return position where added
|
67
126
|
def add_first(data)
|
127
|
+
raise ArgumentError 'data must have non-nil value' unless data
|
68
128
|
@list.insert(0,data)
|
129
|
+
if @list.size > 1
|
130
|
+
update_prev_in_listitem(head+1)
|
131
|
+
update_next_in_listitem(head)
|
132
|
+
else
|
133
|
+
clear_next_in_listitem(head)
|
134
|
+
update_last_in_listinfo
|
135
|
+
end
|
136
|
+
clear_prev_in_listitem(head)
|
137
|
+
update_first_in_listinfo
|
69
138
|
@list.size
|
70
139
|
end
|
71
140
|
|
@@ -75,7 +144,15 @@ class DoublyLinkedList
|
|
75
144
|
# @return data stored in the removed node
|
76
145
|
def remove_last
|
77
146
|
return nil if @list.empty?
|
78
|
-
@list.delete_at(tail)
|
147
|
+
item = @list.delete_at(tail)
|
148
|
+
if @list.size > 0
|
149
|
+
clear_next_in_listitem(tail)
|
150
|
+
update_last_in_listinfo
|
151
|
+
else
|
152
|
+
clear_first_in_listinfo
|
153
|
+
clear_last_in_listinfo
|
154
|
+
end
|
155
|
+
item
|
79
156
|
end
|
80
157
|
|
81
158
|
##
|
@@ -84,7 +161,15 @@ class DoublyLinkedList
|
|
84
161
|
# @return data stored in the removed node
|
85
162
|
def remove_first
|
86
163
|
return nil if @list.empty?
|
87
|
-
@list.delete_at(head)
|
164
|
+
item = @list.delete_at(head)
|
165
|
+
if @list.size > 0
|
166
|
+
clear_prev_in_listitem(head)
|
167
|
+
update_first_in_listinfo
|
168
|
+
else
|
169
|
+
clear_first_in_listinfo
|
170
|
+
clear_last_in_listinfo
|
171
|
+
end
|
172
|
+
item
|
88
173
|
end
|
89
174
|
|
90
175
|
# Returns list array without list info.
|
@@ -111,11 +196,84 @@ class DoublyLinkedList
|
|
111
196
|
|
112
197
|
private
|
113
198
|
|
199
|
+
# head returns the first index into the array list. See first method to get the first item in the list.
|
114
200
|
def head
|
115
201
|
@list && @list.size > 0 ? 0 : nil
|
116
202
|
end
|
117
203
|
|
204
|
+
# tail returns the last index into the array list. See last method to get the last item in the list.
|
118
205
|
def tail
|
119
206
|
@list && @list.size > 0 ? @list.size-1 : nil
|
120
207
|
end
|
208
|
+
|
209
|
+
def valid_list?
|
210
|
+
@list && !@list.empty?
|
211
|
+
end
|
212
|
+
|
213
|
+
def item_idx_in_range(item_idx)
|
214
|
+
item_idx >= head && item_idx <= tail
|
215
|
+
end
|
216
|
+
|
217
|
+
def clear_first_in_listinfo
|
218
|
+
@clear_first.call(@list_info,@list) if @clear_first && @list_info
|
219
|
+
end
|
220
|
+
|
221
|
+
def update_first_in_listinfo
|
222
|
+
@update_first.call(@list_info,@list) if @update_first && @list_info && valid_list?
|
223
|
+
end
|
224
|
+
|
225
|
+
def clear_last_in_listinfo
|
226
|
+
@clear_last.call(@list_info,@list) if @clear_last && @list_info
|
227
|
+
end
|
228
|
+
|
229
|
+
def update_last_in_listinfo
|
230
|
+
@update_last.call(@list_info,@list) if @update_last && @list_info && valid_list?
|
231
|
+
end
|
232
|
+
|
233
|
+
def clear_next_in_listitem(item_idx)
|
234
|
+
@clear_next.call(@list,item_idx) if @clear_next && valid_list? && item_idx_in_range(item_idx)
|
235
|
+
end
|
236
|
+
|
237
|
+
def update_next_in_listitem(item_idx)
|
238
|
+
@update_next.call(@list,item_idx) if @update_next && valid_list? && item_idx_in_range(item_idx)
|
239
|
+
end
|
240
|
+
|
241
|
+
def clear_prev_in_listitem(item_idx)
|
242
|
+
@clear_prev.call(@list,item_idx) if @clear_prev && valid_list? && item_idx_in_range(item_idx)
|
243
|
+
end
|
244
|
+
|
245
|
+
def update_prev_in_listitem(item_idx)
|
246
|
+
@update_prev.call(@list,item_idx) if @update_prev && valid_list? && item_idx_in_range(item_idx)
|
247
|
+
end
|
248
|
+
|
249
|
+
def find_first_in_listinfo
|
250
|
+
@find_first.call(@list_info,@list) if @find_first && (@list_info || valid_list?)
|
251
|
+
end
|
252
|
+
|
253
|
+
def find_last_in_listinfo
|
254
|
+
@find_last.call(@list_info,@list) if @find_last && (@list_info || valid_list?)
|
255
|
+
end
|
256
|
+
|
257
|
+
def find_next_listitem(current_item)
|
258
|
+
@find_next.call(@list,current_item) if @find_next && valid_list? && current_item
|
259
|
+
end
|
260
|
+
|
261
|
+
def find_prev_listitem(current_item)
|
262
|
+
@find_prev.call(@list,current_item) if @find_prev && valid_list? && current_item
|
263
|
+
end
|
264
|
+
|
265
|
+
def organize_list
|
266
|
+
return @list unless @find_first && @find_next
|
267
|
+
first_item = find_first_in_listinfo
|
268
|
+
return @list unless first_item
|
269
|
+
organized = []
|
270
|
+
organized[0] = first_item
|
271
|
+
1.upto(@list.length-1) do |idx|
|
272
|
+
current_item = organized[idx-1]
|
273
|
+
next_item = find_next_listitem(current_item)
|
274
|
+
organized[idx] = next_item
|
275
|
+
end
|
276
|
+
organized
|
277
|
+
end
|
278
|
+
|
121
279
|
end
|
@@ -0,0 +1,462 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'DoublyLinkedList' do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
class DummyList < DoublyLinkedList
|
7
|
+
|
8
|
+
@@clear_first_callback = lambda { |list_info| list_info.first_item = nil }
|
9
|
+
@@clear_last_callback = lambda { |list_info| list_info.last_item = nil }
|
10
|
+
@@update_first_callback = lambda { |list_info, list| list_info.first_item = list.first.item_id }
|
11
|
+
@@update_last_callback = lambda { |list_info, list| list_info.last_item = list.last.item_id }
|
12
|
+
|
13
|
+
@@clear_next_callback = lambda { |list, item_idx| list[item_idx].next_item = nil }
|
14
|
+
@@clear_prev_callback = lambda { |list, item_idx| list[item_idx].prev_item = nil }
|
15
|
+
@@update_next_callback = lambda { |list, item_idx| list[item_idx].next_item = list[item_idx+1].item_id }
|
16
|
+
@@update_prev_callback = lambda { |list, item_idx| list[item_idx].prev_item = list[item_idx-1].item_id }
|
17
|
+
|
18
|
+
@@find_first_callback = lambda do |list_info, list|
|
19
|
+
if list_info
|
20
|
+
first_id = list_info.first_item
|
21
|
+
first_idx = list.index { |item| item.item_id == first_id }
|
22
|
+
return list[first_idx] if first_idx
|
23
|
+
end
|
24
|
+
|
25
|
+
# if first isn't set, try to figure out first by looking for an item with prev_item == nil
|
26
|
+
# NOTE: If multiple items have prev_item == nil, it will return the first one it finds.
|
27
|
+
first_idx = list.index { |item| item.prev_item == nil }
|
28
|
+
first_idx ? list[first_idx] : nil
|
29
|
+
end
|
30
|
+
|
31
|
+
@@find_last_callback = lambda do |list_info, list|
|
32
|
+
if list_info
|
33
|
+
last_id = list_info.last_item
|
34
|
+
last_idx = list.index { |item| item.item_id == last_id }
|
35
|
+
return list[last_idx] if last_idx && last_idx >= 0 && last_idx < list.size
|
36
|
+
end
|
37
|
+
|
38
|
+
# if last isn't set, try to figure out last by looking for an item with next_item == nil
|
39
|
+
# NOTE: If multiple items have next_item == nil, it will return the first one it finds.
|
40
|
+
last_idx = list.index { |item| item.next_item == nil }
|
41
|
+
last_idx ? list[last_idx] : nil
|
42
|
+
end
|
43
|
+
|
44
|
+
@@find_next_callback = lambda do |list, current_item|
|
45
|
+
next_id = current_item.next_item
|
46
|
+
next_idx = list.index { |item| item.item_id == next_id }
|
47
|
+
next_idx ? list[next_idx] : nil
|
48
|
+
end
|
49
|
+
@@find_prev_callback = lambda do |list, current_item|
|
50
|
+
prev_id = current_item.prev_item
|
51
|
+
prev_idx = list.index { |item| item.item_id == prev_id }
|
52
|
+
prev_idx ? list[prev_idx] : nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def initialize(*args)
|
56
|
+
new_args = args[0].dup unless args.empty?
|
57
|
+
new_args = {} if args.empty?
|
58
|
+
|
59
|
+
# set callbacks
|
60
|
+
new_args[:clear_first_callback] = @@clear_first_callback
|
61
|
+
new_args[:clear_last_callback] = @@clear_last_callback
|
62
|
+
new_args[:update_first_callback] = @@update_first_callback
|
63
|
+
new_args[:update_last_callback] = @@update_last_callback
|
64
|
+
|
65
|
+
new_args[:clear_next_callback] = @@clear_next_callback
|
66
|
+
new_args[:clear_prev_callback] = @@clear_prev_callback
|
67
|
+
new_args[:update_next_callback] = @@update_next_callback
|
68
|
+
new_args[:update_prev_callback] = @@update_prev_callback
|
69
|
+
|
70
|
+
new_args[:find_first_callback] = @@find_first_callback
|
71
|
+
new_args[:find_last_callback] = @@find_last_callback
|
72
|
+
new_args[:find_next_callback] = @@find_next_callback
|
73
|
+
new_args[:find_prev_callback] = @@find_prev_callback
|
74
|
+
|
75
|
+
super(new_args)
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.get_item_by_id(list,id)
|
79
|
+
list.index { |item| item.item_id == id }
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
class DummyListInfo
|
85
|
+
attr_accessor :first_item, :last_item, :item_ids
|
86
|
+
def initialize(info)
|
87
|
+
@first_item = info[:first_item] if info.has_key? :first_item
|
88
|
+
@last_item = info[:last_item] if info.has_key? :last_item
|
89
|
+
@item_ids = info[:item_ids] if info.has_key? :item_ids
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class DummyListItem
|
94
|
+
attr_accessor :next_item, :prev_item, :value, :item_id
|
95
|
+
def initialize(item)
|
96
|
+
@next_item = item[:next_item] if item.has_key? :next_item
|
97
|
+
@prev_item = item[:prev_item] if item.has_key? :prev_item
|
98
|
+
@value = item[:value] if item.has_key? :value
|
99
|
+
@item_id = item[:item_id] if item.has_key? :item_id
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
after(:all) do
|
105
|
+
Object.send(:remove_const, "DummyList")
|
106
|
+
Object.send(:remove_const, "DummyListInfo")
|
107
|
+
Object.send(:remove_const, "DummyListItem")
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
describe '#new' do
|
112
|
+
it "should initialize to empty list" do
|
113
|
+
l = DummyList.new
|
114
|
+
expect(l.size).to eq 0
|
115
|
+
expect(l.first).to be_nil
|
116
|
+
expect(l.last).to be_nil
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should initialize with list info" do
|
120
|
+
l = DummyList.new :list_info => {:title =>'test list', :description => 'Test out my doubly linked list.'}
|
121
|
+
expect(l.size).to eq 0
|
122
|
+
expect(l.first).to be_nil
|
123
|
+
expect(l.last).to be_nil
|
124
|
+
expect(l.list_info).to be_kind_of(Hash)
|
125
|
+
expect(l.list_info).to eq( {:title =>'test list', :description => 'Test out my doubly linked list.'} )
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should initialize with items" do
|
129
|
+
# info = DummyListInfo.new( :first_item => 2, :last_item => 4, :item_ids => [1,2,3,4] )
|
130
|
+
items = []
|
131
|
+
items << DummyListItem.new( :item_id => 1, :prev_item => 2, :next_item => 3, :value => 'cat' )
|
132
|
+
items << DummyListItem.new( :item_id => 2, :prev_item => nil, :next_item => 1, :value => 'dog' )
|
133
|
+
items << DummyListItem.new( :item_id => 3, :prev_item => 1, :next_item => 4, :value => 'rabbit' )
|
134
|
+
items << DummyListItem.new( :item_id => 4, :prev_item => 3, :next_item => nil, :value => 'fish' )
|
135
|
+
l = DummyList.new :items => items
|
136
|
+
# l = DummyList.new :items => items, :list_info => info
|
137
|
+
expect(l.size).to eq 4
|
138
|
+
expect(l.first.value).to eq 'dog'
|
139
|
+
expect(l.last.value).to eq 'fish'
|
140
|
+
list_items = l.to_a.collect {|i| i.value }
|
141
|
+
expect(list_items).to eq ['dog','cat','rabbit','fish']
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should initialize with list info and items" do
|
145
|
+
info = DummyListInfo.new( :first_item => 4, :last_item => 3, :item_ids => [1,2,3,4] )
|
146
|
+
items = []
|
147
|
+
items << DummyListItem.new( :item_id => 1, :prev_item => 2, :next_item => 3, :value => 'cat' )
|
148
|
+
items << DummyListItem.new( :item_id => 2, :prev_item => 4, :next_item => 1, :value => 'dog' )
|
149
|
+
items << DummyListItem.new( :item_id => 3, :prev_item => 1, :next_item => nil, :value => 'rabbit' )
|
150
|
+
items << DummyListItem.new( :item_id => 4, :prev_item => nil, :next_item => 2, :value => 'fish' )
|
151
|
+
l = DummyList.new :items => items, :list_info => info
|
152
|
+
expect(l.first_item).to eq 4
|
153
|
+
expect(l.last_item).to eq 3
|
154
|
+
expect(l.size).to eq 4
|
155
|
+
expect(l.first.value).to eq 'fish'
|
156
|
+
expect(l.last.value).to eq 'rabbit'
|
157
|
+
list_items = l.to_a.collect {|i| i.value }
|
158
|
+
expect(list_items).to eq ['fish','dog','cat','rabbit']
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe '#add_last' do
|
163
|
+
it "should create list and add item when list is empty" do
|
164
|
+
l = DummyList.new
|
165
|
+
expect(l.size).to eq 0
|
166
|
+
expect(l.first).to be_nil
|
167
|
+
expect(l.last).to be_nil
|
168
|
+
|
169
|
+
new_item = DummyListItem.new({:value=>'cat',:item_id=>'c1'})
|
170
|
+
expect(l.add_last(new_item)).to eq 1
|
171
|
+
expect(l.size).to eq 1
|
172
|
+
expect(l.first.value).to eq 'cat'
|
173
|
+
expect(l.last.value).to eq 'cat'
|
174
|
+
list_items = l.to_a.collect {|i| i.value }
|
175
|
+
expect(list_items).to eq ['cat']
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should add item after last when one item list" do
|
179
|
+
l = DummyList.new :items => [
|
180
|
+
DummyListItem.new({:value=>'dog',:item_id=>'d1',:prev_item=>nil,:next_item=>nil}) ]
|
181
|
+
expect(l.size).to eq 1
|
182
|
+
expect(l.first.value).to eq 'dog'
|
183
|
+
expect(l.last.value).to eq 'dog'
|
184
|
+
|
185
|
+
new_item = DummyListItem.new({:value=>'cat',:item_id=>'c1'})
|
186
|
+
expect(l.add_last(new_item)).to eq 2
|
187
|
+
expect(l.size).to eq 2
|
188
|
+
expect(l.first.value).to eq 'dog'
|
189
|
+
expect(l.last.value).to eq 'cat'
|
190
|
+
list_items = l.to_a.collect {|i| i.value }
|
191
|
+
expect(list_items).to eq ['dog','cat']
|
192
|
+
end
|
193
|
+
|
194
|
+
it "should add item after last when multiple item list" do
|
195
|
+
l = DummyList.new :items => [
|
196
|
+
DummyListItem.new({:value=>'cat', :item_id=>'c1', :prev_item=>nil, :next_item=>'d1'}),
|
197
|
+
DummyListItem.new({:value=>'dog', :item_id=>'d1', :prev_item=>'c1', :next_item=>'r1'}),
|
198
|
+
DummyListItem.new({:value=>'rabbit', :item_id=>'r1', :prev_item=>'d1', :next_item=>'f1'}),
|
199
|
+
DummyListItem.new({:value=>'fish', :item_id=>'f1', :prev_item=>'r1', :next_item=>nil })]
|
200
|
+
expect(l.size).to eq 4
|
201
|
+
expect(l.first.value).to eq 'cat'
|
202
|
+
expect(l.last.value).to eq 'fish'
|
203
|
+
|
204
|
+
new_item = DummyListItem.new({:value=>'gerbil',:item_id=>'g1'})
|
205
|
+
expect(l.add_last(new_item)).to eq 5
|
206
|
+
expect(l.size).to eq 5
|
207
|
+
expect(l.first.value).to eq 'cat'
|
208
|
+
expect(l.last.value).to eq 'gerbil'
|
209
|
+
list_items = l.to_a.collect {|i| i.value }
|
210
|
+
expect(list_items).to eq ['cat','dog','rabbit','fish','gerbil']
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
describe '#add_first' do
|
215
|
+
it "should create list and add item when list is empty" do
|
216
|
+
l = DummyList.new
|
217
|
+
expect(l.size).to eq 0
|
218
|
+
expect(l.first).to be_nil
|
219
|
+
expect(l.last).to be_nil
|
220
|
+
|
221
|
+
new_item = DummyListItem.new({:value=>'cat',:item_id=>'c1'})
|
222
|
+
expect(l.add_first(new_item)).to eq 1
|
223
|
+
expect(l.size).to eq 1
|
224
|
+
expect(l.first.value).to eq 'cat'
|
225
|
+
expect(l.last.value).to eq 'cat'
|
226
|
+
list_items = l.to_a.collect {|i| i.value }
|
227
|
+
expect(list_items).to eq ['cat']
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should add item before first when one item list" do
|
231
|
+
l = DummyList.new :items => [
|
232
|
+
DummyListItem.new({:value=>'dog',:item_id=>'d1',:prev_item=>nil,:next_item=>nil}) ]
|
233
|
+
expect(l.size).to eq 1
|
234
|
+
expect(l.first.value).to eq 'dog'
|
235
|
+
expect(l.last.value).to eq 'dog'
|
236
|
+
|
237
|
+
new_item = DummyListItem.new({:value=>'cat',:item_id=>'c1'})
|
238
|
+
expect(l.add_first(new_item)).to eq 2
|
239
|
+
expect(l.size).to eq 2
|
240
|
+
expect(l.first.value).to eq 'cat'
|
241
|
+
expect(l.last.value).to eq 'dog'
|
242
|
+
list_items = l.to_a.collect {|i| i.value }
|
243
|
+
expect(list_items).to eq ['cat','dog']
|
244
|
+
end
|
245
|
+
|
246
|
+
it "should add item before first when multiple item list" do
|
247
|
+
l = DummyList.new :items => [
|
248
|
+
DummyListItem.new({:value=>'cat', :item_id=>'c1', :prev_item=>nil, :next_item=>'d1'}),
|
249
|
+
DummyListItem.new({:value=>'dog', :item_id=>'d1', :prev_item=>'c1', :next_item=>'r1'}),
|
250
|
+
DummyListItem.new({:value=>'rabbit', :item_id=>'r1', :prev_item=>'d1', :next_item=>'f1'}),
|
251
|
+
DummyListItem.new({:value=>'fish', :item_id=>'f1', :prev_item=>'r1', :next_item=>nil })]
|
252
|
+
expect(l.size).to eq 4
|
253
|
+
expect(l.first.value).to eq 'cat'
|
254
|
+
expect(l.last.value).to eq 'fish'
|
255
|
+
|
256
|
+
new_item = DummyListItem.new({:value=>'gerbil',:item_id=>'g1'})
|
257
|
+
expect(l.add_first(new_item)).to eq 5
|
258
|
+
expect(l.size).to eq 5
|
259
|
+
expect(l.first.value).to eq 'gerbil'
|
260
|
+
expect(l.last.value).to eq 'fish'
|
261
|
+
list_items = l.to_a.collect {|i| i.value }
|
262
|
+
expect(list_items).to eq ['gerbil','cat','dog','rabbit','fish']
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
describe '#remove_last' do
|
267
|
+
it "should return nil when list is empty" do
|
268
|
+
l = DummyList.new
|
269
|
+
expect(l.size).to eq 0
|
270
|
+
expect(l.first).to be_nil
|
271
|
+
expect(l.last).to be_nil
|
272
|
+
|
273
|
+
expect(l.remove_last).to be_nil
|
274
|
+
expect(l.size).to eq 0
|
275
|
+
expect(l.first).to be_nil
|
276
|
+
expect(l.last).to be_nil
|
277
|
+
end
|
278
|
+
|
279
|
+
it "should remove item emptying the list and return item's data when one item list" do
|
280
|
+
l = DummyList.new :items => [
|
281
|
+
DummyListItem.new({:value=>'dog',:item_id=>'d1',:prev_item=>nil,:next_item=>nil}) ]
|
282
|
+
expect(l.size).to eq 1
|
283
|
+
expect(l.first.value).to eq 'dog'
|
284
|
+
expect(l.last.value).to eq 'dog'
|
285
|
+
|
286
|
+
expect(l.remove_last.value).to eq 'dog'
|
287
|
+
expect(l.size).to eq 0
|
288
|
+
expect(l.first).to be_nil
|
289
|
+
expect(l.last).to be_nil
|
290
|
+
end
|
291
|
+
|
292
|
+
it "should add item before first when multiple item list" do
|
293
|
+
l = DummyList.new :items => [
|
294
|
+
DummyListItem.new({:value=>'cat', :item_id=>'c1', :prev_item=>nil, :next_item=>'d1'}),
|
295
|
+
DummyListItem.new({:value=>'dog', :item_id=>'d1', :prev_item=>'c1', :next_item=>'r1'}),
|
296
|
+
DummyListItem.new({:value=>'rabbit', :item_id=>'r1', :prev_item=>'d1', :next_item=>'f1'}),
|
297
|
+
DummyListItem.new({:value=>'fish', :item_id=>'f1', :prev_item=>'r1', :next_item=>nil })]
|
298
|
+
expect(l.size).to eq 4
|
299
|
+
expect(l.first.value).to eq 'cat'
|
300
|
+
expect(l.last.value).to eq 'fish'
|
301
|
+
|
302
|
+
expect(l.remove_last.value).to eq 'fish'
|
303
|
+
expect(l.size).to eq 3
|
304
|
+
expect(l.first.value).to eq 'cat'
|
305
|
+
expect(l.last.value).to eq 'rabbit'
|
306
|
+
list_items = l.to_a.collect {|i| i.value }
|
307
|
+
expect(list_items).to eq ['cat','dog','rabbit']
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
describe '#remove_first' do
|
312
|
+
it "should return nil when list is empty" do
|
313
|
+
l = DummyList.new
|
314
|
+
expect(l.size).to eq 0
|
315
|
+
expect(l.first).to be_nil
|
316
|
+
expect(l.last).to be_nil
|
317
|
+
|
318
|
+
expect(l.remove_first).to be_nil
|
319
|
+
expect(l.size).to eq 0
|
320
|
+
expect(l.first).to be_nil
|
321
|
+
expect(l.last).to be_nil
|
322
|
+
end
|
323
|
+
|
324
|
+
it "should remove item emptying the list and return item's data when one item list" do
|
325
|
+
l = DummyList.new :items => [
|
326
|
+
DummyListItem.new({:value=>'dog',:item_id=>'d1',:prev_item=>nil,:next_item=>nil}) ]
|
327
|
+
expect(l.size).to eq 1
|
328
|
+
expect(l.first.value).to eq 'dog'
|
329
|
+
expect(l.last.value).to eq 'dog'
|
330
|
+
|
331
|
+
expect(l.remove_first.value).to eq 'dog'
|
332
|
+
expect(l.size).to eq 0
|
333
|
+
expect(l.first).to be_nil
|
334
|
+
expect(l.last).to be_nil
|
335
|
+
end
|
336
|
+
|
337
|
+
it "should add item before first when multiple item list" do
|
338
|
+
l = DummyList.new :items => [
|
339
|
+
DummyListItem.new({:value=>'cat', :item_id=>'c1', :prev_item=>nil, :next_item=>'d1'}),
|
340
|
+
DummyListItem.new({:value=>'dog', :item_id=>'d1', :prev_item=>'c1', :next_item=>'r1'}),
|
341
|
+
DummyListItem.new({:value=>'rabbit', :item_id=>'r1', :prev_item=>'d1', :next_item=>'f1'}),
|
342
|
+
DummyListItem.new({:value=>'fish', :item_id=>'f1', :prev_item=>'r1', :next_item=>nil })]
|
343
|
+
expect(l.size).to eq 4
|
344
|
+
expect(l.first.value).to eq 'cat'
|
345
|
+
expect(l.last.value).to eq 'fish'
|
346
|
+
|
347
|
+
expect(l.remove_first.value).to eq 'cat'
|
348
|
+
expect(l.size).to eq 3
|
349
|
+
expect(l.first.value).to eq 'dog'
|
350
|
+
expect(l.last.value).to eq 'fish'
|
351
|
+
list_items = l.to_a.collect {|i| i.value }
|
352
|
+
expect(list_items).to eq ['dog','rabbit','fish']
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
describe '#missing_method' do
|
357
|
+
before(:all) do
|
358
|
+
class Dummy < DummyListInfo
|
359
|
+
def hello
|
360
|
+
"hello back at you"
|
361
|
+
end
|
362
|
+
def size
|
363
|
+
"very large indeed"
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
after(:all) do
|
368
|
+
Object.send(:remove_const, "Dummy")
|
369
|
+
end
|
370
|
+
|
371
|
+
context "when list responds to missing method" do
|
372
|
+
it "should pass method to list and succeed" do
|
373
|
+
l = DummyList.new :list_info => Dummy.new({}), :items => [
|
374
|
+
DummyListItem.new({:value=>'cat', :item_id=>'c1', :prev_item=>nil, :next_item=>'d1'}),
|
375
|
+
DummyListItem.new({:value=>'dog', :item_id=>'d1', :prev_item=>'c1', :next_item=>'r1'}),
|
376
|
+
DummyListItem.new({:value=>'rabbit', :item_id=>'r1', :prev_item=>'d1', :next_item=>'f1'}),
|
377
|
+
DummyListItem.new({:value=>'fish', :item_id=>'f1', :prev_item=>'r1', :next_item=>nil })]
|
378
|
+
list_items = l.values_at(1..2).collect {|i| i.value }
|
379
|
+
expect(list_items).to eq ['dog','rabbit']
|
380
|
+
sort_list = l.sort { |x,y| x.value <=> y.value }
|
381
|
+
list_items = sort_list.to_a.collect {|i| i.value }
|
382
|
+
expect(list_items).to eq ['cat','dog','fish','rabbit']
|
383
|
+
end
|
384
|
+
|
385
|
+
it "should pass method to list only even if list_info has the same method and succeed" do
|
386
|
+
l = DummyList.new :list_info => Dummy.new({}), :items => [
|
387
|
+
DummyListItem.new({:value=>'cat', :item_id=>'c1', :prev_item=>nil, :next_item=>'d1'}),
|
388
|
+
DummyListItem.new({:value=>'dog', :item_id=>'d1', :prev_item=>'c1', :next_item=>'r1'}),
|
389
|
+
DummyListItem.new({:value=>'rabbit', :item_id=>'r1', :prev_item=>'d1', :next_item=>'f1'}),
|
390
|
+
DummyListItem.new({:value=>'fish', :item_id=>'f1', :prev_item=>'r1', :next_item=>nil })]
|
391
|
+
expect(l.size).to eq 4
|
392
|
+
end
|
393
|
+
|
394
|
+
it "should pass method each to the list" do
|
395
|
+
l = DummyList.new :list_info => Dummy.new({}), :items => [
|
396
|
+
DummyListItem.new({:value=>'cat', :item_id=>'c1', :prev_item=>nil, :next_item=>'d1'}),
|
397
|
+
DummyListItem.new({:value=>'dog', :item_id=>'d1', :prev_item=>'c1', :next_item=>'r1'}),
|
398
|
+
DummyListItem.new({:value=>'rabbit', :item_id=>'r1', :prev_item=>'d1', :next_item=>'f1'}),
|
399
|
+
DummyListItem.new({:value=>'fish', :item_id=>'f1', :prev_item=>'r1', :next_item=>nil })]
|
400
|
+
a = []
|
401
|
+
l.each do |i|
|
402
|
+
a << i
|
403
|
+
list_items = l.to_a.collect {|i| i.value }
|
404
|
+
expect(list_items).to include i.value
|
405
|
+
end
|
406
|
+
list_items = a.to_a.collect {|i| i.value }
|
407
|
+
expect(list_items).to eq ['cat','dog','rabbit','fish']
|
408
|
+
end
|
409
|
+
|
410
|
+
it "should pass method each to the list when block is inline" do
|
411
|
+
l = DummyList.new :list_info => Dummy.new({}), :items => [
|
412
|
+
DummyListItem.new({:value=>'cat', :item_id=>'c1', :prev_item=>nil, :next_item=>'d1'}),
|
413
|
+
DummyListItem.new({:value=>'dog', :item_id=>'d1', :prev_item=>'c1', :next_item=>'r1'}),
|
414
|
+
DummyListItem.new({:value=>'rabbit', :item_id=>'r1', :prev_item=>'d1', :next_item=>'f1'}),
|
415
|
+
DummyListItem.new({:value=>'fish', :item_id=>'f1', :prev_item=>'r1', :next_item=>nil })]
|
416
|
+
a = []
|
417
|
+
l.each { |i| a<<i; list_items = l.to_a.collect {|i| i.value }; expect(list_items).to include i.value }
|
418
|
+
list_items = a.to_a.collect {|i| i.value }
|
419
|
+
expect(list_items).to eq ['cat','dog','rabbit','fish']
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
context "when list does not respond to missing method" do
|
424
|
+
it "should pass method to list_info and succeed if list_info responds to that method" do
|
425
|
+
l = DummyList.new :list_info => Dummy.new({}), :items => [
|
426
|
+
DummyListItem.new({:value=>'cat', :item_id=>'c1', :prev_item=>nil, :next_item=>'d1'}),
|
427
|
+
DummyListItem.new({:value=>'dog', :item_id=>'d1', :prev_item=>'c1', :next_item=>'r1'}),
|
428
|
+
DummyListItem.new({:value=>'rabbit', :item_id=>'r1', :prev_item=>'d1', :next_item=>'f1'}),
|
429
|
+
DummyListItem.new({:value=>'fish', :item_id=>'f1', :prev_item=>'r1', :next_item=>nil })]
|
430
|
+
expect(l.hello).to eq 'hello back at you'
|
431
|
+
end
|
432
|
+
|
433
|
+
it "should not pass array method to list_info when @list is empty and succeed if list_info responds to that method" do
|
434
|
+
l = DummyList.new :list_info => Dummy.new({})
|
435
|
+
expect(l.size).not_to eq 'very large indeed'
|
436
|
+
expect(l.size).to eq 0
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
context "when neither list nor list_info respond to missing method" do
|
441
|
+
it "should raise an error if it is not an array method nor list_info method" do
|
442
|
+
l = DummyList.new :list_info => Dummy.new({}), :items => [
|
443
|
+
DummyListItem.new({:value=>'cat', :item_id=>'c1', :prev_item=>nil, :next_item=>'d1'}),
|
444
|
+
DummyListItem.new({:value=>'dog', :item_id=>'d1', :prev_item=>'c1', :next_item=>'r1'}),
|
445
|
+
DummyListItem.new({:value=>'rabbit', :item_id=>'r1', :prev_item=>'d1', :next_item=>'f1'}),
|
446
|
+
DummyListItem.new({:value=>'fish', :item_id=>'f1', :prev_item=>'r1', :next_item=>nil })]
|
447
|
+
expect{ l.foo }.to raise_error(NoMethodError, /undefined method `foo'/)
|
448
|
+
end
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
describe '#inspect' do
|
453
|
+
it "should return class and items" do
|
454
|
+
l = DummyList.new :list_info => DummyListInfo.new({}), :items => [
|
455
|
+
DummyListItem.new({:value=>'cat', :item_id=>'c1', :prev_item=>nil, :next_item=>'d1'}),
|
456
|
+
DummyListItem.new({:value=>'dog', :item_id=>'d1', :prev_item=>'c1', :next_item=>'r1'}),
|
457
|
+
DummyListItem.new({:value=>'rabbit', :item_id=>'r1', :prev_item=>'d1', :next_item=>nil })]
|
458
|
+
expect(l.inspect).to match /#<DummyList:0x(\d|[abcdef])* \[(\s|\S)*@value="cat"(\s|\S)*@value="dog"(\s|\S)*@value="rabbit"(\s|\S)*/
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
end
|
File without changes
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: doubly_linked_list
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- E. Lynette Rayle
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-03-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|
@@ -85,7 +85,8 @@ files:
|
|
85
85
|
- Rakefile
|
86
86
|
- doubly_linked_list.gemspec
|
87
87
|
- lib/doubly_linked_list.rb
|
88
|
-
- spec/
|
88
|
+
- spec/complex_doubly_linked_list_spec.rb
|
89
|
+
- spec/simple_doubly_linked_list_spec.rb
|
89
90
|
- spec/spec_helper.rb
|
90
91
|
homepage: https://github.com/elrayle/doubly_linked_list
|
91
92
|
licenses:
|
@@ -113,5 +114,6 @@ specification_version: 4
|
|
113
114
|
summary: Ruby implementation of doubly_linked_lists using an array to hold and manipulate
|
114
115
|
items.
|
115
116
|
test_files:
|
116
|
-
- spec/
|
117
|
+
- spec/complex_doubly_linked_list_spec.rb
|
118
|
+
- spec/simple_doubly_linked_list_spec.rb
|
117
119
|
- spec/spec_helper.rb
|