hamster 0.1.23 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +26 -0
- data/README.rdoc +1 -1
- data/lib/hamster.rb +1 -1
- data/lib/hamster/core_ext/io.rb +7 -5
- data/lib/hamster/hash.rb +31 -29
- data/lib/hamster/list.rb +203 -128
- data/lib/hamster/set.rb +39 -25
- data/lib/hamster/stack.rb +9 -5
- data/lib/hamster/trie.rb +5 -1
- data/lib/hamster/version.rb +1 -1
- data/spec/hamster/hash/all_spec.rb +29 -25
- data/spec/hamster/hash/reduce_spec.rb +1 -1
- data/spec/hamster/hash/uniq_spec.rb +23 -0
- data/spec/hamster/list/all_spec.rb +55 -55
- data/spec/hamster/list/any_spec.rb +4 -8
- data/spec/hamster/list/append_spec.rb +2 -20
- data/spec/hamster/list/break_spec.rb +22 -121
- data/spec/hamster/list/cadr_spec.rb +4 -0
- data/spec/hamster/list/chunk_spec.rb +6 -0
- data/spec/hamster/list/combinations_spec.rb +51 -0
- data/spec/hamster/list/count_spec.rb +4 -8
- data/spec/hamster/list/cycle_spec.rb +5 -24
- data/spec/hamster/list/drop_spec.rb +2 -14
- data/spec/hamster/list/drop_while_spec.rb +2 -14
- data/spec/hamster/list/each_spec.rb +4 -8
- data/spec/hamster/list/eql_spec.rb +9 -10
- data/spec/hamster/list/filter_spec.rb +2 -20
- data/spec/hamster/list/find_spec.rb +4 -8
- data/spec/hamster/list/grep_spec.rb +2 -20
- data/spec/hamster/list/include_spec.rb +4 -8
- data/spec/hamster/list/init_spec.rb +4 -0
- data/spec/hamster/list/inits_spec.rb +42 -0
- data/spec/hamster/list/inspect_spec.rb +4 -8
- data/spec/hamster/list/intersperse_spec.rb +2 -14
- data/spec/hamster/list/join_spec.rb +4 -8
- data/spec/hamster/list/last_spec.rb +4 -8
- data/spec/hamster/list/map_spec.rb +2 -14
- data/spec/hamster/list/maximum_spec.rb +4 -8
- data/spec/hamster/list/minimum_spec.rb +4 -8
- data/spec/hamster/list/none_spec.rb +4 -8
- data/spec/hamster/list/one_spec.rb +4 -8
- data/spec/hamster/list/partition_spec.rb +12 -111
- data/spec/hamster/list/product_spec.rb +4 -8
- data/spec/hamster/list/reduce_spec.rb +4 -8
- data/spec/hamster/list/remove_spec.rb +2 -14
- data/spec/hamster/list/reverse_spec.rb +4 -8
- data/spec/hamster/list/size_spec.rb +4 -8
- data/spec/hamster/list/sorting_spec.rb +2 -14
- data/spec/hamster/list/span_spec.rb +22 -121
- data/spec/hamster/list/split_at_spec.rb +2 -65
- data/spec/hamster/list/sum_spec.rb +4 -8
- data/spec/hamster/list/tails_spec.rb +42 -0
- data/spec/hamster/list/take_spec.rb +2 -14
- data/spec/hamster/list/take_while_spec.rb +2 -14
- data/spec/hamster/list/to_a_spec.rb +4 -8
- data/spec/hamster/list/to_ary_spec.rb +4 -8
- data/spec/hamster/list/union_spec.rb +1 -21
- data/spec/hamster/list/uniq_spec.rb +3 -15
- data/spec/hamster/list/zip_spec.rb +1 -21
- data/spec/hamster/set/all_spec.rb +33 -29
- data/spec/hamster/set/product_spec.rb +32 -0
- data/spec/hamster/set/sum_spec.rb +32 -0
- data/spec/hamster/set/uniq_spec.rb +1 -1
- data/spec/spec.opts +0 -1
- metadata +8 -2
data/History.rdoc
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
=== 0.2.0 / 2010-01-14
|
2
|
+
|
3
|
+
* List methods that return lists are now all lazy. Not sure what, if any, negative impact this will have but the positives have so far been well worth it.
|
4
|
+
|
5
|
+
* Ensure List#eql? (and #==) doesn't accidentally consider an empty list to be equal to an empty array!
|
6
|
+
|
7
|
+
* Ensure List responds_to? cadr and friends.
|
8
|
+
|
9
|
+
* Stream now releases the block for garbage collection once called.
|
10
|
+
|
11
|
+
* Implement List#combinations.
|
12
|
+
|
13
|
+
* Implement List#inits.
|
14
|
+
|
15
|
+
* Implement List#tails.
|
16
|
+
|
17
|
+
* Implement Hash#uniq.
|
18
|
+
|
19
|
+
* Alias #uniq as #remove_duplicates.
|
20
|
+
|
21
|
+
* Alias #all? as #forall?
|
22
|
+
|
23
|
+
* Implement Set#product.
|
24
|
+
|
25
|
+
* Implement Set#sum.
|
26
|
+
|
1
27
|
=== 0.1.23 / 2010-01-11
|
2
28
|
|
3
29
|
* Implement List#product.
|
data/README.rdoc
CHANGED
@@ -170,7 +170,7 @@ How is this even possible? It's possible because <tt>IO#to_list</tt> creates a l
|
|
170
170
|
|
171
171
|
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.
|
172
172
|
|
173
|
-
Performance is pretty good--especially with lazy lists--but there are some things which
|
173
|
+
Performance is pretty good--especially with lazy lists--but there are some things which may blow the stack due to a lack of Tail-Call-Optimisation in Ruby.
|
174
174
|
|
175
175
|
Documentation is sparse but I've tried as best I can to write specs that read 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.
|
176
176
|
|
data/lib/hamster.rb
CHANGED
data/lib/hamster/core_ext/io.rb
CHANGED
@@ -7,11 +7,13 @@ module Hamster
|
|
7
7
|
module IO
|
8
8
|
|
9
9
|
def to_list(sep = $/)
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
Stream.new do
|
11
|
+
line = gets(sep)
|
12
|
+
if line
|
13
|
+
Sequence.new(line, to_list)
|
14
|
+
else
|
15
|
+
EmptyList
|
16
|
+
end
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
data/lib/hamster/hash.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
1
3
|
require 'hamster/trie'
|
2
4
|
|
3
5
|
module Hamster
|
@@ -8,6 +10,8 @@ module Hamster
|
|
8
10
|
|
9
11
|
class Hash
|
10
12
|
|
13
|
+
extend Forwardable
|
14
|
+
|
11
15
|
def initialize(trie = Trie.new)
|
12
16
|
@trie = trie
|
13
17
|
end
|
@@ -15,19 +19,19 @@ module Hamster
|
|
15
19
|
def size
|
16
20
|
@trie.size
|
17
21
|
end
|
18
|
-
|
22
|
+
def_delegator :self, :size, :length
|
19
23
|
|
20
24
|
def empty?
|
21
25
|
@trie.empty?
|
22
26
|
end
|
23
|
-
|
27
|
+
def_delegator :self, :empty?, :null?
|
24
28
|
|
25
29
|
def has_key?(key)
|
26
30
|
@trie.has_key?(key)
|
27
31
|
end
|
28
|
-
|
29
|
-
|
30
|
-
|
32
|
+
def_delegator :self, :has_key?, :key?
|
33
|
+
def_delegator :self, :has_key?, :include?
|
34
|
+
def_delegator :self, :has_key?, :member?
|
31
35
|
|
32
36
|
def get(key)
|
33
37
|
entry = @trie.get(key)
|
@@ -35,12 +39,12 @@ module Hamster
|
|
35
39
|
entry.value
|
36
40
|
end
|
37
41
|
end
|
38
|
-
|
42
|
+
def_delegator :self, :get, :[]
|
39
43
|
|
40
44
|
def put(key, value)
|
41
45
|
self.class.new(@trie.put(key, value))
|
42
46
|
end
|
43
|
-
|
47
|
+
def_delegator :self, :put, :[]=
|
44
48
|
|
45
49
|
def delete(key)
|
46
50
|
trie = @trie.delete(key)
|
@@ -55,7 +59,7 @@ module Hamster
|
|
55
59
|
return self unless block_given?
|
56
60
|
@trie.each { |entry| yield(entry.key, entry.value) }
|
57
61
|
end
|
58
|
-
|
62
|
+
def_delegator :self, :each, :foreach
|
59
63
|
|
60
64
|
def map
|
61
65
|
return self unless block_given?
|
@@ -65,14 +69,14 @@ module Hamster
|
|
65
69
|
self.class.new(@trie.reduce(Trie.new) { |trie, entry| trie.put(*yield(entry.key, entry.value)) })
|
66
70
|
end
|
67
71
|
end
|
68
|
-
|
72
|
+
def_delegator :self, :map, :collect
|
69
73
|
|
70
74
|
def reduce(memo)
|
71
75
|
return memo unless block_given?
|
72
76
|
@trie.reduce(memo) { |memo, entry| yield(memo, entry.key, entry.value) }
|
73
77
|
end
|
74
|
-
|
75
|
-
|
78
|
+
def_delegator :self, :reduce, :inject
|
79
|
+
def_delegator :self, :reduce, :fold
|
76
80
|
|
77
81
|
def filter
|
78
82
|
return self unless block_given?
|
@@ -83,26 +87,23 @@ module Hamster
|
|
83
87
|
self.class.new(trie)
|
84
88
|
end
|
85
89
|
end
|
86
|
-
|
87
|
-
|
90
|
+
def_delegator :self, :filter, :select
|
91
|
+
def_delegator :self, :filter, :find_all
|
88
92
|
|
89
93
|
def remove
|
90
94
|
return self unless block_given?
|
91
95
|
filter { |key, value| !yield(key, value) }
|
92
96
|
end
|
93
|
-
|
94
|
-
|
97
|
+
def_delegator :self, :remove, :reject
|
98
|
+
def_delegator :self, :remove, :delete_if
|
95
99
|
|
96
100
|
def any?
|
97
|
-
|
98
|
-
|
99
|
-
else
|
100
|
-
return !empty?
|
101
|
-
end
|
101
|
+
return !empty? unless block_given?
|
102
|
+
each { |key, value| return true if yield(key, value) }
|
102
103
|
false
|
103
104
|
end
|
104
|
-
|
105
|
-
|
105
|
+
def_delegator :self, :any?, :exist?
|
106
|
+
def_delegator :self, :any?, :exists?
|
106
107
|
|
107
108
|
def all?
|
108
109
|
if block_given?
|
@@ -110,25 +111,26 @@ module Hamster
|
|
110
111
|
end
|
111
112
|
true
|
112
113
|
end
|
114
|
+
def_delegator :self, :all?, :forall?
|
113
115
|
|
114
116
|
def none?
|
115
|
-
|
116
|
-
|
117
|
-
else
|
118
|
-
return empty?
|
119
|
-
end
|
117
|
+
return empty? unless block_given?
|
118
|
+
each { |key, value| return false if yield(key, value) }
|
120
119
|
true
|
121
120
|
end
|
122
121
|
|
123
122
|
def eql?(other)
|
124
123
|
other.is_a?(self.class) && @trie.eql?(other.instance_eval{@trie})
|
125
124
|
end
|
126
|
-
|
125
|
+
def_delegator :self, :eql?, :==
|
127
126
|
|
128
127
|
def dup
|
129
128
|
self
|
130
129
|
end
|
131
|
-
|
130
|
+
def_delegator :self, :dup, :clone
|
131
|
+
def_delegator :self, :dup, :uniq
|
132
|
+
def_delegator :self, :dup, :nub
|
133
|
+
def_delegator :self, :dup, :remove_duplicates
|
132
134
|
|
133
135
|
end
|
134
136
|
|
data/lib/hamster/list.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'forwardable'
|
1
2
|
require 'monitor'
|
2
3
|
|
3
4
|
require 'hamster/set'
|
@@ -6,23 +7,25 @@ module Hamster
|
|
6
7
|
|
7
8
|
class << self
|
8
9
|
|
10
|
+
extend Forwardable
|
11
|
+
|
9
12
|
def list(*items)
|
10
13
|
items.reverse.reduce(EmptyList) { |list, item| list.cons(item) }
|
11
14
|
end
|
12
15
|
|
13
16
|
def stream(&block)
|
14
17
|
return EmptyList unless block_given?
|
15
|
-
Stream.new(yield
|
18
|
+
Stream.new { Sequence.new(yield, stream(&block)) }
|
16
19
|
end
|
17
20
|
|
18
21
|
def interval(from, to)
|
19
22
|
return EmptyList if from > to
|
20
|
-
Stream.new(from
|
23
|
+
Stream.new { Sequence.new(from, interval(from.succ, to)) }
|
21
24
|
end
|
22
|
-
|
25
|
+
def_delegator :self, :interval, :range
|
23
26
|
|
24
27
|
def repeat(item)
|
25
|
-
Stream.new(item
|
28
|
+
Stream.new { Sequence.new(item, repeat(item)) }
|
26
29
|
end
|
27
30
|
|
28
31
|
def replicate(number, item)
|
@@ -30,29 +33,37 @@ module Hamster
|
|
30
33
|
end
|
31
34
|
|
32
35
|
def iterate(item, &block)
|
33
|
-
Stream.new(item
|
36
|
+
Stream.new { Sequence.new(item, iterate(yield(item), &block)) }
|
34
37
|
end
|
35
38
|
|
36
39
|
end
|
37
40
|
|
38
41
|
module List
|
39
42
|
|
43
|
+
extend Forwardable
|
44
|
+
|
40
45
|
Undefined = Object.new
|
41
46
|
|
47
|
+
CADR = /^c([ad]+)r$/
|
48
|
+
|
49
|
+
def first
|
50
|
+
head
|
51
|
+
end
|
52
|
+
|
42
53
|
def empty?
|
43
54
|
false
|
44
55
|
end
|
45
|
-
|
56
|
+
def_delegator :self, :empty?, :null?
|
46
57
|
|
47
58
|
def size
|
48
59
|
reduce(0) { |memo, item| memo.succ }
|
49
60
|
end
|
50
|
-
|
61
|
+
def_delegator :self, :size, :length
|
51
62
|
|
52
63
|
def cons(item)
|
53
64
|
Sequence.new(item, self)
|
54
65
|
end
|
55
|
-
|
66
|
+
def_delegator :self, :cons, :>>
|
56
67
|
|
57
68
|
def each
|
58
69
|
return self unless block_given?
|
@@ -62,13 +73,19 @@ module Hamster
|
|
62
73
|
list = list.tail
|
63
74
|
end
|
64
75
|
end
|
65
|
-
|
76
|
+
def_delegator :self, :each, :foreach
|
66
77
|
|
67
78
|
def map(&block)
|
68
79
|
return self unless block_given?
|
69
|
-
Stream.new
|
80
|
+
Stream.new do
|
81
|
+
if empty?
|
82
|
+
self
|
83
|
+
else
|
84
|
+
Sequence.new(yield(head), tail.map(&block))
|
85
|
+
end
|
86
|
+
end
|
70
87
|
end
|
71
|
-
|
88
|
+
def_delegator :self, :map, :collect
|
72
89
|
|
73
90
|
def reduce(memo = Undefined, &block)
|
74
91
|
return tail.reduce(head, &block) if memo.equal?(Undefined)
|
@@ -76,80 +93,102 @@ module Hamster
|
|
76
93
|
each { |item| memo = yield(memo, item) }
|
77
94
|
memo
|
78
95
|
end
|
79
|
-
|
80
|
-
|
96
|
+
def_delegator :self, :reduce, :inject
|
97
|
+
def_delegator :self, :reduce, :fold
|
81
98
|
|
82
99
|
def filter(&block)
|
83
100
|
return self unless block_given?
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
101
|
+
Stream.new do
|
102
|
+
if empty?
|
103
|
+
self
|
104
|
+
elsif yield(head)
|
105
|
+
Sequence.new(head, tail.filter(&block))
|
106
|
+
else
|
107
|
+
tail.filter(&block)
|
108
|
+
end
|
88
109
|
end
|
89
|
-
Stream.new(list.head) { list.tail.filter(&block) }
|
90
110
|
end
|
91
|
-
|
92
|
-
|
111
|
+
def_delegator :self, :filter, :select
|
112
|
+
def_delegator :self, :filter, :find_all
|
93
113
|
|
94
114
|
def remove(&block)
|
95
115
|
return self unless block_given?
|
96
116
|
filter { |item| !yield(item) }
|
97
117
|
end
|
98
|
-
|
99
|
-
|
118
|
+
def_delegator :self, :remove, :reject
|
119
|
+
def_delegator :self, :remove, :delete_if
|
100
120
|
|
101
121
|
def take_while(&block)
|
102
122
|
return self unless block_given?
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
123
|
+
Stream.new do
|
124
|
+
if empty?
|
125
|
+
self
|
126
|
+
elsif yield(head)
|
127
|
+
Sequence.new(head, tail.take_while(&block))
|
128
|
+
else
|
129
|
+
EmptyList
|
130
|
+
end
|
107
131
|
end
|
108
132
|
end
|
109
133
|
|
110
|
-
def drop_while
|
134
|
+
def drop_while(&block)
|
111
135
|
return self unless block_given?
|
112
|
-
|
113
|
-
|
114
|
-
|
136
|
+
Stream.new do
|
137
|
+
if empty?
|
138
|
+
self
|
139
|
+
elsif yield(head)
|
140
|
+
tail.drop_while(&block)
|
141
|
+
else
|
142
|
+
self
|
143
|
+
end
|
115
144
|
end
|
116
|
-
list
|
117
145
|
end
|
118
146
|
|
119
147
|
def take(number)
|
120
|
-
|
121
|
-
|
148
|
+
Stream.new do
|
149
|
+
if empty?
|
150
|
+
self
|
151
|
+
elsif number > 0
|
152
|
+
Sequence.new(head, tail.take(number - 1))
|
153
|
+
else
|
154
|
+
EmptyList
|
155
|
+
end
|
156
|
+
end
|
122
157
|
end
|
123
158
|
|
124
159
|
def drop(number)
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
160
|
+
Stream.new do
|
161
|
+
if empty?
|
162
|
+
self
|
163
|
+
elsif number > 0
|
164
|
+
tail.drop(number - 1)
|
165
|
+
else
|
166
|
+
self
|
167
|
+
end
|
129
168
|
end
|
130
|
-
list
|
131
169
|
end
|
132
170
|
|
133
171
|
def include?(object)
|
134
172
|
any? { |item| item == object }
|
135
173
|
end
|
136
|
-
|
137
|
-
|
138
|
-
|
174
|
+
def_delegator :self, :include?, :member?
|
175
|
+
def_delegator :self, :include?, :contains?
|
176
|
+
def_delegator :self, :include?, :elem?
|
139
177
|
|
140
178
|
def any?
|
141
179
|
return any? { |item| item } unless block_given?
|
142
180
|
each { |item| return true if yield(item) }
|
143
181
|
false
|
144
182
|
end
|
145
|
-
|
146
|
-
|
183
|
+
def_delegator :self, :any?, :exist?
|
184
|
+
def_delegator :self, :any?, :exists?
|
147
185
|
|
148
186
|
def all?
|
149
187
|
return all? { |item| item } unless block_given?
|
150
188
|
each { |item| return false unless yield(item) }
|
151
189
|
true
|
152
190
|
end
|
191
|
+
def_delegator :self, :all?, :forall?
|
153
192
|
|
154
193
|
def none?
|
155
194
|
return none? { |item| item } unless block_given?
|
@@ -171,19 +210,25 @@ module Hamster
|
|
171
210
|
return nil unless block_given?
|
172
211
|
each { |item| return item if yield(item) }
|
173
212
|
end
|
174
|
-
|
213
|
+
def_delegator :self, :find, :detect
|
175
214
|
|
176
215
|
def partition(&block)
|
177
216
|
return self unless block_given?
|
178
|
-
Stream.new(filter(&block)
|
217
|
+
Stream.new { Sequence.new(filter(&block), Sequence.new(remove(&block))) }
|
179
218
|
end
|
180
219
|
|
181
220
|
def append(other)
|
182
|
-
Stream.new
|
221
|
+
Stream.new do
|
222
|
+
if empty?
|
223
|
+
other
|
224
|
+
else
|
225
|
+
Sequence.new(head, tail.append(other))
|
226
|
+
end
|
227
|
+
end
|
183
228
|
end
|
184
|
-
|
185
|
-
|
186
|
-
|
229
|
+
def_delegator :self, :append, :concat
|
230
|
+
def_delegator :self, :append, :cat
|
231
|
+
def_delegator :self, :append, :+
|
187
232
|
|
188
233
|
def reverse
|
189
234
|
reduce(EmptyList) { |list, item| list.cons(item) }
|
@@ -193,37 +238,49 @@ module Hamster
|
|
193
238
|
return minimum { |minimum, item| item <=> minimum } unless block_given?
|
194
239
|
reduce { |minimum, item| yield(minimum, item) < 0 ? item : minimum }
|
195
240
|
end
|
196
|
-
|
241
|
+
def_delegator :self, :minimum, :min
|
197
242
|
|
198
243
|
def maximum(&block)
|
199
244
|
return maximum { |maximum, item| item <=> maximum } unless block_given?
|
200
245
|
reduce { |maximum, item| yield(maximum, item) > 0 ? item : maximum }
|
201
246
|
end
|
202
|
-
|
247
|
+
def_delegator :self, :maximum, :max
|
203
248
|
|
204
249
|
def grep(pattern, &block)
|
205
250
|
filter { |item| pattern === item }.map(&block)
|
206
251
|
end
|
207
252
|
|
208
253
|
def zip(other)
|
209
|
-
Stream.new
|
254
|
+
Stream.new do
|
255
|
+
if empty? && other.empty?
|
256
|
+
self
|
257
|
+
else
|
258
|
+
Sequence.new(Sequence.new(head, Sequence.new(other.head)), tail.zip(other.tail))
|
259
|
+
end
|
260
|
+
end
|
210
261
|
end
|
211
262
|
|
212
263
|
def cycle
|
213
|
-
Stream.new
|
264
|
+
Stream.new do
|
265
|
+
if empty?
|
266
|
+
self
|
267
|
+
else
|
268
|
+
Sequence.new(head, tail.append(self.cycle))
|
269
|
+
end
|
270
|
+
end
|
214
271
|
end
|
215
272
|
|
216
273
|
def split_at(number)
|
217
|
-
Sequence.new(
|
274
|
+
Sequence.new(take(number), Sequence.new(drop(number)))
|
218
275
|
end
|
219
276
|
|
220
277
|
def span(&block)
|
221
|
-
return Sequence.new(
|
222
|
-
|
278
|
+
return Sequence.new(self, Sequence.new(EmptyList)) unless block_given?
|
279
|
+
Sequence.new(take_while(&block), Sequence.new(drop_while(&block)))
|
223
280
|
end
|
224
281
|
|
225
282
|
def break(&block)
|
226
|
-
return Sequence.new(
|
283
|
+
return Sequence.new(self, Sequence.new(EmptyList)) unless block_given?
|
227
284
|
span { |item| !yield(item) }
|
228
285
|
end
|
229
286
|
|
@@ -236,42 +293,56 @@ module Hamster
|
|
236
293
|
end
|
237
294
|
|
238
295
|
def sort(&block)
|
239
|
-
|
296
|
+
Stream.new do
|
297
|
+
Hamster.list(*to_a.sort(&block))
|
298
|
+
end
|
240
299
|
end
|
241
300
|
|
242
301
|
def sort_by(&block)
|
243
302
|
return sort unless block_given?
|
244
|
-
|
303
|
+
Stream.new do
|
304
|
+
Hamster.list(*to_a.sort_by(&block))
|
305
|
+
end
|
245
306
|
end
|
246
307
|
|
247
308
|
def join(sep = "")
|
309
|
+
return "" if empty?
|
248
310
|
sep = sep.to_s
|
249
311
|
tail.reduce(head.to_s) { |string, item| string << sep << item.to_s }
|
250
312
|
end
|
251
313
|
|
252
314
|
def intersperse(sep)
|
253
|
-
|
254
|
-
|
315
|
+
Stream.new do
|
316
|
+
if tail.empty?
|
317
|
+
self
|
318
|
+
else
|
319
|
+
Sequence.new(head, Sequence.new(sep, tail.intersperse(sep)))
|
320
|
+
end
|
321
|
+
end
|
255
322
|
end
|
256
323
|
|
257
324
|
def uniq(items = Set.new)
|
258
|
-
|
259
|
-
|
260
|
-
|
325
|
+
Stream.new do
|
326
|
+
if empty?
|
327
|
+
self
|
328
|
+
elsif items.include?(head)
|
329
|
+
tail.uniq(items)
|
330
|
+
else
|
331
|
+
Sequence.new(head, tail.uniq(items.add(head)))
|
332
|
+
end
|
261
333
|
end
|
262
|
-
return list if list.empty?
|
263
|
-
Stream.new(list.head) { list.tail.uniq(items.add(list.head)) }
|
264
334
|
end
|
265
|
-
|
335
|
+
def_delegator :self, :uniq, :nub
|
336
|
+
def_delegator :self, :uniq, :remove_duplicates
|
266
337
|
|
267
338
|
def union(other)
|
268
339
|
self.append(other).uniq
|
269
340
|
end
|
270
|
-
|
341
|
+
def_delegator :self, :union, :|
|
271
342
|
|
272
343
|
def init
|
273
344
|
return EmptyList if tail.empty?
|
274
|
-
Stream.new(head
|
345
|
+
Stream.new { Sequence.new(head, tail.init) }
|
275
346
|
end
|
276
347
|
|
277
348
|
def last
|
@@ -290,6 +361,38 @@ module Hamster
|
|
290
361
|
reduce(0, &:+)
|
291
362
|
end
|
292
363
|
|
364
|
+
def tails
|
365
|
+
Stream.new do
|
366
|
+
if empty?
|
367
|
+
Sequence.new(self)
|
368
|
+
else
|
369
|
+
Sequence.new(self, tail.tails)
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
def inits
|
375
|
+
Stream.new do
|
376
|
+
if empty?
|
377
|
+
Sequence.new(self)
|
378
|
+
else
|
379
|
+
Sequence.new(EmptyList, tail.inits.map { |list| list.cons(head) })
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
def combinations(number)
|
385
|
+
return Sequence.new(EmptyList) if number == 0
|
386
|
+
Stream.new do
|
387
|
+
if empty?
|
388
|
+
self
|
389
|
+
else
|
390
|
+
tail.combinations(number - 1).map { |list| list.cons(head) }.append(tail.combinations(number))
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
394
|
+
def_delegator :self, :combinations, :combination
|
395
|
+
|
293
396
|
def eql?(other)
|
294
397
|
return false unless other.is_a?(List)
|
295
398
|
|
@@ -301,20 +404,21 @@ module Hamster
|
|
301
404
|
list = list.tail
|
302
405
|
other = other.tail
|
303
406
|
end
|
304
|
-
|
407
|
+
|
408
|
+
other.empty? && list.empty?
|
305
409
|
end
|
306
|
-
|
410
|
+
def_delegator :self, :eql?, :==
|
307
411
|
|
308
412
|
def dup
|
309
413
|
self
|
310
414
|
end
|
311
|
-
|
415
|
+
def_delegator :self, :dup, :clone
|
312
416
|
|
313
417
|
def to_a
|
314
418
|
reduce([]) { |a, item| a << item }
|
315
419
|
end
|
316
|
-
|
317
|
-
|
420
|
+
def_delegator :self, :to_a, :to_ary
|
421
|
+
def_delegator :self, :to_a, :entries
|
318
422
|
|
319
423
|
def to_list
|
320
424
|
self
|
@@ -324,10 +428,14 @@ module Hamster
|
|
324
428
|
to_a.inspect
|
325
429
|
end
|
326
430
|
|
431
|
+
def respond_to?(name, include_private = false)
|
432
|
+
super || CADR === name
|
433
|
+
end
|
434
|
+
|
327
435
|
private
|
328
436
|
|
329
437
|
def method_missing(name, *args, &block)
|
330
|
-
if
|
438
|
+
if CADR === name
|
331
439
|
accessor($1)
|
332
440
|
else
|
333
441
|
super
|
@@ -354,7 +462,6 @@ module Hamster
|
|
354
462
|
include List
|
355
463
|
|
356
464
|
attr_reader :head, :tail
|
357
|
-
alias_method :first, :head
|
358
465
|
|
359
466
|
def initialize(head, tail = EmptyList)
|
360
467
|
@head = head
|
@@ -367,22 +474,33 @@ module Hamster
|
|
367
474
|
|
368
475
|
include List
|
369
476
|
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
def initialize(head, &tail)
|
374
|
-
@head = head
|
375
|
-
@tail = tail
|
477
|
+
def initialize(&block)
|
478
|
+
@block = block
|
376
479
|
@mutex = Mutex.new
|
377
480
|
end
|
378
481
|
|
482
|
+
def head
|
483
|
+
target.head
|
484
|
+
end
|
485
|
+
|
379
486
|
def tail
|
487
|
+
target.tail
|
488
|
+
end
|
489
|
+
|
490
|
+
def empty?
|
491
|
+
target.empty?
|
492
|
+
end
|
493
|
+
|
494
|
+
private
|
495
|
+
|
496
|
+
def target
|
380
497
|
@mutex.synchronize do
|
381
|
-
unless defined?(@
|
382
|
-
@
|
498
|
+
unless defined?(@target)
|
499
|
+
@target = @block.call
|
500
|
+
@block = nil
|
383
501
|
end
|
384
502
|
end
|
385
|
-
@
|
503
|
+
@target
|
386
504
|
end
|
387
505
|
|
388
506
|
end
|
@@ -396,7 +514,6 @@ module Hamster
|
|
396
514
|
def head
|
397
515
|
nil
|
398
516
|
end
|
399
|
-
alias_method :first, :head
|
400
517
|
|
401
518
|
def tail
|
402
519
|
self
|
@@ -405,48 +522,6 @@ module Hamster
|
|
405
522
|
def empty?
|
406
523
|
true
|
407
524
|
end
|
408
|
-
alias_method :null?, :empty?
|
409
|
-
|
410
|
-
def map
|
411
|
-
self
|
412
|
-
end
|
413
|
-
alias_method :collect, :map
|
414
|
-
|
415
|
-
def filter
|
416
|
-
self
|
417
|
-
end
|
418
|
-
alias_method :select, :filter
|
419
|
-
alias_method :find_all, :filter
|
420
|
-
|
421
|
-
def remove
|
422
|
-
self
|
423
|
-
end
|
424
|
-
alias_method :reject, :remove
|
425
|
-
alias_method :delete_if, :remove
|
426
|
-
|
427
|
-
def take_while
|
428
|
-
self
|
429
|
-
end
|
430
|
-
|
431
|
-
def take(number)
|
432
|
-
self
|
433
|
-
end
|
434
|
-
|
435
|
-
def append(other)
|
436
|
-
other
|
437
|
-
end
|
438
|
-
alias_method :concat, :append
|
439
|
-
alias_method :cat, :append
|
440
|
-
alias_method :+, :append
|
441
|
-
|
442
|
-
def zip(other)
|
443
|
-
return super unless other.empty?
|
444
|
-
self
|
445
|
-
end
|
446
|
-
|
447
|
-
def cycle
|
448
|
-
self
|
449
|
-
end
|
450
525
|
|
451
526
|
end
|
452
527
|
|