doubly_linked_list 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
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