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: 7d7076f1fe66bdbee71d9f8ab23203733c7f302d
4
- data.tar.gz: 8994066abb5e143f78a14f84e1a1aabe0ecaa0bd
3
+ metadata.gz: 0872378b46d546aec11ec96d3675082b099fe887
4
+ data.tar.gz: 0922c01e2fd25b855c904824152d7cf99b9f5bca
5
5
  SHA512:
6
- metadata.gz: dab92466e5d1affe6b07a8f1a2e0dd7494b1d2e9e2ccfd98b076fe277db743111f86e827fac62633693e0e091c9445ab864e774c2015dcabb4c7d29d09ba7c83
7
- data.tar.gz: 22cdf33047c74811c85d3730a204d8a3f42dd660803ee4196204679213fb5d01ac839ea5c1c553b1862df759ba4abca3de2b8673784974cb06b073277a69f491
6
+ metadata.gz: 018b32fc622f2ed204602a51a90cc9a94360f6357efe20dd89e0756f127570264ad1ff2ad62cf410d92b3e952a38ee54c822c0055b27e65a6397ec4b32e44a2a
7
+ data.tar.gz: 98fbb16c4415b0dbed687b3e9e1076fa6289d7237c2b036c8ec6d6c7ddf0f7fbd76b537e7b7b9c833bc176d5eb6e555909e413aa4b102c5c151cca8eb62f3302
@@ -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.5'
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
@@ -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
- @list_info = args[0][:list_info] if ! args.empty? && args[0].is_a?(Hash) && args[0].key?(:list_info)
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
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.5
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-01-30 00:00:00.000000000 Z
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/doubly_linked_list_spec.rb
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/doubly_linked_list_spec.rb
117
+ - spec/complex_doubly_linked_list_spec.rb
118
+ - spec/simple_doubly_linked_list_spec.rb
117
119
  - spec/spec_helper.rb