hamster 0.1.8 → 0.1.11
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.
- data/README.rdoc +34 -10
- data/lib/hamster.rb +0 -1
- data/lib/hamster/hash.rb +77 -20
- data/lib/hamster/list.rb +189 -52
- data/lib/hamster/set.rb +78 -23
- data/lib/hamster/stack.rb +13 -14
- data/lib/hamster/trie.rb +13 -4
- data/lib/hamster/version.rb +1 -1
- data/spec/hamster/hash/all_spec.rb +53 -0
- data/spec/hamster/hash/any_spec.rb +62 -0
- data/spec/hamster/hash/construction_spec.rb +21 -5
- data/spec/hamster/hash/copying_spec.rb +6 -10
- data/spec/hamster/hash/each_spec.rb +6 -18
- data/spec/hamster/hash/empty_spec.rb +9 -5
- data/spec/hamster/hash/eql_spec.rb +17 -22
- data/spec/hamster/hash/filter_spec.rb +61 -0
- data/spec/hamster/hash/get_spec.rb +24 -12
- data/spec/hamster/hash/has_key_spec.rb +17 -13
- data/spec/hamster/hash/map_spec.rb +66 -0
- data/spec/hamster/hash/none_spec.rb +62 -0
- data/spec/hamster/hash/put_spec.rb +17 -73
- data/spec/hamster/hash/reduce_spec.rb +58 -0
- data/spec/hamster/hash/reject_spec.rb +57 -0
- data/spec/hamster/hash/remove_spec.rb +13 -85
- data/spec/hamster/hash/size_spec.rb +25 -0
- data/spec/hamster/list/cadr_spec.rb +37 -0
- data/spec/hamster/list/construction_spec.rb +46 -6
- data/spec/hamster/list/copying_spec.rb +13 -11
- data/spec/hamster/list/drop_spec.rb +29 -0
- data/spec/hamster/list/drop_while_spec.rb +39 -0
- data/spec/hamster/list/each_spec.rb +24 -24
- data/spec/hamster/list/empty_spec.rb +15 -6
- data/spec/hamster/list/eql_spec.rb +27 -7
- data/spec/hamster/list/filter_spec.rb +51 -0
- data/spec/hamster/list/head_spec.rb +27 -0
- data/spec/hamster/list/include_spec.rb +37 -0
- data/spec/hamster/list/lazy_spec.rb +21 -0
- data/spec/hamster/list/map_spec.rb +21 -19
- data/spec/hamster/list/reduce_spec.rb +27 -15
- data/spec/hamster/list/reject_spec.rb +47 -0
- data/spec/hamster/list/size_spec.rb +31 -0
- data/spec/hamster/list/tail_spec.rb +27 -0
- data/spec/hamster/list/take_spec.rb +29 -0
- data/spec/hamster/list/take_while_spec.rb +45 -0
- data/spec/hamster/set/add_spec.rb +49 -0
- data/spec/hamster/set/all_spec.rb +61 -0
- data/spec/hamster/set/any_spec.rb +61 -0
- data/spec/hamster/set/construction_spec.rb +3 -3
- data/spec/hamster/set/copying_spec.rb +21 -0
- data/spec/hamster/set/each_spec.rb +36 -0
- data/spec/hamster/set/empty_spec.rb +21 -0
- data/spec/hamster/set/eql_spec.rb +31 -0
- data/spec/hamster/set/filter_spec.rb +61 -0
- data/spec/hamster/set/include_spec.rb +29 -0
- data/spec/hamster/set/map_spec.rb +66 -0
- data/spec/hamster/set/none_spec.rb +61 -0
- data/spec/hamster/set/reduce_spec.rb +58 -0
- data/spec/hamster/set/reject_spec.rb +57 -0
- data/spec/hamster/set/remove_spec.rb +45 -0
- data/spec/hamster/set/size_spec.rb +25 -0
- data/spec/hamster/stack/copying_spec.rb +1 -1
- data/spec/hamster/stack/empty_spec.rb +2 -2
- data/spec/hamster/stack/eql_spec.rb +15 -4
- data/spec/hamster/stack/push_spec.rb +6 -26
- data/spec/hamster/trie/remove_spec.rb +117 -0
- metadata +39 -7
- data/TODO +0 -1
- data/spec/hamster/list/accessor_spec.rb +0 -26
- data/spec/hamster/list/car_spec.rb +0 -17
data/lib/hamster/set.rb
CHANGED
@@ -1,31 +1,31 @@
|
|
1
|
+
require 'hamster/trie'
|
2
|
+
|
1
3
|
module Hamster
|
2
4
|
|
3
|
-
|
5
|
+
def self.set(*items)
|
6
|
+
items.reduce(Set.new) { |set, item| set.add(item) }
|
7
|
+
end
|
4
8
|
|
5
|
-
|
6
|
-
items.reduce(self.new) { |set, item| set.add(item) }
|
7
|
-
end
|
9
|
+
class Set
|
8
10
|
|
9
11
|
def initialize(trie = Trie.new)
|
10
12
|
@trie = trie
|
11
13
|
end
|
12
14
|
|
13
|
-
# Returns the number of items in the set.
|
14
|
-
def size
|
15
|
-
@trie.size
|
16
|
-
end
|
17
|
-
|
18
|
-
# Returns <tt>true</tt> if the set contains no items.
|
19
15
|
def empty?
|
20
16
|
@trie.empty?
|
21
17
|
end
|
22
18
|
|
23
|
-
|
19
|
+
def size
|
20
|
+
@trie.size
|
21
|
+
end
|
22
|
+
alias_method :length, :size
|
23
|
+
|
24
24
|
def include?(item)
|
25
25
|
@trie.has_key?(item)
|
26
26
|
end
|
27
|
+
alias_method :member?, :include?
|
27
28
|
|
28
|
-
# Returns a copy of <tt>self</tt> with the given item added. If already exists, returns <tt>self</tt>.
|
29
29
|
def add(item)
|
30
30
|
if include?(item)
|
31
31
|
self
|
@@ -33,36 +33,91 @@ module Hamster
|
|
33
33
|
self.class.new(@trie.put(item, nil))
|
34
34
|
end
|
35
35
|
end
|
36
|
+
alias_method :<<, :add
|
36
37
|
|
37
|
-
# Returns a copy of <tt>self</tt> with the given item removed. If not found, returns <tt>self</tt>.
|
38
38
|
def remove(key)
|
39
|
-
|
40
|
-
if !
|
41
|
-
self.class.new(
|
39
|
+
trie = @trie.remove(key)
|
40
|
+
if !trie.equal?(@trie)
|
41
|
+
self.class.new(trie)
|
42
42
|
else
|
43
43
|
self
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
# Calls <tt>block</tt> once for each item in the set, passing the item as the only parameter.
|
48
|
-
# Returns <tt>self</tt>
|
49
47
|
def each
|
50
48
|
block_given? or return enum_for(__method__)
|
51
|
-
@trie.each { |entry| yield
|
49
|
+
@trie.each { |entry| yield(entry.key) }
|
52
50
|
self
|
53
51
|
end
|
54
52
|
|
55
|
-
|
53
|
+
def map
|
54
|
+
block_given? or return enum_for(:each)
|
55
|
+
if empty?
|
56
|
+
self
|
57
|
+
else
|
58
|
+
self.class.new(@trie.reduce(Trie.new) { |trie, entry| trie.put(yield(entry.key), nil) })
|
59
|
+
end
|
60
|
+
end
|
61
|
+
alias_method :collect, :map
|
62
|
+
|
63
|
+
def reduce(memo)
|
64
|
+
block_given? or return memo
|
65
|
+
@trie.reduce(memo) { |memo, entry| yield(memo, entry.key) }
|
66
|
+
end
|
67
|
+
alias_method :inject, :reduce
|
68
|
+
|
69
|
+
def filter
|
70
|
+
block_given? or return enum_for(__method__)
|
71
|
+
trie = @trie.filter { |entry| yield(entry.key) }
|
72
|
+
if !trie.equal?(@trie)
|
73
|
+
self.class.new(trie)
|
74
|
+
else
|
75
|
+
self
|
76
|
+
end
|
77
|
+
end
|
78
|
+
alias_method :select, :filter
|
79
|
+
|
80
|
+
def reject
|
81
|
+
block_given? or return enum_for(__method__)
|
82
|
+
select { |item| !yield(item) }
|
83
|
+
end
|
84
|
+
|
85
|
+
def any?
|
86
|
+
if block_given?
|
87
|
+
each { |item| return true if yield(item) }
|
88
|
+
else
|
89
|
+
each { |item| return true if item }
|
90
|
+
end
|
91
|
+
false
|
92
|
+
end
|
93
|
+
|
94
|
+
def all?
|
95
|
+
if block_given?
|
96
|
+
each { |item| return false unless yield(item) }
|
97
|
+
else
|
98
|
+
each { |item| return false unless item }
|
99
|
+
end
|
100
|
+
true
|
101
|
+
end
|
102
|
+
|
103
|
+
def none?
|
104
|
+
if block_given?
|
105
|
+
each { |item| return false if yield(item) }
|
106
|
+
else
|
107
|
+
each { |item| return false if item }
|
108
|
+
end
|
109
|
+
true
|
110
|
+
end
|
111
|
+
|
56
112
|
def eql?(other)
|
57
113
|
other.is_a?(self.class) && @trie.eql?(other.instance_eval{@trie})
|
58
114
|
end
|
59
|
-
|
115
|
+
alias_method :==, :eql?
|
60
116
|
|
61
|
-
# Returns <tt>self</tt>
|
62
117
|
def dup
|
63
118
|
self
|
64
119
|
end
|
65
|
-
|
120
|
+
alias_method :clone, :dup
|
66
121
|
|
67
122
|
end
|
68
123
|
|
data/lib/hamster/stack.rb
CHANGED
@@ -1,52 +1,51 @@
|
|
1
|
+
require 'hamster/list'
|
2
|
+
|
1
3
|
module Hamster
|
2
4
|
|
5
|
+
def self.stack
|
6
|
+
Stack.new
|
7
|
+
end
|
8
|
+
|
3
9
|
class Stack
|
4
10
|
|
5
|
-
def initialize(list =
|
11
|
+
def initialize(list = Hamster.list)
|
6
12
|
@list = list
|
7
13
|
end
|
8
14
|
|
9
|
-
# Returns <tt>true</tt> if the stack contains no items.
|
10
15
|
def empty?
|
11
16
|
@list.empty?
|
12
17
|
end
|
13
18
|
|
14
|
-
# Returns the number of items on the stack.
|
15
19
|
def size
|
16
20
|
@list.size
|
17
21
|
end
|
18
22
|
|
19
|
-
# Returns the item at the top of the stack.
|
20
23
|
def top
|
21
|
-
@list.
|
24
|
+
@list.head
|
22
25
|
end
|
23
26
|
|
24
|
-
# Returns a copy of <tt>self</tt> with the given item as the new top
|
25
27
|
def push(item)
|
26
28
|
self.class.new(@list.cons(item))
|
27
29
|
end
|
28
30
|
|
29
|
-
# Returns a copy of <tt>self</tt> without the top item.
|
30
31
|
def pop
|
31
|
-
|
32
|
-
if !
|
33
|
-
self.class.new(
|
32
|
+
list = @list.tail
|
33
|
+
if !list.equal?(@list)
|
34
|
+
self.class.new(list)
|
34
35
|
else
|
35
36
|
self
|
36
37
|
end
|
37
38
|
end
|
38
39
|
|
39
|
-
# Returns <tt>true</tt> if . <tt>eql?</tt> is synonymous with <tt>==</tt>
|
40
40
|
def eql?(other)
|
41
41
|
other.is_a?(self.class) && @list.eql?(other.instance_eval{@list})
|
42
42
|
end
|
43
|
-
|
43
|
+
alias_method :==, :eql?
|
44
44
|
|
45
|
-
# Returns <tt>self</tt>
|
46
45
|
def dup
|
47
46
|
self
|
48
47
|
end
|
49
|
-
|
48
|
+
alias_method :clone, :dup
|
50
49
|
|
51
50
|
end
|
52
51
|
|
data/lib/hamster/trie.rb
CHANGED
@@ -27,12 +27,21 @@ module Hamster
|
|
27
27
|
|
28
28
|
# Calls <tt>block</tt> once for each entry in the trie, passing the key-value pair as parameters.
|
29
29
|
def each
|
30
|
-
@entries.each { |entry| yield
|
30
|
+
@entries.each { |entry| yield(entry) if entry }
|
31
31
|
@children.each do |child|
|
32
|
-
child.each { |entry| yield
|
32
|
+
child.each { |entry| yield(entry) } if child
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
+
def reduce(memo)
|
37
|
+
each { |entry| memo = yield(memo, entry) }
|
38
|
+
memo
|
39
|
+
end
|
40
|
+
|
41
|
+
def filter
|
42
|
+
reduce(self) { |trie, entry| yield(entry) ? trie : trie.remove(entry.key) }
|
43
|
+
end
|
44
|
+
|
36
45
|
# Returns a copy of <tt>self</tt> with the given value associated with the key.
|
37
46
|
def put(key, value)
|
38
47
|
index = index_for(key)
|
@@ -86,7 +95,7 @@ module Hamster
|
|
86
95
|
end
|
87
96
|
true
|
88
97
|
end
|
89
|
-
|
98
|
+
alias_method :==, :eql?
|
90
99
|
|
91
100
|
protected
|
92
101
|
|
@@ -120,7 +129,7 @@ module Hamster
|
|
120
129
|
|
121
130
|
# Returns a replacement instance after removing the specified entry. If empty, returns <tt>nil</tt>
|
122
131
|
def remove_at(index = @entries.index { |e| e })
|
123
|
-
yield
|
132
|
+
yield(@entries[index]) if block_given?
|
124
133
|
if size > 1
|
125
134
|
entries = @entries.dup
|
126
135
|
child = @children[index]
|
data/lib/hamster/version.rb
CHANGED
@@ -0,0 +1,53 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe Hamster::Hash do
|
4
|
+
|
5
|
+
describe "#all?" do
|
6
|
+
|
7
|
+
describe "when empty" do
|
8
|
+
|
9
|
+
before do
|
10
|
+
@hash = Hamster.hash
|
11
|
+
end
|
12
|
+
|
13
|
+
it "with a block returns true" do
|
14
|
+
@hash.all? {}.should be_true
|
15
|
+
end
|
16
|
+
|
17
|
+
it "with no block returns true" do
|
18
|
+
@hash.all?.should be_true
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "when not empty" do
|
24
|
+
|
25
|
+
before do
|
26
|
+
@hash = Hamster.hash("A" => "aye", "B" => "bee", "C" => "see")
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "with a block" do
|
30
|
+
|
31
|
+
it "returns true if the block always returns true" do
|
32
|
+
@hash.all? { |item| true }.should be_true
|
33
|
+
end
|
34
|
+
|
35
|
+
it "returns false if the block ever returns false" do
|
36
|
+
@hash.all? { |key, value| key == "D" || value == "dee" }.should be_false
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "with no block" do
|
42
|
+
|
43
|
+
it "returns true" do
|
44
|
+
@hash.all?.should be_true
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe Hamster::Hash do
|
4
|
+
|
5
|
+
describe "#any?" do
|
6
|
+
|
7
|
+
describe "when empty" do
|
8
|
+
|
9
|
+
before do
|
10
|
+
@hash = Hamster.hash
|
11
|
+
end
|
12
|
+
|
13
|
+
it "with a block returns false" do
|
14
|
+
@hash.any? {}.should be_false
|
15
|
+
end
|
16
|
+
|
17
|
+
it "with no block returns false" do
|
18
|
+
@hash.any?.should be_false
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "when not empty" do
|
24
|
+
|
25
|
+
before do
|
26
|
+
@hash = Hamster.hash("A" => "aye", "B" => "bee", "C" => "see", nil => "NIL")
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "with a block" do
|
30
|
+
|
31
|
+
[
|
32
|
+
["A", "aye"],
|
33
|
+
["B", "bee"],
|
34
|
+
["C", "see"],
|
35
|
+
[nil, "NIL"],
|
36
|
+
].each do |pair|
|
37
|
+
|
38
|
+
it "returns true if the block ever returns true (#{pair.inspect})" do
|
39
|
+
@hash.any? { |key, value| key == pair.first && value == pair.last }.should be_true
|
40
|
+
end
|
41
|
+
|
42
|
+
it "returns false if the block always returns false" do
|
43
|
+
@hash.any? { |key, value| key == "D" && value == "dee" }.should be_false
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "with no block" do
|
51
|
+
|
52
|
+
it "returns true" do
|
53
|
+
@hash.any?.should be_true
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -2,14 +2,30 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
2
2
|
|
3
3
|
describe Hamster::Hash do
|
4
4
|
|
5
|
-
describe ".
|
5
|
+
describe ".hash" do
|
6
|
+
|
7
|
+
describe "with nothing" do
|
8
|
+
|
9
|
+
before do
|
10
|
+
@hash = Hamster.hash
|
11
|
+
end
|
12
|
+
|
13
|
+
it "returns an empty hash" do
|
14
|
+
@hash.should be_empty
|
15
|
+
end
|
6
16
|
|
7
|
-
before do
|
8
|
-
@hash = Hamster::Hash["A" => "aye", "B" => "bee", "C" => "see"]
|
9
17
|
end
|
10
18
|
|
11
|
-
|
12
|
-
|
19
|
+
describe "with an implicit hash" do
|
20
|
+
|
21
|
+
before do
|
22
|
+
@hash = Hamster.hash("A" => "aye", "B" => "bee", "C" => "see")
|
23
|
+
end
|
24
|
+
|
25
|
+
it "is equivalent to repeatedly using #put" do
|
26
|
+
@hash.should == Hamster.hash.put("A", "aye").put("B", "bee").put("C", "see")
|
27
|
+
end
|
28
|
+
|
13
29
|
end
|
14
30
|
|
15
31
|
end
|
@@ -3,21 +3,17 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
3
3
|
describe Hamster::Hash do
|
4
4
|
|
5
5
|
before do
|
6
|
-
@hash = Hamster
|
6
|
+
@hash = Hamster.hash("A" => "aye", "B" => "bee", "C" => "see")
|
7
7
|
end
|
8
8
|
|
9
|
-
|
9
|
+
[:dup, :clone].each do |method|
|
10
10
|
|
11
|
-
|
12
|
-
@hash.dup.should equal(@hash)
|
13
|
-
end
|
14
|
-
|
15
|
-
end
|
11
|
+
describe "##{method}" do
|
16
12
|
|
17
|
-
|
13
|
+
it "returns self" do
|
14
|
+
@hash.send(method).should equal(@hash)
|
15
|
+
end
|
18
16
|
|
19
|
-
it "returns self" do
|
20
|
-
@hash.clone.should equal(@hash)
|
21
17
|
end
|
22
18
|
|
23
19
|
end
|
@@ -5,11 +5,7 @@ describe Hamster::Hash do
|
|
5
5
|
describe "#each" do
|
6
6
|
|
7
7
|
before do
|
8
|
-
@hash = Hamster
|
9
|
-
@expected_pairs = { "A" => "aye", "B" => "bee", "C" => "sea" }
|
10
|
-
@expected_pairs.each do |key, value|
|
11
|
-
@hash = @hash.put(key, value)
|
12
|
-
end
|
8
|
+
@hash = Hamster.hash("A" => "aye", "B" => "bee", "C" => "see")
|
13
9
|
end
|
14
10
|
|
15
11
|
describe "with a block (internal iteration)" do
|
@@ -18,26 +14,18 @@ describe Hamster::Hash do
|
|
18
14
|
@hash.each {}.should equal(@hash)
|
19
15
|
end
|
20
16
|
|
21
|
-
it "yields all key
|
17
|
+
it "yields all key/value pairs" do
|
22
18
|
actual_pairs = {}
|
23
|
-
@hash.each
|
24
|
-
|
25
|
-
end
|
26
|
-
actual_pairs.should == @expected_pairs
|
19
|
+
@hash.each { |key, value| actual_pairs[key] = value }
|
20
|
+
actual_pairs.should == {"A" => "aye", "B" => "bee", "C" => "see"}
|
27
21
|
end
|
28
22
|
|
29
23
|
end
|
30
24
|
|
31
25
|
describe "with no block (external iteration)" do
|
32
26
|
|
33
|
-
it "returns an enumerator over all key
|
34
|
-
|
35
|
-
enum = @hash.each
|
36
|
-
loop do
|
37
|
-
key, value = enum.next
|
38
|
-
actual_pairs[key] = value
|
39
|
-
end
|
40
|
-
actual_pairs.should == @expected_pairs
|
27
|
+
it "returns an enumerator over all key/value pairs" do
|
28
|
+
Hash[*@hash.each.to_a.flatten].should == {"A" => "aye", "B" => "bee", "C" => "see"}
|
41
29
|
end
|
42
30
|
|
43
31
|
end
|