hamster 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +8 -0
- data/README.rdoc +13 -7
- data/lib/hamster/trie.rb +15 -15
- data/lib/hamster/version.rb +1 -1
- data/spec/hamster/trie/each_spec.rb +51 -0
- data/spec/hamster/trie/empty_spec.rb +22 -0
- data/spec/hamster/trie/enumerable_spec.rb +13 -0
- data/spec/hamster/trie/get_spec.rb +26 -0
- data/spec/hamster/trie/has_key_spec.rb +25 -0
- data/spec/hamster/trie/put_spec.rb +97 -0
- data/spec/hamster/trie/remove_spec.rb +115 -0
- metadata +9 -3
- data/spec/hamster/trie_spec.rb +0 -267
data/History.rdoc
CHANGED
data/README.rdoc
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
= Hamster
|
2
2
|
|
3
|
-
Hash Array Mapped Tries (HAMT) for Ruby (
|
3
|
+
Hash Array Mapped Tries (HAMT) for Ruby (see http://lamp.epfl.ch/papers/idealhashtrees.pdf).
|
4
4
|
|
5
5
|
Why do you care?
|
6
6
|
|
7
|
-
HAMTs are hash tables with one really neat property: their structure enables you to perform very efficient
|
7
|
+
HAMTs are hash tables with one really neat property: their structure enables you to perform very efficient copy-on-write operations. For example:
|
8
8
|
|
9
9
|
trie = Hamster::Trie.new
|
10
10
|
|
11
11
|
trie.put("Name", "Simon")
|
12
|
-
trie.get("Name")
|
12
|
+
trie.get("Name") # => nil
|
13
13
|
|
14
14
|
Huh? That's not much use!
|
15
15
|
|
@@ -18,7 +18,7 @@ Remember, each instance of a trie is immutable. #put creates an efficient copy c
|
|
18
18
|
trie = Hamster::Trie.new
|
19
19
|
|
20
20
|
trie = trie.put("Name", "Simon")
|
21
|
-
trie.get("Name")
|
21
|
+
trie.get("Name") # => "Simon"
|
22
22
|
|
23
23
|
The same goes for remove:
|
24
24
|
|
@@ -27,12 +27,18 @@ The same goes for remove:
|
|
27
27
|
trie = trie.put("Name", "Simon")
|
28
28
|
trie = trie.put("Gender", "Male")
|
29
29
|
trie = trie.remove("Name")
|
30
|
-
trie.get("Name")
|
31
|
-
trie.get("Gender")
|
30
|
+
trie.get("Name") # => nil
|
31
|
+
trie.get("Gender") # => "Male"
|
32
32
|
|
33
33
|
So tell me again why I care?
|
34
34
|
|
35
|
-
As mentioned earlier, HAMTs perform a copy whenever they are modified
|
35
|
+
As mentioned earlier, HAMTs perform a copy whenever they are modified meaning there is never any chance that two threads could be modifying the same instance at any one time. And, because they are very efficient copies, you don't need to worry about using up gobs of heap space in the process.
|
36
|
+
|
37
|
+
Thats nice but I don't really have multi-threading issues.
|
38
|
+
|
39
|
+
OK, how about transactional memory:
|
40
|
+
|
41
|
+
Need an example
|
36
42
|
|
37
43
|
So what's the downside?
|
38
44
|
|
data/lib/hamster/trie.rb
CHANGED
@@ -77,38 +77,38 @@ module Hamster
|
|
77
77
|
|
78
78
|
# Returns a copy of <tt>self</tt> with the given key/value pair removed. If not found, returns <tt>self</tt>.
|
79
79
|
def remove(key)
|
80
|
+
remove!(key) || self
|
81
|
+
end
|
82
|
+
|
83
|
+
protected
|
84
|
+
|
85
|
+
def put!(key, value)
|
86
|
+
@entries[index_for(key)] = Entry.new(key, value)
|
87
|
+
self
|
88
|
+
end
|
89
|
+
|
90
|
+
def remove!(key)
|
80
91
|
index = index_for(key)
|
81
92
|
entry = @entries[index]
|
82
93
|
child = @children[index]
|
83
94
|
if entry && entry.has_key?(key)
|
84
|
-
# TODO: Probably should "pull up" a child entry
|
85
95
|
entries = @entries.dup
|
86
96
|
entries[index] = nil
|
87
|
-
self.class.new(@significant_bits, entries, @children)
|
97
|
+
self.class.new(@significant_bits, entries, @children) unless size == 1
|
88
98
|
elsif child
|
89
|
-
new_child = child.remove(key)
|
99
|
+
new_child = child.remove!(key)
|
90
100
|
if new_child != child
|
91
|
-
# TODO: Probably should "prune" empty children
|
92
101
|
children = @children.dup
|
93
102
|
children[index] = new_child
|
94
103
|
self.class.new(@significant_bits, @entries, children)
|
95
104
|
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
protected
|
100
|
-
|
101
|
-
def put!(key, value)
|
102
|
-
@entries[index_for(key)] = Entry.new(key, value)
|
103
|
-
self
|
105
|
+
end
|
104
106
|
end
|
105
107
|
|
106
108
|
private
|
107
109
|
|
108
110
|
def index_for(key)
|
109
|
-
key.hash.abs & 31
|
110
|
-
# puts "#{key}##{key.object_id}:#{key.hash}"
|
111
|
-
# (key.hash.abs >> @significant_bits) & 31
|
111
|
+
(key.hash.abs >> @significant_bits) & 31
|
112
112
|
end
|
113
113
|
|
114
114
|
end
|
data/lib/hamster/version.rb
CHANGED
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
module Hamster
|
4
|
+
|
5
|
+
describe Trie do
|
6
|
+
|
7
|
+
describe "#each" do
|
8
|
+
|
9
|
+
before do
|
10
|
+
@trie = Trie.new
|
11
|
+
@expected_pairs = { "A" => "aye", "B" => "bee", "C" => "sea" }
|
12
|
+
@expected_pairs.each do |key, value|
|
13
|
+
@trie = @trie.put(key, value)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "with a block (internal iteration)" do
|
18
|
+
|
19
|
+
it "returns self" do
|
20
|
+
@trie.each {}.should == @trie
|
21
|
+
end
|
22
|
+
|
23
|
+
it "yields all key value pairs" do
|
24
|
+
actual_pairs = {}
|
25
|
+
@trie.each do |key, value|
|
26
|
+
actual_pairs[key] = value
|
27
|
+
end
|
28
|
+
actual_pairs.should == @expected_pairs
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "with no block (external iteration)" do
|
34
|
+
|
35
|
+
it "returns an enumerator over all key value pairs" do
|
36
|
+
actual_pairs = {}
|
37
|
+
enum = @trie.each
|
38
|
+
loop do
|
39
|
+
key, value = enum.next
|
40
|
+
actual_pairs[key] = value
|
41
|
+
end
|
42
|
+
actual_pairs.should == @expected_pairs
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
module Hamster
|
4
|
+
|
5
|
+
describe Trie do
|
6
|
+
|
7
|
+
describe "#empty?" do
|
8
|
+
|
9
|
+
it "initially returns true" do
|
10
|
+
Trie.new.should be_empty
|
11
|
+
end
|
12
|
+
|
13
|
+
it "returns false once items have been added" do
|
14
|
+
trie = Trie.new.put("A", "aye")
|
15
|
+
trie.should_not be_empty
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
module Hamster
|
4
|
+
|
5
|
+
describe Trie do
|
6
|
+
|
7
|
+
describe "#get" do
|
8
|
+
|
9
|
+
before do
|
10
|
+
@trie = Trie.new
|
11
|
+
@trie = @trie.put("A", "aye")
|
12
|
+
end
|
13
|
+
|
14
|
+
it "returns the value for an existing key" do
|
15
|
+
@trie.get("A").should == "aye"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "returns nil for a non-existing key" do
|
19
|
+
@trie.get("B").should be_nil
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
module Hamster
|
4
|
+
|
5
|
+
describe Trie do
|
6
|
+
|
7
|
+
describe "#has_key?" do
|
8
|
+
|
9
|
+
before do
|
10
|
+
@trie = Trie.new.put("A", "aye")
|
11
|
+
end
|
12
|
+
|
13
|
+
it "returns true for an existing key" do
|
14
|
+
@trie.has_key?("A").should be_true
|
15
|
+
end
|
16
|
+
|
17
|
+
it "returns false for a non-existing key" do
|
18
|
+
@trie.has_key?("B").should be_false
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
module Hamster
|
4
|
+
|
5
|
+
describe Trie do
|
6
|
+
|
7
|
+
describe "#put" do
|
8
|
+
|
9
|
+
describe "with a key/value pair that already exists" do
|
10
|
+
|
11
|
+
before do
|
12
|
+
@original = Trie.new.put("A", "aye").put("B", "bee")
|
13
|
+
@copy = @original.put("A", "yes")
|
14
|
+
end
|
15
|
+
|
16
|
+
it "returns a modified copy" do
|
17
|
+
@copy.should_not === @original
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "the original" do
|
21
|
+
|
22
|
+
it "still has the original key/value pairs" do
|
23
|
+
@original.get("A").should == "aye"
|
24
|
+
@original.get("B").should == "bee"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "still has the original size" do
|
28
|
+
@original.size.should == 2
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "the modified copy" do
|
34
|
+
|
35
|
+
it "has the new key/value pairs" do
|
36
|
+
@copy.get("A").should == "yes"
|
37
|
+
@copy.get("B").should == "bee"
|
38
|
+
end
|
39
|
+
|
40
|
+
it "has the original size" do
|
41
|
+
@copy.size == 2
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "with a key/value pair that doesn't exist" do
|
49
|
+
|
50
|
+
before do
|
51
|
+
@original = Trie.new.put("A", "aye")
|
52
|
+
@copy = @original.put("B", "bee")
|
53
|
+
end
|
54
|
+
|
55
|
+
it "returns a modified copy" do
|
56
|
+
@copy.should_not === @original
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "the original" do
|
60
|
+
|
61
|
+
it "still has the original key/value pairs" do
|
62
|
+
@original.get("A").should == "aye"
|
63
|
+
end
|
64
|
+
|
65
|
+
it "doesn't contain the new key/value pair" do
|
66
|
+
@original.has_key?("B").should be_false
|
67
|
+
end
|
68
|
+
|
69
|
+
it "still has the original size" do
|
70
|
+
@original.size.should == 1
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "the modified copy" do
|
76
|
+
|
77
|
+
it "has the original key/value pairs" do
|
78
|
+
@copy.get("A").should == "aye"
|
79
|
+
end
|
80
|
+
|
81
|
+
it "has the new key/value pair" do
|
82
|
+
@copy.get("B").should == "bee"
|
83
|
+
end
|
84
|
+
|
85
|
+
it "size is increased by one" do
|
86
|
+
@copy.size.should == 2
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
module Hamster
|
4
|
+
|
5
|
+
describe Trie do
|
6
|
+
|
7
|
+
describe "#remove" do
|
8
|
+
|
9
|
+
describe "with an existing key" do
|
10
|
+
|
11
|
+
before do
|
12
|
+
@original = Trie.new.put("A", "aye").put("B", "bee")
|
13
|
+
@copy = @original.remove("A")
|
14
|
+
end
|
15
|
+
|
16
|
+
it "returns a modified copy" do
|
17
|
+
@copy.should_not === @original
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "the original" do
|
21
|
+
|
22
|
+
it "still has the original key/value pairs" do
|
23
|
+
@original.get("A").should == "aye"
|
24
|
+
@original.get("B").should == "bee"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "still has the original size" do
|
28
|
+
@original.size.should == 2
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "the modified copy" do
|
34
|
+
|
35
|
+
it "has all but the removed original key/value pairs" do
|
36
|
+
@copy.get("B").should == "bee"
|
37
|
+
end
|
38
|
+
|
39
|
+
it "doesn't have the removed key" do
|
40
|
+
@copy.has_key?("A").should be_false
|
41
|
+
end
|
42
|
+
|
43
|
+
it "has a size one less than the original" do
|
44
|
+
@copy.size.should == 1
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "with non-existing keys" do
|
52
|
+
|
53
|
+
before do
|
54
|
+
@original = Trie.new.put("A", "aye")
|
55
|
+
@copy = @original.remove("missing")
|
56
|
+
end
|
57
|
+
|
58
|
+
it "returns self" do
|
59
|
+
@copy.should === @original
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "the original" do
|
63
|
+
|
64
|
+
it "still has the original key/value pairs" do
|
65
|
+
@original.get("A").should == "aye"
|
66
|
+
end
|
67
|
+
|
68
|
+
it "still has the original size" do
|
69
|
+
@original.size.should == 1
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "with keys of the same hash value" do
|
77
|
+
|
78
|
+
class Key
|
79
|
+
def hash; 1; end
|
80
|
+
end
|
81
|
+
|
82
|
+
def number_of_tries
|
83
|
+
ObjectSpace.garbage_collect
|
84
|
+
ObjectSpace.each_object(Trie) {}
|
85
|
+
end
|
86
|
+
|
87
|
+
before do
|
88
|
+
@a = Key.new
|
89
|
+
@b = Key.new
|
90
|
+
@original = Trie.new.put(@a, "aye").put(@b, "bee")
|
91
|
+
end
|
92
|
+
|
93
|
+
it "no longer provides access to the removed key" do
|
94
|
+
copy = @original.remove(@b)
|
95
|
+
copy.has_key?(@b).should be_false
|
96
|
+
end
|
97
|
+
|
98
|
+
it "provides access to the remaining keys" do
|
99
|
+
copy = @original.remove(@a)
|
100
|
+
copy.get(@b).should == "bee"
|
101
|
+
end
|
102
|
+
|
103
|
+
it "cleans up empty tries" do
|
104
|
+
number_of_tries_before = number_of_tries
|
105
|
+
copy = @original.remove(@b)
|
106
|
+
number_of_tries.should == number_of_tries_before + 1
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hamster
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Simon Harris
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-10-
|
12
|
+
date: 2009-10-25 00:00:00 +11:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -29,7 +29,13 @@ files:
|
|
29
29
|
- lib/hamster/trie.rb
|
30
30
|
- lib/hamster/version.rb
|
31
31
|
- lib/hamster.rb
|
32
|
-
- spec/hamster/
|
32
|
+
- spec/hamster/trie/each_spec.rb
|
33
|
+
- spec/hamster/trie/empty_spec.rb
|
34
|
+
- spec/hamster/trie/enumerable_spec.rb
|
35
|
+
- spec/hamster/trie/get_spec.rb
|
36
|
+
- spec/hamster/trie/has_key_spec.rb
|
37
|
+
- spec/hamster/trie/put_spec.rb
|
38
|
+
- spec/hamster/trie/remove_spec.rb
|
33
39
|
- spec/spec.opts
|
34
40
|
- spec/spec_helper.rb
|
35
41
|
- tasks/spec.rb
|
data/spec/hamster/trie_spec.rb
DELETED
@@ -1,267 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
-
|
3
|
-
module Hamster
|
4
|
-
|
5
|
-
describe Trie do
|
6
|
-
|
7
|
-
before do
|
8
|
-
@expected_pairs = {}
|
9
|
-
@trie = Trie.new
|
10
|
-
("A".."Z").each do |letter|
|
11
|
-
@expected_pairs.store(letter, letter.downcase)
|
12
|
-
@trie = @trie.put(letter, letter.downcase)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
it "is Enumerable" do
|
17
|
-
Trie.is_a?(Enumerable)
|
18
|
-
end
|
19
|
-
|
20
|
-
describe "#empty?" do
|
21
|
-
|
22
|
-
it "initially returns true" do
|
23
|
-
Trie.new.should be_empty
|
24
|
-
end
|
25
|
-
|
26
|
-
it "returns false once items have been added" do
|
27
|
-
@trie.should_not be_empty
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
describe "#each" do
|
33
|
-
|
34
|
-
describe "with a block (internal iteration)" do
|
35
|
-
|
36
|
-
it "returns self" do
|
37
|
-
@trie.each {}.should == @trie
|
38
|
-
|
39
|
-
end
|
40
|
-
|
41
|
-
it "yields all key value pairs" do
|
42
|
-
actual_pairs = {}
|
43
|
-
@trie.each do |key, value|
|
44
|
-
actual_pairs[key] = value
|
45
|
-
end
|
46
|
-
actual_pairs.should == @expected_pairs
|
47
|
-
end
|
48
|
-
|
49
|
-
end
|
50
|
-
|
51
|
-
describe "with no block (external iteration)" do
|
52
|
-
|
53
|
-
it "returns an enumerator over all key value pairs" do
|
54
|
-
actual_pairs = {}
|
55
|
-
enum = @trie.each
|
56
|
-
loop do
|
57
|
-
key, value = enum.next
|
58
|
-
actual_pairs[key] = value
|
59
|
-
end
|
60
|
-
actual_pairs.should == @expected_pairs
|
61
|
-
end
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
end
|
66
|
-
|
67
|
-
describe "#get" do
|
68
|
-
|
69
|
-
it "returns values associated with existing keys" do
|
70
|
-
@expected_pairs.each do |key, value|
|
71
|
-
@trie.get(key).should == value
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
it "returns nil for non-existing" do
|
76
|
-
@trie.get("missing").should be_nil
|
77
|
-
end
|
78
|
-
|
79
|
-
end
|
80
|
-
|
81
|
-
describe "#has_key?" do
|
82
|
-
|
83
|
-
it "returns true for existing keys" do
|
84
|
-
@expected_pairs.each_key do |key|
|
85
|
-
@trie.has_key?(key).should be_true
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
it "returns false for non-existing keys" do
|
90
|
-
@trie.has_key?("missing").should be_false
|
91
|
-
end
|
92
|
-
|
93
|
-
end
|
94
|
-
|
95
|
-
describe "#put" do
|
96
|
-
|
97
|
-
describe "with key/value pairs that already exists" do
|
98
|
-
|
99
|
-
before do
|
100
|
-
@copy = @trie.put("J", "jay")
|
101
|
-
end
|
102
|
-
|
103
|
-
it "returns a modified copy" do
|
104
|
-
@copy.should_not === @trie
|
105
|
-
end
|
106
|
-
|
107
|
-
describe "the original" do
|
108
|
-
|
109
|
-
it "still has the original key/value pairs" do
|
110
|
-
@expected_pairs.each do |key, value|
|
111
|
-
@trie.get(key).should == value
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
it "still has the original size" do
|
116
|
-
@trie.size.should == @expected_pairs.size
|
117
|
-
end
|
118
|
-
|
119
|
-
end
|
120
|
-
|
121
|
-
describe "the modified copy" do
|
122
|
-
|
123
|
-
it "has the new key/value pair" do
|
124
|
-
@copy.get("J").should == "jay"
|
125
|
-
end
|
126
|
-
|
127
|
-
it "has the original size" do
|
128
|
-
@trie.size.should == @expected_pairs.size
|
129
|
-
end
|
130
|
-
|
131
|
-
end
|
132
|
-
|
133
|
-
end
|
134
|
-
|
135
|
-
describe "with key/value pairs that don't exist"
|
136
|
-
|
137
|
-
before do
|
138
|
-
@copy = @trie.put("missing", "in action")
|
139
|
-
end
|
140
|
-
|
141
|
-
it "returns a modified copy" do
|
142
|
-
@copy.should_not === @trie
|
143
|
-
end
|
144
|
-
|
145
|
-
describe "the original" do
|
146
|
-
|
147
|
-
it "still has the original key/value pairs" do
|
148
|
-
@expected_pairs.each do |key, value|
|
149
|
-
@trie.get(key).should == value
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
it "doesn't contain the new key/value pair" do
|
154
|
-
@trie.has_key?("missing").should be_false
|
155
|
-
end
|
156
|
-
|
157
|
-
it "still has the original size" do
|
158
|
-
@trie.size.should == @expected_pairs.size
|
159
|
-
end
|
160
|
-
|
161
|
-
end
|
162
|
-
|
163
|
-
describe "the modified copy" do
|
164
|
-
|
165
|
-
it "returns values associated with existing keys" do
|
166
|
-
@expected_pairs.each do |key, value|
|
167
|
-
@copy.get(key).should == value
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
it "has the new key/value pair" do
|
172
|
-
@copy.get("missing").should == "in action"
|
173
|
-
end
|
174
|
-
|
175
|
-
it "size is increased by 1" do
|
176
|
-
@copy.size.should == @expected_pairs.size + 1
|
177
|
-
end
|
178
|
-
|
179
|
-
end
|
180
|
-
|
181
|
-
end
|
182
|
-
|
183
|
-
describe "#remove" do
|
184
|
-
|
185
|
-
it "can be used successively to remove all key/value pairs" do
|
186
|
-
@expected_pairs.each do |key, value|
|
187
|
-
@trie = @trie.remove(key)
|
188
|
-
end
|
189
|
-
@trie.should be_empty
|
190
|
-
end
|
191
|
-
|
192
|
-
describe "with existing keys" do
|
193
|
-
|
194
|
-
before do
|
195
|
-
@copy = @trie.remove("J")
|
196
|
-
end
|
197
|
-
|
198
|
-
it "returns a modified copy" do
|
199
|
-
@copy.should_not === @trie
|
200
|
-
end
|
201
|
-
|
202
|
-
describe "the original" do
|
203
|
-
|
204
|
-
it "still has the original key/value pairs" do
|
205
|
-
@expected_pairs.each do |key, value|
|
206
|
-
@trie.get(key).should == value
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
it "still has the original size" do
|
211
|
-
@trie.size.should == @expected_pairs.size
|
212
|
-
end
|
213
|
-
|
214
|
-
end
|
215
|
-
|
216
|
-
describe "the modified copy" do
|
217
|
-
|
218
|
-
it "doesn't have the removed key" do
|
219
|
-
@copy.has_key?("J").should be_false
|
220
|
-
end
|
221
|
-
|
222
|
-
it "returns values associated with all but the removed key" do
|
223
|
-
@expected_pairs.each do |key, value|
|
224
|
-
next if key == "J"
|
225
|
-
@copy.get(key).should == value
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
it "has one less than the original" do
|
230
|
-
@copy.size.should == @expected_pairs.size - 1
|
231
|
-
end
|
232
|
-
|
233
|
-
end
|
234
|
-
|
235
|
-
end
|
236
|
-
|
237
|
-
describe "with non-existing keys" do
|
238
|
-
|
239
|
-
before do
|
240
|
-
@copy = @trie.remove("missing")
|
241
|
-
end
|
242
|
-
|
243
|
-
it "returns self" do
|
244
|
-
@copy.should === @trie
|
245
|
-
end
|
246
|
-
|
247
|
-
describe "the original" do
|
248
|
-
|
249
|
-
it "returns values associated with existing keys" do
|
250
|
-
@expected_pairs.each do |key, value|
|
251
|
-
@trie.get(key).should == value
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
it "has the original size" do
|
256
|
-
@trie.size.should == @expected_pairs.size
|
257
|
-
end
|
258
|
-
|
259
|
-
end
|
260
|
-
|
261
|
-
end
|
262
|
-
|
263
|
-
end
|
264
|
-
|
265
|
-
end
|
266
|
-
|
267
|
-
end
|