linked_list 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/Benchmarks.txt ADDED
@@ -0,0 +1,26 @@
1
+ (in /Users/francois/Documents/work/linked_list)
2
+ Loaded suite -e
3
+ Started
4
+ .................................................................................................
5
+ Finished in 0.015711 seconds.
6
+
7
+ 97 tests, 97 assertions, 0 failures, 0 errors
8
+ Building a list of 1 million random strings
9
+ Took 4.389 seconds
10
+ Converting to an array
11
+ Took 1.686 seconds
12
+ user system total real
13
+ list#push/pop 0.350000 0.000000 0.350000 ( 0.364001)
14
+ array#push/pop 0.000000 0.000000 0.000000 ( 0.009894)
15
+ user system total real
16
+ list#last 0.000000 0.000000 0.000000 ( 0.000027)
17
+ array#last 0.000000 0.000000 0.000000 ( 0.000012)
18
+ user system total real
19
+ list#first 0.010000 0.000000 0.010000 ( 0.001188)
20
+ array#first 0.000000 0.000000 0.000000 ( 0.000449)
21
+ user system total real
22
+ list#reverse 7.540000 0.170000 7.710000 ( 7.806306)
23
+ array#reverse 0.010000 0.010000 0.020000 ( 0.008443)
24
+ user system total real
25
+ list#dup 23.080000 0.380000 23.460000 ( 24.039316)
26
+ array#dup 0.000000 0.000000 0.000000 ( 0.000017)
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 1.0.0 2008-11-12
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/Manifest.txt ADDED
@@ -0,0 +1,14 @@
1
+ History.txt
2
+ Manifest.txt
3
+ Benchmarks.txt
4
+ README.rdoc
5
+ Rakefile
6
+ lib/linked_list.rb
7
+ lib/linked_list/node.rb
8
+ script/console
9
+ script/destroy
10
+ script/generate
11
+ tasks/benchmark.rake
12
+ test/test_helper.rb
13
+ test/test_linked_list.rb
14
+ test/test_linked_list_node.rb
data/README.rdoc ADDED
@@ -0,0 +1,58 @@
1
+ = LinkedList
2
+
3
+ * http://linkedlist.rubyforge.org/
4
+
5
+ == DESCRIPTION:
6
+
7
+ A simple linked list implementation that follows Ruby's conventions.
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ * FIXME: #dup is implemented by reversing the list twice. This should be pretty slow... Untested, not benchmarked.
12
+ * This implementation isn't thread safe.
13
+
14
+ == SYNOPSIS:
15
+
16
+ list = LinkedList.new
17
+ list << "a"
18
+ list.push "b"
19
+ list.unshift "c"
20
+ list.inspect
21
+ #=> ("c" ("b" ("a" nil)))
22
+ list.pop
23
+ #=> ("b" ("a" nil))
24
+ list.map {|v| v*2}
25
+ #=> ("bb" ("aa" nil))
26
+
27
+ == REQUIREMENTS:
28
+
29
+ * Ruby 1.8.6+
30
+
31
+ == INSTALL:
32
+
33
+ * sudo gem install linked_list
34
+
35
+ == LICENSE:
36
+
37
+ (The MIT License)
38
+
39
+ Copyright (c) 2008 François Beausoleil
40
+
41
+ Permission is hereby granted, free of charge, to any person obtaining
42
+ a copy of this software and associated documentation files (the
43
+ 'Software'), to deal in the Software without restriction, including
44
+ without limitation the rights to use, copy, modify, merge, publish,
45
+ distribute, sublicense, and/or sell copies of the Software, and to
46
+ permit persons to whom the Software is furnished to do so, subject to
47
+ the following conditions:
48
+
49
+ The above copyright notice and this permission notice shall be
50
+ included in all copies or substantial portions of the Software.
51
+
52
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
53
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
54
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
55
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
56
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
57
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
58
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ %w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
2
+ require File.dirname(__FILE__) + '/lib/linked_list'
3
+
4
+ # Generate all the Rake tasks
5
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
6
+ $hoe = Hoe.new('linked_list', LinkedList::VERSION) do |p|
7
+ p.developer('François Beausoleil', 'francois@teksol.info')
8
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
9
+ p.rubyforge_name = "linkedlist"
10
+ p.extra_dev_deps = [
11
+ ['newgem', ">= #{::Newgem::VERSION}"],
12
+ ['francois-shoulda', ">= 2.0.5"]
13
+ ]
14
+
15
+ p.clean_globs |= %w[**/.DS_Store tmp *.log]
16
+ path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
17
+ p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
18
+ p.rsync_args = '-av --delete --ignore-errors'
19
+ end
20
+
21
+ require 'newgem/tasks' # load /tasks/*.rake
22
+ Dir['tasks/**/*.rake'].each { |t| load t }
@@ -0,0 +1,204 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require "linked_list/node"
5
+
6
+ # Linked list implementation.
7
+ # Linked lists have O(1) insertions and pops. Traversal is O(n).
8
+ #
9
+ # == Implementation Notes
10
+ # This implementation isn't thread safe. In fact, traversal is thread safe, but insertions and removals aren't.
11
+ #
12
+ # This implementation has problems with #dup, but beyond that, it looks fine. It needs to be battle tested though.
13
+ # As a performance optimization, #size is cached and maintained locally, instead of being recalculated everytime.
14
+ class LinkedList
15
+ VERSION = '1.0.0'
16
+ include Enumerable
17
+
18
+ attr_reader :cdr, :size
19
+ alias_method :length, :size
20
+
21
+ def initialize
22
+ clear
23
+ end
24
+
25
+ # Two lists are equal if they have the same values in the same positions.
26
+ def ==(other)
27
+ cdr == other.cdr
28
+ end
29
+
30
+ # A list is empty if it doesn't have any nodes.
31
+ def empty?
32
+ cdr.nil?
33
+ end
34
+
35
+ # Returns a duplicate of this list, where the nodes are also copied.
36
+ # FIXME: Performance hog... The implementation sucks big time.
37
+ def dup
38
+ reverse.reverse
39
+ end
40
+
41
+ # Yields each value
42
+ def each
43
+ each_node do |node|
44
+ yield node.value
45
+ end
46
+ end
47
+
48
+ # Yields each LinkedList::Node (or subclass)
49
+ def each_node
50
+ node = cdr
51
+ while node
52
+ yield node
53
+ node = node.cdr
54
+ end
55
+ end
56
+ protected :each_node
57
+
58
+ # Returns an Array that has the same values as this LinkedList
59
+ def to_a
60
+ inject(Array.new) do |memo, value|
61
+ memo << value
62
+ end
63
+ end
64
+
65
+ def at(index)
66
+ index = normalize_index(index)
67
+ each_with_index do |value, idx|
68
+ return value if index == idx
69
+ end
70
+ nil
71
+ end
72
+
73
+ def normalize_index(index)
74
+ index < 0 ? (length + index) : index
75
+ end
76
+ protected :normalize_index
77
+
78
+ def [](*args)
79
+ case args.length
80
+ when 1
81
+ case args.first
82
+ when Range
83
+ indexes = args.first
84
+ start, stop = normalize_index(indexes.first), normalize_index(indexes.exclude_end? ? indexes.last - 1 : indexes.last)
85
+ indexes = (start .. stop)
86
+ result = []
87
+ each_with_index do |value, idx|
88
+ next unless indexes.include?(idx)
89
+ result << value
90
+ end
91
+ result
92
+ else
93
+ at(args.first)
94
+ end
95
+ when 2
96
+ index = normalize_index(args.first)
97
+ return nil unless (0 .. length).include?(index)
98
+ count = args.last
99
+ self[index ... (index + count)]
100
+ else
101
+ raise ArgumentError, "Expected (index), (index, length) or (index0..index1), received #{args.inspect}"
102
+ end
103
+ end
104
+
105
+ # Returns a new instance of self with a reverse insertion order
106
+ def reverse
107
+ list = new_species
108
+ each do |value|
109
+ list << value
110
+ end
111
+ list
112
+ end
113
+
114
+ # Destructively maps this list's values to the return value of the block
115
+ def map!
116
+ each_node do |node|
117
+ node.value = yield(node.value)
118
+ end
119
+ end
120
+
121
+ # Returns a new instance of self where the values have been replaced with the results of the block's
122
+ def map(&block)
123
+ list = dup
124
+ list.map!(&block)
125
+ list
126
+ end
127
+
128
+ # Pushes a new value at the head of this list
129
+ def <<(value)
130
+ @cdr = new_node(value, cdr)
131
+ @lcdr = @cdr if @lcdr.nil?
132
+ @size += 1
133
+ self
134
+ end
135
+ alias_method :push, :<<
136
+ alias_method :unshift, :<<
137
+
138
+ # Pops the head of the list, returning the value
139
+ def pop
140
+ return nil if empty?
141
+ @size -= 1
142
+ value = cdr.value
143
+ @cdr = cdr.cdr
144
+ @lcdr = nil if empty?
145
+ value
146
+ end
147
+ alias_method :shift, :pop
148
+
149
+ # Initializes this list to the empty state
150
+ def clear
151
+ @cdr, @lcdr, @size = nil, nil, 0
152
+ end
153
+
154
+ # Returns the first value of this list
155
+ def first
156
+ cdr.nil? ? nil : cdr.value
157
+ end
158
+
159
+ # Returns the last value of this list
160
+ def last
161
+ return nil if empty?
162
+ @lcdr.value
163
+ end
164
+
165
+ def concat(other)
166
+ result = new_species
167
+ other.reverse.each do |value|
168
+ result << value
169
+ end
170
+ self.reverse.each do |value|
171
+ result << value
172
+ end
173
+ result
174
+ end
175
+ alias_method :+, :concat
176
+
177
+ # Returns a new instance of the same class as self.
178
+ def new_species
179
+ self.class.new
180
+ end
181
+ protected :new_species
182
+
183
+ # Returns a new node instance.
184
+ def new_node(value, cdr)
185
+ node_class.new(value, cdr)
186
+ end
187
+ protected :new_node
188
+
189
+ # Returns the class of node to use. Defaults to LinkedList::Node.
190
+ def node_class
191
+ LinkedList::Node
192
+ end
193
+ protected :node_class
194
+
195
+ # Returns a nice looking view of this list.
196
+ # list = LinkedList.new
197
+ # list.push "a"
198
+ # list.push "b"
199
+ # list.inspect
200
+ # #=> ("b" ("a" nil))
201
+ def inspect
202
+ cdr.inspect
203
+ end
204
+ end
@@ -0,0 +1,23 @@
1
+ class LinkedList
2
+ # Implements a single node of the linked list.
3
+ class Node
4
+ attr_accessor :cdr, :value
5
+
6
+ def initialize(value, cdr)
7
+ @cdr, @value = cdr, value
8
+ end
9
+
10
+ # Two nodes are equal if their values are equal and their cdr's are equal too.
11
+ def ==(other)
12
+ cdr == other.cdr && value == other.value
13
+ end
14
+
15
+ # Returns a nice-looking string.
16
+ # node = LinkedList::Node.new("a", nil)
17
+ # node.inspect
18
+ # #=> ("a" nil)
19
+ def inspect
20
+ "(#{value.inspect} #{cdr.inspect})"
21
+ end
22
+ end
23
+ end
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/linked_list.rb'}"
9
+ puts "Loading linked_list gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,74 @@
1
+ namespace :test do
2
+ task :benchmark => %w(test) do
3
+ require "benchmark"
4
+ include Benchmark
5
+ $:.unshift File.dirname(__FILE__) + "/../lib"
6
+ require "linked_list"
7
+
8
+ puts "Building a list of 1 million random strings"
9
+ list = nil
10
+ time = realtime do
11
+ list = list_of_elements(1_000_000)
12
+ end
13
+ puts "Took %.3f seconds" % time
14
+ puts "Converting to an array"
15
+ array = nil
16
+ time = realtime do
17
+ array = list.to_a
18
+ end
19
+ puts "Took %.3f seconds" % time
20
+
21
+ bm(16) do |x|
22
+ x.report("list#push/pop") do
23
+ 20_000.times do
24
+ list.push "a"
25
+ end
26
+ 20_000.times do
27
+ list.pop
28
+ end
29
+ end
30
+ x.report("array#push/pop") do
31
+ 20_000.times do
32
+ array.push "a"
33
+ end
34
+ 20_000.times do
35
+ array.pop
36
+ end
37
+ end
38
+ end
39
+
40
+ bm(16) do |x|
41
+ x.report("list#last") { 20.times { list.last } }
42
+ x.report("array#last") { 20.times { array.last } }
43
+ end
44
+
45
+ bm(16) do |x|
46
+ x.report("list#first") { 2_000.times { list.first } }
47
+ x.report("array#first") { 2_000.times { array.first } }
48
+ end
49
+
50
+ bm(16) do |x|
51
+ x.report("list#reverse") { list.reverse }
52
+ x.report("array#reverse") { array.reverse }
53
+ end
54
+
55
+ bm(16) do |x|
56
+ x.report("list#dup") { list.dup }
57
+ x.report("array#dup") { array.dup }
58
+ end
59
+ end
60
+ end
61
+
62
+ def list_of_elements(count)
63
+ list = LinkedList.new
64
+ count.times do
65
+ list << nil
66
+ end
67
+ list
68
+ end
69
+
70
+ CHARS = ('a' .. 'z').to_a + ('A' .. 'Z').to_a + ('0' .. '9').to_a
71
+ LENGTH = CHARS.length
72
+ def random_string
73
+ (0..10).inject("") {|str, _| str << CHARS[rand(LENGTH)]}
74
+ end
@@ -0,0 +1,6 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../lib/linked_list'
3
+ require "rubygems"
4
+
5
+ gem "francois-shoulda"
6
+ require "shoulda"
@@ -0,0 +1,516 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestLinkedList < Test::Unit::TestCase
4
+ context "An empty LinkedList" do
5
+ setup do
6
+ @list = LinkedList.new
7
+ end
8
+
9
+ context "#push'ing a value of nil" do
10
+ setup do
11
+ @list.push nil
12
+ end
13
+
14
+ should "have a length of 1" do
15
+ assert_equal 1, @list.length
16
+ end
17
+
18
+ should "be equal to [nil]" do
19
+ assert_equal [nil], @list.to_a
20
+ end
21
+ end
22
+
23
+ context "#push'ing an element" do
24
+ setup do
25
+ @list.push "a"
26
+ end
27
+
28
+ should "be equal to ['a']" do
29
+ assert_equal %w(a), @list.to_a
30
+ end
31
+ end
32
+
33
+ context "calling #reverse" do
34
+ setup do
35
+ @other = @list.reverse
36
+ end
37
+
38
+ should "return another list instance" do
39
+ assert_not_same @list, @other
40
+ end
41
+
42
+ should "return an empty list" do
43
+ assert @other.empty?
44
+ end
45
+ end
46
+
47
+ context "calling #to_a" do
48
+ setup do
49
+ @other = @list.to_a
50
+ end
51
+
52
+ should "be an Array" do
53
+ assert_kind_of Array, @other
54
+ end
55
+
56
+ should "be empty" do
57
+ assert @other.empty?
58
+ end
59
+ end
60
+
61
+ should "return nil on #at(0)" do
62
+ assert_nil @list.at(0)
63
+ end
64
+
65
+ should "return nil on #at(-1)" do
66
+ assert_nil @list.at(-1)
67
+ end
68
+
69
+ should "return nil on #[](1)" do
70
+ assert_nil @list[1]
71
+ end
72
+
73
+ should "return nil on #[](-1)" do
74
+ assert_nil @list[-1]
75
+ end
76
+
77
+ should "return nil on #[](0, 1)" do
78
+ assert_equal [], @list[0, 1]
79
+ end
80
+
81
+ should "return nil on #[](0..1)" do
82
+ assert_equal [], @list[0..1]
83
+ end
84
+
85
+ should "return nil on #[](0)" do
86
+ assert_nil @list[0]
87
+ end
88
+
89
+ should "return a new instance when calling #dup" do
90
+ assert_not_same @list, @list.dup
91
+ end
92
+
93
+ should "return nil for #first" do
94
+ assert_nil @list.first
95
+ end
96
+
97
+ should "return nil for #last" do
98
+ assert_nil @list.last
99
+ end
100
+
101
+ should "be empty" do
102
+ assert @list.empty?
103
+ end
104
+
105
+ should "have a length of 0" do
106
+ assert_equal 0, @list.length
107
+ end
108
+
109
+ should "have a size of 0" do
110
+ assert_equal 0, @list.size
111
+ end
112
+
113
+ should "never call the #each block" do
114
+ yielded = 0
115
+ @list.each do |value|
116
+ yielded += 1
117
+ end
118
+ assert yielded.zero?
119
+ end
120
+
121
+ context "calling #concat(['a'])" do
122
+ setup do
123
+ @other = @list.concat(%w(a))
124
+ end
125
+
126
+ should "return a new list" do
127
+ assert_not_same @other, @list
128
+ end
129
+
130
+ should "return a list with one more element" do
131
+ assert_equal @list.length + 1, @other.length
132
+ end
133
+
134
+ should "return a list equal to ('a' nil)" do
135
+ assert_equal LinkedList.new << "a", @other
136
+ end
137
+ end
138
+ end
139
+
140
+ context "A linked list with one element" do
141
+ setup do
142
+ @list = LinkedList.new
143
+ @list << "a"
144
+ end
145
+
146
+ context "calling #pop" do
147
+ setup do
148
+ @element = @list.pop
149
+ end
150
+
151
+ should "be empty?" do
152
+ assert @list.empty?
153
+ end
154
+
155
+ should "return the element" do
156
+ assert_equal "a", @element
157
+ end
158
+
159
+ should "have a size of 0" do
160
+ assert @list.size.zero?
161
+ end
162
+
163
+ should "return nil from #last" do
164
+ assert_nil @list.last
165
+ end
166
+
167
+ should "return nil from #first" do
168
+ assert_nil @list.first
169
+ end
170
+
171
+ context "pushing 'b'" do
172
+ setup do
173
+ @list.push "b"
174
+ end
175
+
176
+ should "NOT be empty" do
177
+ assert !@list.empty?
178
+ end
179
+
180
+ should "be ['b']" do
181
+ assert_equal %w(b), @list.to_a
182
+ end
183
+
184
+ should "return 'b' from #last" do
185
+ assert_equal "b", @list.last
186
+ end
187
+
188
+ should "return 'b' from #first" do
189
+ assert_equal "b", @list.first
190
+ end
191
+ end
192
+ end
193
+
194
+ context "calling #to_a" do
195
+ setup do
196
+ @other = @list.to_a
197
+ end
198
+
199
+ should "be equal to ['a']" do
200
+ assert_equal %w(a), @other
201
+ end
202
+ end
203
+
204
+ context "calling #reverse" do
205
+ setup do
206
+ @other = @list.reverse
207
+ end
208
+
209
+ should "be equal to the initial list" do
210
+ assert_equal @list, @other
211
+ end
212
+ end
213
+
214
+ context "calling #dup" do
215
+ setup do
216
+ @other = @list.dup
217
+ end
218
+
219
+ should "be a new instance" do
220
+ assert_not_same @list, @other
221
+ end
222
+
223
+ should "have duplicated the nodes" do
224
+ @list.map! {|value| value*2}
225
+ assert_not_equal @list, @other
226
+ end
227
+ end
228
+
229
+ should "return 'a' for #at(-1)" do
230
+ assert_equal "a", @list.at(-1)
231
+ end
232
+
233
+ should "return 'a' for #at(0)" do
234
+ assert_equal "a", @list.at(0)
235
+ end
236
+
237
+ should "return nil for #at(2)" do
238
+ assert_nil @list.at(2)
239
+ end
240
+
241
+ should "return nil for #at(-2)" do
242
+ assert_nil @list.at(-2)
243
+ end
244
+
245
+ should "return nil for #at(1)" do
246
+ assert_nil @list.at(1)
247
+ end
248
+
249
+ should "return 'a' for #first" do
250
+ assert_equal "a", @list.first
251
+ end
252
+
253
+ should "return 'a' for #last" do
254
+ assert_equal "a", @list.last
255
+ end
256
+
257
+ should "NOT be empty?" do
258
+ assert !@list.empty?
259
+ end
260
+
261
+ should "have a size of 1" do
262
+ assert_equal 1, @list.size
263
+ end
264
+
265
+ should "yield the single element to the #each block" do
266
+ @list.each do |value|
267
+ assert_equal "a", value
268
+ end
269
+ end
270
+
271
+ should "yield once calling #each" do
272
+ yielded = 0
273
+ @list.each do |value|
274
+ yielded += 1
275
+ end
276
+ assert_equal 1, yielded
277
+ end
278
+
279
+ should "yield the value and the index when calling #each_with_index" do
280
+ yields = []
281
+ @list.each_with_index do |value, index|
282
+ yields << [value, index]
283
+ end
284
+ assert_equal [["a", 0]], yields
285
+ end
286
+
287
+ should "include?('a')" do
288
+ assert @list.include?("a")
289
+ end
290
+
291
+ should "NOT include?('b')" do
292
+ assert !@list.include?("b")
293
+ end
294
+ end
295
+
296
+ context "A list with 2 elements" do
297
+ setup do
298
+ @list = LinkedList.new
299
+ @list << "a"
300
+ @list << "b"
301
+ end
302
+
303
+ context "calling #to_a" do
304
+ setup do
305
+ @other = @list.to_a
306
+ end
307
+
308
+ should "be equal to ['b', 'a']" do
309
+ assert_equal %w(b a), @other
310
+ end
311
+ end
312
+
313
+ context "calling #reverse" do
314
+ setup do
315
+ @other = @list.reverse
316
+ end
317
+
318
+ should "return the elements in insertion order" do
319
+ assert_equal %w(a b), @other.to_a
320
+ end
321
+ end
322
+
323
+ context "cleared" do
324
+ setup do
325
+ @list.clear
326
+ end
327
+
328
+ should "be empty?" do
329
+ assert @list.empty?
330
+ end
331
+ end
332
+
333
+ context "#map" do
334
+ setup do
335
+ @other = @list.map {|f| f*2}
336
+ end
337
+
338
+ should "return a list of 2 elements" do
339
+ assert_equal 2, @other.length
340
+ end
341
+
342
+ should "include?('aa')" do
343
+ assert @other.include?("aa")
344
+ end
345
+
346
+ should "include?('bb')" do
347
+ assert @other.include?("bb")
348
+ end
349
+
350
+ should "NOT have reversed the list" do
351
+ assert_equal %w(bb aa), @other.to_a
352
+ end
353
+ end
354
+
355
+ context "calling #pop" do
356
+ setup do
357
+ @element = @list.pop
358
+ end
359
+
360
+ should "NOT be empty?" do
361
+ assert !@list.empty?
362
+ end
363
+
364
+ should "return the moast recently pushed element" do
365
+ assert_equal "b", @element
366
+ end
367
+
368
+ should "have a size of 1" do
369
+ assert_equal 1, @list.size
370
+ end
371
+ end
372
+
373
+ should "return 'b' for #at(0)" do
374
+ assert_equal "b", @list.at(0)
375
+ end
376
+
377
+ should "return 'a' for #at(1)" do
378
+ assert_equal "a", @list.at(1)
379
+ end
380
+
381
+ should "return 'a' for #at(-1)" do
382
+ assert_equal "a", @list.at(-1)
383
+ end
384
+
385
+ should "return 'b' for #at(-2)" do
386
+ assert_equal "b", @list.at(-2)
387
+ end
388
+
389
+ should "return 'b' for #first" do
390
+ assert_equal "b", @list.first
391
+ end
392
+
393
+ should "return 'a' for #last" do
394
+ assert_equal "a", @list.last
395
+ end
396
+
397
+ should "include?('b')" do
398
+ assert @list.include?("b")
399
+ end
400
+
401
+ should "have a length of 2" do
402
+ assert_equal 2, @list.length
403
+ end
404
+
405
+ should "yield the value and the index when calling #each_with_index" do
406
+ yields = []
407
+ @list.each_with_index do |value, index|
408
+ yields << [value, index]
409
+ end
410
+ assert_equal [["b", 0], ["a", 1]], yields
411
+ end
412
+ end
413
+
414
+ context "A list with 5 elements" do
415
+ setup do
416
+ @list = LinkedList.new
417
+ @list << "a" << "b" << "c" << "d" << "e"
418
+ end
419
+
420
+ should "have a length of 5" do
421
+ assert_equal 5, @list.length
422
+ end
423
+
424
+ should "return 'a' for #at(-1)" do
425
+ assert_equal "a", @list.at(-1)
426
+ end
427
+
428
+ should "return 'e' for #at(-5)" do
429
+ assert_equal "e", @list.at(-5)
430
+ end
431
+
432
+ should "return ['e', 'd', 'c', 'b', 'a'] for #[](0..10)" do
433
+ assert_equal %w(e d c b a), @list[0..10]
434
+ end
435
+
436
+ should "return ['e', 'd'] for #[](0..1)" do
437
+ assert_equal %w(e d), @list[0..1]
438
+ end
439
+
440
+ should "return ['e'] for #[](0..0)" do
441
+ assert_equal %w(e), @list[0..0]
442
+ end
443
+
444
+ should "return ['e', 'd', 'c'] for #[](0..2)" do
445
+ assert_equal %w(e d c), @list[0..2]
446
+ end
447
+
448
+ should "return ['e', 'd', 'c', 'b', 'a'] for #[](0, 10)" do
449
+ assert_equal %w(e d c b a), @list[0, 10]
450
+ end
451
+
452
+ should "return ['e'] for #[](0, 1)" do
453
+ assert_equal %w(e), @list[0, 1]
454
+ end
455
+
456
+ should "return ['e', 'd'] for #[](0, 2)" do
457
+ assert_equal %w(e d), @list[0, 2]
458
+ end
459
+
460
+ should "return nil for #[](-240)" do
461
+ assert_nil @list[-240]
462
+ end
463
+
464
+ should "return nil for #[](240)" do
465
+ assert_nil @list[240]
466
+ end
467
+
468
+ should "return nil for #[](-240, 100)" do
469
+ assert_nil @list[-240, 100]
470
+ end
471
+
472
+ should "return nil for #[](240, 100)" do
473
+ assert_nil @list[240, 100]
474
+ end
475
+
476
+ should "return ['b', 'a'] for #[](-2..-1)" do
477
+ assert_equal %w(b a), @list[-2..-1]
478
+ end
479
+
480
+ should "return ['c', 'b'] for #[](-3, 2)" do
481
+ assert_equal %w(c b), @list[-3, 2]
482
+ end
483
+
484
+ context "calling #concat(['x', 'y', 'z'])" do
485
+ setup do
486
+ @other = @list.concat(%w(x y z))
487
+ end
488
+
489
+ should "return a new list" do
490
+ assert_not_same @list, @other
491
+ end
492
+
493
+ should "return a list of 8 elements" do
494
+ assert_equal 8, @other.length
495
+ end
496
+
497
+ should "return a LinkedList" do
498
+ assert_kind_of LinkedList, @other
499
+ end
500
+
501
+ should "return ['e', 'd', 'c', 'b', 'a', 'x', 'y', 'z']" do
502
+ assert_equal %w(e d c b a x y z), @other.to_a
503
+ end
504
+ end
505
+
506
+ context "calling #+(('z' nil))" do
507
+ setup do
508
+ @other = @list + (LinkedList.new << "z")
509
+ end
510
+
511
+ should "return ['e', 'd', 'c', 'b', 'a', 'z']" do
512
+ assert_equal %w(e d c b a z), @other.to_a
513
+ end
514
+ end
515
+ end
516
+ end
@@ -0,0 +1,41 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestLinkedListNode < Test::Unit::TestCase
4
+ context "A node with the empty string as a value at the end of the chain" do
5
+ setup do
6
+ @node = LinkedList::Node.new("", nil)
7
+ end
8
+
9
+ should "be equal to itself" do
10
+ assert_equal @node, @node
11
+ end
12
+
13
+ should "be equal to another node that is empty" do
14
+ assert_equal @node, LinkedList::Node.new("", nil)
15
+ end
16
+
17
+ should "NOT be equal to another node that has a different value" do
18
+ assert_not_equal @node, LinkedList::Node.new("a", nil)
19
+ end
20
+
21
+ should "NOT be equal to another node that has a different cdr" do
22
+ assert_not_equal @node, LinkedList::Node.new("", LinkedList::Node.new(nil, nil))
23
+ end
24
+
25
+ should "be inspectable" do
26
+ assert_equal "(\"\" nil)", @node.inspect
27
+ end
28
+ end
29
+
30
+ context "A node with a value of 'a' and a successor of 'b'" do
31
+ setup do
32
+ @tail = LinkedList::Node.new("b", nil)
33
+ @head = LinkedList::Node.new("a", @tail)
34
+ end
35
+
36
+ should "be inspectable" do
37
+ assert_equal "(\"a\" (\"b\" nil))", @head.inspect
38
+ end
39
+ end
40
+
41
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: linked_list
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - "Fran\xC3\xA7ois Beausoleil"
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-11-12 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: newgem
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.0.7
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: francois-shoulda
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 2.0.5
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: hoe
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 1.8.0
44
+ version:
45
+ description: A simple linked list implementation that follows Ruby's conventions.
46
+ email:
47
+ - francois@teksol.info
48
+ executables: []
49
+
50
+ extensions: []
51
+
52
+ extra_rdoc_files:
53
+ - History.txt
54
+ - Manifest.txt
55
+ - Benchmarks.txt
56
+ - README.rdoc
57
+ files:
58
+ - History.txt
59
+ - Manifest.txt
60
+ - Benchmarks.txt
61
+ - README.rdoc
62
+ - Rakefile
63
+ - lib/linked_list.rb
64
+ - lib/linked_list/node.rb
65
+ - script/console
66
+ - script/destroy
67
+ - script/generate
68
+ - tasks/benchmark.rake
69
+ - test/test_helper.rb
70
+ - test/test_linked_list.rb
71
+ - test/test_linked_list_node.rb
72
+ has_rdoc: true
73
+ homepage: http://linkedlist.rubyforge.org/
74
+ post_install_message:
75
+ rdoc_options:
76
+ - --main
77
+ - README.rdoc
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: "0"
85
+ version:
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: "0"
91
+ version:
92
+ requirements: []
93
+
94
+ rubyforge_project: linkedlist
95
+ rubygems_version: 1.2.0
96
+ signing_key:
97
+ specification_version: 2
98
+ summary: A simple linked list implementation that follows Ruby's conventions.
99
+ test_files:
100
+ - test/test_helper.rb
101
+ - test/test_linked_list.rb
102
+ - test/test_linked_list_node.rb