hamster 0.1.13 → 0.1.14
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/History.rdoc +14 -0
- data/README.rdoc +2 -2
- data/lib/hamster/hash.rb +10 -9
- data/lib/hamster/list.rb +96 -64
- data/lib/hamster/set.rb +12 -5
- data/lib/hamster/version.rb +1 -1
- data/spec/hamster/hash/all_spec.rb +1 -1
- data/spec/hamster/hash/eql_spec.rb +42 -13
- data/spec/hamster/hash/filter_spec.rb +1 -1
- data/spec/hamster/hash/reduce_spec.rb +1 -1
- data/spec/hamster/hash/reject_spec.rb +31 -27
- data/spec/hamster/list/all_spec.rb +73 -0
- data/spec/hamster/list/any_spec.rb +77 -0
- data/spec/hamster/list/cadr_spec.rb +4 -2
- data/spec/hamster/list/cons_spec.rb +6 -4
- data/spec/hamster/list/copying_spec.rb +4 -2
- data/spec/hamster/list/drop_spec.rb +16 -2
- data/spec/hamster/list/drop_while_spec.rb +17 -3
- data/spec/hamster/list/each_spec.rb +18 -4
- data/spec/hamster/list/empty_spec.rb +4 -2
- data/spec/hamster/list/eql_spec.rb +41 -7
- data/spec/hamster/list/filter_spec.rb +20 -6
- data/spec/hamster/list/find_spec.rb +63 -0
- data/spec/hamster/list/head_spec.rb +4 -2
- data/spec/hamster/list/include_spec.rb +16 -2
- data/spec/hamster/list/inspect_spec.rb +16 -2
- data/spec/hamster/list/map_spec.rb +18 -4
- data/spec/hamster/list/none_spec.rb +73 -0
- data/spec/hamster/list/reduce_spec.rb +66 -12
- data/spec/hamster/list/reject_spec.rb +39 -21
- data/spec/hamster/list/size_spec.rb +16 -2
- data/spec/hamster/list/tail_spec.rb +4 -2
- data/spec/hamster/list/take_spec.rb +16 -2
- data/spec/hamster/list/take_while_spec.rb +18 -4
- data/spec/hamster/list/to_a_spec.rb +16 -2
- data/spec/hamster/list/to_ary_spec.rb +42 -0
- data/spec/hamster/set/eql_spec.rb +35 -5
- data/spec/hamster/set/filter_spec.rb +1 -1
- data/spec/hamster/set/reduce_spec.rb +1 -1
- data/spec/hamster/set/reject_spec.rb +31 -27
- data/spec/hamster/set/to_a_spec.rb +29 -0
- data/spec/hamster/stack/copying_spec.rb +4 -2
- data/spec/hamster/stack/empty_spec.rb +4 -2
- data/spec/hamster/stack/eql_spec.rb +27 -7
- data/spec/hamster/stack/inspect_spec.rb +4 -2
- data/spec/hamster/stack/pop_spec.rb +12 -8
- data/spec/hamster/stack/push_spec.rb +6 -4
- data/spec/hamster/stack/size_spec.rb +4 -2
- data/spec/hamster/stack/top_spec.rb +6 -4
- metadata +8 -2
data/History.rdoc
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
=== 0.1.14 / 2009-12-14
|
2
|
+
|
3
|
+
* List#reduce supports optional initial value.
|
4
|
+
|
5
|
+
* Implemented List#to_ary for implicit conversion to arrays and call parameters.
|
6
|
+
|
7
|
+
* Implemented Set#to_a.
|
8
|
+
|
9
|
+
* Alias #filter as #find_all.
|
10
|
+
|
11
|
+
* Alias #reject as #delete_if.
|
12
|
+
|
13
|
+
* Alias #reduce as #fold.
|
14
|
+
|
1
15
|
=== 0.1.13 / 2009-12-10
|
2
16
|
|
3
17
|
* Stack now fully functional
|
data/README.rdoc
CHANGED
@@ -120,7 +120,7 @@ Lists are, where possible, lazy. That is, they try to defer processing items unt
|
|
120
120
|
true
|
121
121
|
end
|
122
122
|
|
123
|
-
The following code will only call <tt
|
123
|
+
The following code will only call <tt>prime?</tt> as many times as necessary to generate the first 3 prime numbers between 10000 and 1000000:
|
124
124
|
|
125
125
|
Hamster.interval(10000, 1000000).filter { |i| prime?(i) }.take(3) # => 0.0009s
|
126
126
|
|
@@ -142,6 +142,6 @@ Besides <tt>Hamster.list</tt> there is <tt>Hamster.interval(from, to)</tt> and <
|
|
142
142
|
|
143
143
|
Hamster started out as a spike to prove a point and has since morphed into something I actually use. My primary concern has been to round out the functionality with good test coverage and clean, readable code.
|
144
144
|
|
145
|
-
Performance is pretty good--especially with lazy lists--but there are some things which
|
145
|
+
Performance is pretty good--especially with lazy lists--but there are some things which unfortunately had to be converted from recursive to iterative due to a lack of Tail-Call-Optimisation in Ruby, making them a little less readable than I would otherwise have preferred.
|
146
146
|
|
147
147
|
Documentation is sparse but I've tried as best I can to write specs that reads as documentation. I've also tried to alias methods as their <tt>Enumerable</tt> equivalents where possible to make it easier for people to migrate code.
|
data/lib/hamster/hash.rb
CHANGED
@@ -51,13 +51,13 @@ module Hamster
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def each
|
54
|
-
|
54
|
+
return self unless block_given?
|
55
55
|
@trie.each { |entry| yield(entry.key, entry.value) }
|
56
56
|
self
|
57
57
|
end
|
58
58
|
|
59
59
|
def map
|
60
|
-
|
60
|
+
return self unless block_given?
|
61
61
|
if empty?
|
62
62
|
self
|
63
63
|
else
|
@@ -67,13 +67,14 @@ module Hamster
|
|
67
67
|
alias_method :collect, :map
|
68
68
|
|
69
69
|
def reduce(memo)
|
70
|
-
|
70
|
+
return memo unless block_given?
|
71
71
|
@trie.reduce(memo) { |memo, entry| yield(memo, entry.key, entry.value) }
|
72
72
|
end
|
73
73
|
alias_method :inject, :reduce
|
74
|
+
alias_method :fold, :reduce
|
74
75
|
|
75
76
|
def filter
|
76
|
-
|
77
|
+
return self unless block_given?
|
77
78
|
trie = @trie.filter { |entry| yield(entry.key, entry.value) }
|
78
79
|
if !trie.equal?(@trie)
|
79
80
|
self.class.new(trie)
|
@@ -82,17 +83,19 @@ module Hamster
|
|
82
83
|
end
|
83
84
|
end
|
84
85
|
alias_method :select, :filter
|
86
|
+
alias_method :find_all, :filter
|
85
87
|
|
86
88
|
def reject
|
87
|
-
|
89
|
+
return self unless block_given?
|
88
90
|
select { |key, value| !yield(key, value) }
|
89
91
|
end
|
92
|
+
alias_method :delete_if, :reject
|
90
93
|
|
91
94
|
def any?
|
92
95
|
if block_given?
|
93
96
|
each { |key, value| return true if yield(key, value) }
|
94
97
|
else
|
95
|
-
|
98
|
+
return !empty?
|
96
99
|
end
|
97
100
|
false
|
98
101
|
end
|
@@ -102,8 +105,6 @@ module Hamster
|
|
102
105
|
def all?
|
103
106
|
if block_given?
|
104
107
|
each { |key, value| return false unless yield(key, value) }
|
105
|
-
else
|
106
|
-
each { |pair| return false unless pair }
|
107
108
|
end
|
108
109
|
true
|
109
110
|
end
|
@@ -112,7 +113,7 @@ module Hamster
|
|
112
113
|
if block_given?
|
113
114
|
each { |key, value| return false if yield(key, value) }
|
114
115
|
else
|
115
|
-
|
116
|
+
return empty?
|
116
117
|
end
|
117
118
|
true
|
118
119
|
end
|
data/lib/hamster/list.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
module Hamster
|
2
2
|
|
3
|
+
Undefined = Object.new
|
4
|
+
|
3
5
|
class << self
|
4
6
|
|
5
7
|
def list(*items)
|
@@ -7,7 +9,7 @@ module Hamster
|
|
7
9
|
end
|
8
10
|
|
9
11
|
def stream(&block)
|
10
|
-
|
12
|
+
return EmptyList unless block_given?
|
11
13
|
Stream.new(yield) { stream(&block) }
|
12
14
|
end
|
13
15
|
|
@@ -29,7 +31,7 @@ module Hamster
|
|
29
31
|
end
|
30
32
|
|
31
33
|
def size
|
32
|
-
|
34
|
+
reduce(0) { |memo, item| memo + 1 }
|
33
35
|
end
|
34
36
|
alias_method :length, :size
|
35
37
|
|
@@ -38,46 +40,56 @@ module Hamster
|
|
38
40
|
end
|
39
41
|
alias_method :>>, :cons
|
40
42
|
|
41
|
-
def each
|
42
|
-
|
43
|
-
|
44
|
-
|
43
|
+
def each
|
44
|
+
return self unless block_given?
|
45
|
+
list = self
|
46
|
+
while !list.empty?
|
47
|
+
yield(list.head)
|
48
|
+
list = list.tail
|
49
|
+
end
|
45
50
|
nil
|
46
51
|
end
|
47
52
|
|
48
53
|
def map(&block)
|
49
|
-
|
54
|
+
return self unless block_given?
|
50
55
|
Stream.new(yield(head)) { tail.map(&block) }
|
51
56
|
end
|
52
57
|
alias_method :collect, :map
|
53
58
|
|
54
|
-
def reduce(memo, &block)
|
55
|
-
|
56
|
-
|
59
|
+
def reduce(memo = Undefined, &block)
|
60
|
+
return tail.reduce(head, &block) if memo.equal?(Undefined)
|
61
|
+
return memo unless block_given?
|
62
|
+
each { |item| memo = yield(memo, item) }
|
63
|
+
memo
|
57
64
|
end
|
58
65
|
alias_method :inject, :reduce
|
66
|
+
alias_method :fold, :reduce
|
59
67
|
|
60
68
|
def filter(&block)
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
69
|
+
return self unless block_given?
|
70
|
+
list = self
|
71
|
+
while !yield(list.head)
|
72
|
+
list = list.tail
|
73
|
+
return list if list.empty?
|
66
74
|
end
|
75
|
+
Stream.new(list.head) { list.tail.filter(&block) }
|
67
76
|
end
|
68
77
|
alias_method :select, :filter
|
78
|
+
alias_method :find_all, :filter
|
69
79
|
|
70
80
|
def reject(&block)
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
81
|
+
return self unless block_given?
|
82
|
+
list = self
|
83
|
+
while yield(list.head)
|
84
|
+
list = list.tail
|
85
|
+
return list if list.empty?
|
76
86
|
end
|
87
|
+
Stream.new(list.head) { list.tail.reject(&block) }
|
77
88
|
end
|
89
|
+
alias_method :delete_if, :reject
|
78
90
|
|
79
91
|
def take_while(&block)
|
80
|
-
|
92
|
+
return self unless block_given?
|
81
93
|
if yield(head)
|
82
94
|
Stream.new(head) { tail.take_while(&block) }
|
83
95
|
else
|
@@ -85,13 +97,13 @@ module Hamster
|
|
85
97
|
end
|
86
98
|
end
|
87
99
|
|
88
|
-
def drop_while
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
self
|
100
|
+
def drop_while
|
101
|
+
return self unless block_given?
|
102
|
+
list = self
|
103
|
+
while !list.empty? && yield(list.head)
|
104
|
+
list = list.tail
|
94
105
|
end
|
106
|
+
list
|
95
107
|
end
|
96
108
|
|
97
109
|
def take(number)
|
@@ -103,22 +115,67 @@ module Hamster
|
|
103
115
|
end
|
104
116
|
|
105
117
|
def drop(number)
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
118
|
+
list = self
|
119
|
+
while !list.empty? && number > 0
|
120
|
+
number -= 1
|
121
|
+
list = list.tail
|
110
122
|
end
|
123
|
+
list
|
111
124
|
end
|
112
125
|
|
113
|
-
def include?(
|
114
|
-
item
|
126
|
+
def include?(object)
|
127
|
+
each { |item| return true if object == item }
|
128
|
+
false
|
115
129
|
end
|
116
130
|
alias_method :member?, :include?
|
117
131
|
|
132
|
+
def any?
|
133
|
+
if block_given?
|
134
|
+
each { |item| return true if yield(item) }
|
135
|
+
else
|
136
|
+
each { |item| return true if item }
|
137
|
+
end
|
138
|
+
false
|
139
|
+
end
|
140
|
+
alias_method :exist?, :any?
|
141
|
+
alias_method :exists?, :any?
|
142
|
+
|
143
|
+
def all?
|
144
|
+
if block_given?
|
145
|
+
each { |item| return false unless yield(item) }
|
146
|
+
else
|
147
|
+
each { |item| return false unless item }
|
148
|
+
end
|
149
|
+
true
|
150
|
+
end
|
151
|
+
|
152
|
+
def none?
|
153
|
+
if block_given?
|
154
|
+
each { |item| return false if yield(item) }
|
155
|
+
else
|
156
|
+
each { |item| return false if item }
|
157
|
+
end
|
158
|
+
true
|
159
|
+
end
|
160
|
+
|
161
|
+
def find
|
162
|
+
return nil unless block_given?
|
163
|
+
each { |item| return item if yield(item) }
|
164
|
+
end
|
165
|
+
alias_method :detect, :find
|
166
|
+
|
118
167
|
def eql?(other)
|
119
|
-
return true if other.equal?(self)
|
120
168
|
return false unless other.is_a?(List)
|
121
|
-
|
169
|
+
|
170
|
+
list = self
|
171
|
+
while !list.empty? && !other.empty?
|
172
|
+
return true if other.equal?(list)
|
173
|
+
return false unless other.is_a?(List)
|
174
|
+
return false unless other.head.eql?(list.head)
|
175
|
+
list = list.tail
|
176
|
+
other = other.tail
|
177
|
+
end
|
178
|
+
other.equal?(list)
|
122
179
|
end
|
123
180
|
alias_method :==, :eql?
|
124
181
|
|
@@ -128,8 +185,9 @@ module Hamster
|
|
128
185
|
alias_method :clone, :dup
|
129
186
|
|
130
187
|
def to_a
|
131
|
-
reduce([]) { |
|
188
|
+
reduce([]) { |a, item| a << item }
|
132
189
|
end
|
190
|
+
alias_method :to_ary, :to_a
|
133
191
|
|
134
192
|
def inspect
|
135
193
|
to_a.inspect
|
@@ -208,56 +266,30 @@ module Hamster
|
|
208
266
|
true
|
209
267
|
end
|
210
268
|
|
211
|
-
def size
|
212
|
-
0
|
213
|
-
end
|
214
|
-
alias_method :length, :size
|
215
|
-
|
216
|
-
def each
|
217
|
-
block_given? or return self
|
218
|
-
nil
|
219
|
-
end
|
220
|
-
|
221
269
|
def map
|
222
270
|
self
|
223
271
|
end
|
224
272
|
alias_method :collect, :map
|
225
273
|
|
226
|
-
def reduce(memo)
|
227
|
-
memo
|
228
|
-
end
|
229
|
-
alias_method :inject, :reduce
|
230
|
-
|
231
274
|
def filter
|
232
275
|
self
|
233
276
|
end
|
234
277
|
alias_method :select, :filter
|
278
|
+
alias_method :find_all, :filter
|
235
279
|
|
236
280
|
def reject
|
237
281
|
self
|
238
282
|
end
|
283
|
+
alias_method :delete_if, :reject
|
239
284
|
|
240
285
|
def take_while
|
241
286
|
self
|
242
287
|
end
|
243
288
|
|
244
|
-
def drop_while
|
245
|
-
self
|
246
|
-
end
|
247
|
-
|
248
289
|
def take(number)
|
249
290
|
self
|
250
291
|
end
|
251
292
|
|
252
|
-
def drop(number)
|
253
|
-
self
|
254
|
-
end
|
255
|
-
|
256
|
-
def include?(item)
|
257
|
-
false
|
258
|
-
end
|
259
|
-
alias_method :member?, :include?
|
260
|
-
|
261
293
|
end
|
262
294
|
|
263
295
|
end
|
data/lib/hamster/set.rb
CHANGED
@@ -45,13 +45,13 @@ module Hamster
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def each
|
48
|
-
|
48
|
+
return self unless block_given?
|
49
49
|
@trie.each { |entry| yield(entry.key) }
|
50
50
|
self
|
51
51
|
end
|
52
52
|
|
53
53
|
def map
|
54
|
-
|
54
|
+
return self unless block_given?
|
55
55
|
if empty?
|
56
56
|
self
|
57
57
|
else
|
@@ -61,13 +61,14 @@ module Hamster
|
|
61
61
|
alias_method :collect, :map
|
62
62
|
|
63
63
|
def reduce(memo)
|
64
|
-
|
64
|
+
return memo unless block_given?
|
65
65
|
@trie.reduce(memo) { |memo, entry| yield(memo, entry.key) }
|
66
66
|
end
|
67
67
|
alias_method :inject, :reduce
|
68
|
+
alias_method :fold, :reduce
|
68
69
|
|
69
70
|
def filter
|
70
|
-
|
71
|
+
return self unless block_given?
|
71
72
|
trie = @trie.filter { |entry| yield(entry.key) }
|
72
73
|
if !trie.equal?(@trie)
|
73
74
|
self.class.new(trie)
|
@@ -76,11 +77,13 @@ module Hamster
|
|
76
77
|
end
|
77
78
|
end
|
78
79
|
alias_method :select, :filter
|
80
|
+
alias_method :find_all, :filter
|
79
81
|
|
80
82
|
def reject
|
81
|
-
|
83
|
+
return self unless block_given?
|
82
84
|
select { |item| !yield(item) }
|
83
85
|
end
|
86
|
+
alias_method :delete_if, :reject
|
84
87
|
|
85
88
|
def any?
|
86
89
|
if block_given?
|
@@ -121,6 +124,10 @@ module Hamster
|
|
121
124
|
end
|
122
125
|
alias_method :clone, :dup
|
123
126
|
|
127
|
+
def to_a
|
128
|
+
reduce([]) { |a, item| a << item }
|
129
|
+
end
|
130
|
+
|
124
131
|
end
|
125
132
|
|
126
133
|
end
|
data/lib/hamster/version.rb
CHANGED
@@ -29,7 +29,7 @@ describe Hamster::Hash do
|
|
29
29
|
describe "with a block" do
|
30
30
|
|
31
31
|
it "returns true if the block always returns true" do
|
32
|
-
@hash.all? { |
|
32
|
+
@hash.all? { |key, value| true }.should be_true
|
33
33
|
end
|
34
34
|
|
35
35
|
it "returns false if the block ever returns false" do
|
@@ -6,20 +6,49 @@ describe Hamster::Hash do
|
|
6
6
|
|
7
7
|
describe "##{method}" do
|
8
8
|
|
9
|
+
describe "returns false when comparing with" do
|
10
|
+
|
11
|
+
before do
|
12
|
+
@hash = Hamster.hash("A" => "aye", "B" => "bee", "C" => "see")
|
13
|
+
end
|
14
|
+
|
15
|
+
it "a standard hash" do
|
16
|
+
@hash.send(method, "A" => "aye", "B" => "bee", "C" => "see").should be_false
|
17
|
+
end
|
18
|
+
|
19
|
+
it "an aribtrary object" do
|
20
|
+
@hash.send(method, Object.new).should be_false
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
9
25
|
[
|
10
|
-
[
|
11
|
-
[
|
12
|
-
[
|
13
|
-
[
|
14
|
-
[
|
15
|
-
[
|
16
|
-
[
|
17
|
-
[
|
18
|
-
[
|
19
|
-
].each do |a, b,
|
20
|
-
|
21
|
-
|
22
|
-
|
26
|
+
[{}, {}, true],
|
27
|
+
[{"A" => "aye"}, {}, false],
|
28
|
+
[{}, {"A" => "aye"}, false],
|
29
|
+
[{"A" => "aye"}, {"A" => "aye"}, true],
|
30
|
+
[{"A" => "aye"}, {"B" => "bee"}, false],
|
31
|
+
[{"A" => "aye", "B" => "bee"}, {"A" => "aye"}, false],
|
32
|
+
[{"A" => "aye"}, {"A" => "aye", "B" => "bee"}, false],
|
33
|
+
[{"A" => "aye", "B" => "bee", "C" => "see"}, {"A" => "aye", "B" => "bee", "C" => "see"}, true],
|
34
|
+
[{"C" => "see", "A" => "aye", "B" => "bee"}, {"A" => "aye", "B" => "bee", "C" => "see"}, true],
|
35
|
+
].each do |a, b, expected|
|
36
|
+
|
37
|
+
describe "returns #{expected}" do
|
38
|
+
|
39
|
+
before do
|
40
|
+
@a = Hamster.hash(a)
|
41
|
+
@b = Hamster.hash(b)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "for #{a.inspect} and #{b.inspect}" do
|
45
|
+
@a.send(method, @b).should == expected
|
46
|
+
end
|
47
|
+
|
48
|
+
it "for #{b.inspect} and #{a.inspect}" do
|
49
|
+
@b.send(method, @a).should == expected
|
50
|
+
end
|
51
|
+
|
23
52
|
end
|
24
53
|
|
25
54
|
end
|