immutable 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +8 -4
- data/lib/immutable.rb +10 -6
- data/lib/immutable/consable.rb +8 -2
- data/lib/immutable/foldable.rb +2 -2
- data/lib/immutable/headable.rb +130 -5
- data/lib/immutable/map.rb +3 -0
- data/lib/immutable/stream.rb +2 -0
- data/test/immutable/test_list.rb +156 -2
- data/test/immutable/test_map.rb +5 -0
- data/test/immutable/test_stream.rb +37 -0
- data/test/test_helper.rb +12 -8
- metadata +46 -56
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b88830d271351b2eb0b7580fc69e71beb7233165
|
4
|
+
data.tar.gz: ea7083277f60f1c54ae3bb41d9661f7d78186050
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c407518f109f1fc47c2ee3ce6370e762a2207516007117f15877d8038d2ef8fdcb3c9dff0afd53f89271ba640a6ed738c064ccce62b30d75fa073041bef379b1
|
7
|
+
data.tar.gz: c082da1cddcbdb9a72161f9f7750df331f7794953feca638b7ed928ba3617d20a8eec5dba837dc6d6efaa0074ee5ced23c6d8e3937c392c283189e6e18d18376
|
data/README.md
CHANGED
@@ -3,18 +3,22 @@ immutable - immutable data structures for Ruby
|
|
3
3
|
|
4
4
|
This project aims to provide immutable data structures for Ruby.
|
5
5
|
|
6
|
+
[![Build Status](https://secure.travis-ci.org/shugo/immutable.png)](http://travis-ci.org/shugo/immutable)
|
7
|
+
|
6
8
|
Install
|
7
|
-
|
9
|
+
-------
|
8
10
|
|
9
|
-
|
11
|
+
```bash
|
12
|
+
$ gem install immutable
|
13
|
+
```
|
10
14
|
|
11
15
|
Documentation
|
12
|
-
|
16
|
+
-------------
|
13
17
|
|
14
18
|
* [API Reference](http://rubydoc.info/github/shugo/immutable/frames)
|
15
19
|
|
16
20
|
License
|
17
|
-
|
21
|
+
-------
|
18
22
|
|
19
23
|
(The MIT License)
|
20
24
|
|
data/lib/immutable.rb
CHANGED
@@ -2,11 +2,13 @@
|
|
2
2
|
module Immutable
|
3
3
|
end
|
4
4
|
|
5
|
-
|
6
|
-
RubyVM::InstructionSequence.compile_option
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
if defined?(RubyVM)
|
6
|
+
old_compile_option = RubyVM::InstructionSequence.compile_option
|
7
|
+
RubyVM::InstructionSequence.compile_option = {
|
8
|
+
:tailcall_optimization => true,
|
9
|
+
:trace_instruction => false
|
10
|
+
}
|
11
|
+
end
|
10
12
|
begin
|
11
13
|
require_relative "immutable/list"
|
12
14
|
require_relative "immutable/map"
|
@@ -16,5 +18,7 @@ begin
|
|
16
18
|
require_relative "immutable/output_restricted_deque"
|
17
19
|
require_relative "immutable/deque"
|
18
20
|
ensure
|
19
|
-
RubyVM
|
21
|
+
if defined?(RubyVM)
|
22
|
+
RubyVM::InstructionSequence.compile_option = old_compile_option
|
23
|
+
end
|
20
24
|
end
|
data/lib/immutable/consable.rb
CHANGED
@@ -180,7 +180,7 @@ module Immutable
|
|
180
180
|
#
|
181
181
|
# @return [Consable] the concatenated +Consable+ object.
|
182
182
|
def flatten
|
183
|
-
foldr(empty) { |x, xs| x
|
183
|
+
foldr(empty) { |x, xs| safe_append(x, xs) }
|
184
184
|
end
|
185
185
|
|
186
186
|
alias concat flatten
|
@@ -190,7 +190,7 @@ module Immutable
|
|
190
190
|
#
|
191
191
|
# @return [Consable] the obtained +Consable+ object.
|
192
192
|
def flat_map
|
193
|
-
foldr(empty) { |x, xs| yield(x)
|
193
|
+
foldr(empty) { |x, xs| safe_append(yield(x), xs) }
|
194
194
|
end
|
195
195
|
|
196
196
|
alias concat_map flat_map
|
@@ -340,5 +340,11 @@ module Immutable
|
|
340
340
|
def Cons(x, y)
|
341
341
|
y.cons(x)
|
342
342
|
end
|
343
|
+
|
344
|
+
def safe_append(xs, ys)
|
345
|
+
xs.foldr(ys) { |z, zs| Cons(z, zs) }
|
346
|
+
rescue NoMethodError
|
347
|
+
Cons(xs, ys)
|
348
|
+
end
|
343
349
|
end
|
344
350
|
end
|
data/lib/immutable/foldable.rb
CHANGED
@@ -26,14 +26,14 @@ module Immutable
|
|
26
26
|
#
|
27
27
|
# @return [#+] the sum of the numbers.
|
28
28
|
def sum
|
29
|
-
foldl(0,
|
29
|
+
foldl(0) { |x, y| x + y }
|
30
30
|
end
|
31
31
|
|
32
32
|
# Computes the product of the numbers in +self+.
|
33
33
|
#
|
34
34
|
# @return [#*] the product of the numbers.
|
35
35
|
def product
|
36
|
-
foldl(1,
|
36
|
+
foldl(1) { |x, y| x * y }
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
data/lib/immutable/headable.rb
CHANGED
@@ -70,6 +70,8 @@ module Immutable
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
+
alias to_s inspect
|
74
|
+
|
73
75
|
# Returns whether +self+ equals to +x+.
|
74
76
|
#
|
75
77
|
# @param [Object] x the object to compare.
|
@@ -119,10 +121,21 @@ module Immutable
|
|
119
121
|
self
|
120
122
|
end
|
121
123
|
|
124
|
+
# Calls +block+ once for each index in +self+.
|
125
|
+
# @yield [index]
|
126
|
+
# @yieldparam [Integer] index
|
127
|
+
# @yieldreturn [self]
|
128
|
+
# @return [Enumerator]
|
129
|
+
def each_index
|
130
|
+
return to_enum(__callee__) unless block_given?
|
131
|
+
|
132
|
+
each_with_index{ |_, idx| yield(idx) }
|
133
|
+
end
|
134
|
+
|
122
135
|
# Reduces +self+ using +block+ from right to left. +e+ is used as the
|
123
136
|
# starting value. For example:
|
124
137
|
#
|
125
|
-
# List[1, 2, 3].foldr(9) { |x, y| x
|
138
|
+
# List[1, 2, 3].foldr(9) { |x, y| x - y } #=> 1 - (2 - (3 - 9)) = -7
|
126
139
|
#
|
127
140
|
# @param [Object] e the start value.
|
128
141
|
# @return [Object] the reduced value.
|
@@ -153,7 +166,7 @@ module Immutable
|
|
153
166
|
# Reduces +self+ using +block+ from left to right. +e+ is used as the
|
154
167
|
# starting value. For example:
|
155
168
|
#
|
156
|
-
# List[1, 2, 3].foldl(9) { |x, y| x
|
169
|
+
# List[1, 2, 3].foldl(9) { |x, y| x - y } #=> ((9 - 1) - 2) - 3 = 3
|
157
170
|
#
|
158
171
|
# @param [Object] e the start value.
|
159
172
|
# @return [Object] the reduced value.
|
@@ -208,15 +221,127 @@ module Immutable
|
|
208
221
|
# Returns the +n+th element of +self+. If +n+ is out of range, +nil+ is
|
209
222
|
# returned.
|
210
223
|
#
|
224
|
+
# @param [Integer, #to_int] n
|
211
225
|
# @return [Object] the +n+th element.
|
212
226
|
def [](n)
|
213
|
-
|
227
|
+
raise TypeError unless n.respond_to?(:to_int)
|
228
|
+
int = n.to_int
|
229
|
+
|
230
|
+
if int < 0 || empty?
|
214
231
|
nil
|
215
|
-
elsif
|
232
|
+
elsif int == 0
|
216
233
|
head
|
217
234
|
else
|
218
|
-
tail[
|
235
|
+
tail[int - 1]
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
alias at []
|
240
|
+
|
241
|
+
# Returns the +n+th element of +self+. If +n+ is out of range, +IndexError+
|
242
|
+
# returned.
|
243
|
+
#
|
244
|
+
# @overload fetch(n)
|
245
|
+
# @param [Integer, #to_int] n
|
246
|
+
# @return [Object] the +n+th element.
|
247
|
+
# @raise [IndexError] if n is out of rage
|
248
|
+
# @overload fetch(n, ifnone)
|
249
|
+
# @param [Integer, #to_int] n
|
250
|
+
# @return ifnone
|
251
|
+
# @overload fetch(n) {|n|}
|
252
|
+
# @param [Integer, #to_int] n
|
253
|
+
# @yield [n]
|
254
|
+
# @yieldparam [Integer, #to_int] n
|
255
|
+
def fetch(*args)
|
256
|
+
alen = args.length
|
257
|
+
n, ifnone = *args
|
258
|
+
|
259
|
+
unless (1..2).cover?(alen)
|
260
|
+
raise ArgumentError, "wrong number of arguments (#{alen} for 1..2)"
|
219
261
|
end
|
262
|
+
|
263
|
+
raise TypeError unless n.respond_to?(:to_int)
|
264
|
+
int = n.to_int
|
265
|
+
|
266
|
+
return at(int) if int >= 0 && int < length
|
267
|
+
|
268
|
+
if block_given?
|
269
|
+
if alen == 2
|
270
|
+
warn "#{__LINE__}:warning: block supersedes default value argument"
|
271
|
+
end
|
272
|
+
|
273
|
+
yield n
|
274
|
+
else
|
275
|
+
if alen == 2
|
276
|
+
ifnone
|
277
|
+
else
|
278
|
+
raise IndexError, "index #{int} outside of list bounds"
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
# @overload index(val)
|
284
|
+
# @return [Integer, nil] index
|
285
|
+
# @overload index
|
286
|
+
# @return [Enumerator]
|
287
|
+
# @overload index {}
|
288
|
+
# @yieldreturn [Integer, nil] index
|
289
|
+
def index(*args)
|
290
|
+
alen = args.length
|
291
|
+
val = args.first
|
292
|
+
|
293
|
+
raise ArgumentError unless (0..1).cover?(alen)
|
294
|
+
return to_enum(__callee__) if !block_given? && alen == 0
|
295
|
+
|
296
|
+
if alen == 1
|
297
|
+
if block_given?
|
298
|
+
warn "#{__LINE__}:warning: given block not used"
|
299
|
+
end
|
300
|
+
|
301
|
+
each_with_index { |e, idx|
|
302
|
+
return idx if e == val
|
303
|
+
}
|
304
|
+
else
|
305
|
+
if block_given?
|
306
|
+
each_with_index { |e, idx|
|
307
|
+
return idx if yield(e)
|
308
|
+
}
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
nil
|
313
|
+
end
|
314
|
+
|
315
|
+
# @overload rindex(val)
|
316
|
+
# @return [Integer, nil] index
|
317
|
+
# @overload rindex
|
318
|
+
# @return [Enumerator]
|
319
|
+
# @overload rindex {}
|
320
|
+
# @yieldreturn [Integer, nil] index
|
321
|
+
def rindex(*args)
|
322
|
+
alen = args.length
|
323
|
+
val = args.first
|
324
|
+
|
325
|
+
raise ArgumentError unless (0..1).cover?(alen)
|
326
|
+
return to_enum(__callee__) if !block_given? && alen == 0
|
327
|
+
|
328
|
+
if alen == 1
|
329
|
+
if block_given?
|
330
|
+
warn "#{__LINE__}:warning: given block not used"
|
331
|
+
end
|
332
|
+
|
333
|
+
reverse_each.with_index { |e, idx|
|
334
|
+
return length - (idx + 1) if e == val
|
335
|
+
}
|
336
|
+
else
|
337
|
+
if block_given?
|
338
|
+
reverse_each.with_index { |e, idx|
|
339
|
+
return length - (idx + 1) if yield(e)
|
340
|
+
}
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
nil
|
220
345
|
end
|
221
346
|
|
222
347
|
# Converts +self+ to a list.
|
data/lib/immutable/map.rb
CHANGED
@@ -66,6 +66,7 @@ module Immutable
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
+
# @return [String]
|
69
70
|
def inspect
|
70
71
|
"Map[" + foldr_with_key("") { |k, v, s|
|
71
72
|
x = k.inspect + " => " + v.inspect
|
@@ -77,6 +78,8 @@ module Immutable
|
|
77
78
|
} + "]"
|
78
79
|
end
|
79
80
|
|
81
|
+
alias to_s inspect
|
82
|
+
|
80
83
|
# Calls +block+ once for each key/value in +self+.
|
81
84
|
def each(&block)
|
82
85
|
foldl_with_key(nil) { |x, k, v| yield([k, v]) }
|
data/lib/immutable/stream.rb
CHANGED
data/test/immutable/test_list.rb
CHANGED
@@ -14,7 +14,7 @@ module Immutable
|
|
14
14
|
def test_s_from_enum
|
15
15
|
assert_equal(List[], List.from_enum([]))
|
16
16
|
assert_equal(List[1, 2, 3], List.from_enum(1..3))
|
17
|
-
assert_equal(List["a", "b", "c"], List.from_enum("abc".
|
17
|
+
assert_equal(List["a", "b", "c"], List.from_enum("abc".each_char))
|
18
18
|
end
|
19
19
|
|
20
20
|
def test_head
|
@@ -76,6 +76,84 @@ module Immutable
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
+
def test_each_index
|
80
|
+
list = List[]
|
81
|
+
a = []
|
82
|
+
assert_same(list, list.each_index { |x| a << x })
|
83
|
+
assert_equal([], a)
|
84
|
+
|
85
|
+
list = List[1, 2, 3]
|
86
|
+
a = []
|
87
|
+
assert_same(list, list.each_index { |x| a << x })
|
88
|
+
assert_equal([0, 1, 2], a)
|
89
|
+
|
90
|
+
enum = List[1, 2, 3].each_index
|
91
|
+
assert_instance_of(Enumerator, enum)
|
92
|
+
assert_equal(0, enum.next)
|
93
|
+
assert_equal(1, enum.next)
|
94
|
+
assert_equal(2, enum.next)
|
95
|
+
assert_raise(StopIteration) do
|
96
|
+
enum.next
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_index
|
101
|
+
list = List[]
|
102
|
+
assert_equal(nil, list.index(1))
|
103
|
+
|
104
|
+
list = List[1, 2, 1]
|
105
|
+
assert_equal(0, list.index(1))
|
106
|
+
assert_equal(1, list.index(2))
|
107
|
+
assert_equal(nil, list.index(3))
|
108
|
+
|
109
|
+
verbose = $VERBOSE
|
110
|
+
$VERBOSE = nil
|
111
|
+
list = List[1, 2, 1]
|
112
|
+
assert_equal(0, list.index(1) {|e| e * 2 == 4 })
|
113
|
+
assert_equal(1, list.index(2) {|e| e * 2 == 4 })
|
114
|
+
assert_equal(nil, list.index(3) {|e| e * 2 == 4 })
|
115
|
+
$VERBOSE = verbose
|
116
|
+
|
117
|
+
list = List[1, 2, 1]
|
118
|
+
assert_equal(0, list.index {|e| e * 2 == 2 })
|
119
|
+
assert_equal(1, list.index {|e| e * 2 == 4 })
|
120
|
+
assert_equal(nil, list.index {|e| e * 2 == 6 })
|
121
|
+
|
122
|
+
enum = List[1, 2, 1].index
|
123
|
+
assert_instance_of(Enumerator, enum)
|
124
|
+
assert_equal(0, enum.each {|v|v == 1})
|
125
|
+
assert_equal(1, enum.each {|v|v == 2})
|
126
|
+
assert_equal(nil, enum.each {|v|v == 3})
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_rindex
|
130
|
+
list = List[]
|
131
|
+
assert_equal(nil, list.rindex(1))
|
132
|
+
|
133
|
+
list = List[1, 2, 1]
|
134
|
+
assert_equal(2, list.rindex(1))
|
135
|
+
assert_equal(1, list.rindex(2))
|
136
|
+
assert_equal(nil, list.rindex(3))
|
137
|
+
|
138
|
+
verbose = $VERBOSE
|
139
|
+
$VERBOSE = nil
|
140
|
+
list = List[1, 2, 1]
|
141
|
+
assert_equal(2, list.rindex(1) {|e| e * 2 == 4 })
|
142
|
+
assert_equal(1, list.rindex(2) {|e| e * 2 == 4 })
|
143
|
+
assert_equal(nil, list.rindex(3) {|e| e * 2 == 4 })
|
144
|
+
$VERBOSE = verbose
|
145
|
+
|
146
|
+
list = List[1, 2, 1]
|
147
|
+
assert_equal(2, list.rindex {|e| e * 2 == 2 })
|
148
|
+
assert_equal(1, list.rindex {|e| e * 2 == 4 })
|
149
|
+
assert_equal(nil, list.rindex {|e| e * 2 == 6 })
|
150
|
+
|
151
|
+
enum = List[1, 2, 1].rindex
|
152
|
+
assert_instance_of(Enumerator, enum)
|
153
|
+
assert_equal(2, enum.each {|v|v == 1})
|
154
|
+
assert_equal(nil, enum.each {|v|v == 3})
|
155
|
+
end
|
156
|
+
|
79
157
|
def test_foldr
|
80
158
|
assert_equal(0, List[].foldr(0, &:+))
|
81
159
|
assert_equal(123, List[].foldr(123, &:+))
|
@@ -154,6 +232,15 @@ module Immutable
|
|
154
232
|
List[List[1, 2], List[3, 4]].inspect)
|
155
233
|
end
|
156
234
|
|
235
|
+
def test_to_s
|
236
|
+
assert_equal('List[]', List[].to_s)
|
237
|
+
assert_equal('List[1]', List[1].to_s)
|
238
|
+
assert_equal('List["foo"]', List["foo"].to_s)
|
239
|
+
assert_equal('List[1, 2, 3]', List[1, 2, 3].to_s)
|
240
|
+
assert_equal('List[List[1, 2], List[3, 4]]',
|
241
|
+
List[List[1, 2], List[3, 4]].to_s)
|
242
|
+
end
|
243
|
+
|
157
244
|
def test_length
|
158
245
|
assert_equal(0, List[].length)
|
159
246
|
assert_equal(1, List[1].length)
|
@@ -184,6 +271,10 @@ module Immutable
|
|
184
271
|
assert_equal(List[List[1]], List[List[List[1]]].flatten)
|
185
272
|
assert_equal(List[1, 2, 3], List[List[1, 2], List[3]].flatten)
|
186
273
|
assert_equal(List[1, 2, 3], List[List[1], List[2], List[3]].flatten)
|
274
|
+
assert_equal(List[1, 2, 3], List[List[1], 2, List[3]].flatten)
|
275
|
+
assert_equal(List[1, [2], 3], List[List[1], [2], List[3]].flatten)
|
276
|
+
obj = Object.new
|
277
|
+
assert_equal(List[obj, 'str', obj], List[obj, 'str', obj].flatten)
|
187
278
|
end
|
188
279
|
|
189
280
|
def test_map
|
@@ -198,7 +289,9 @@ module Immutable
|
|
198
289
|
|
199
290
|
def test_flat_map
|
200
291
|
assert_equal(List[], List[].flat_map {})
|
201
|
-
|
292
|
+
xs = List["foo", "bar"].flat_map {|s| List.from_enum(s.each_char)}
|
293
|
+
assert_equal(List["f", "o", "o", "b", "a", "r"], xs)
|
294
|
+
xs = List["FOO", "BAR"].flat_map {|s| s.upcase}
|
202
295
|
end
|
203
296
|
|
204
297
|
def test_find
|
@@ -228,6 +321,67 @@ module Immutable
|
|
228
321
|
assert_equal(2, List[1, 2, 3][1])
|
229
322
|
assert_equal(3, List[1, 2, 3][2])
|
230
323
|
assert_equal(nil, List[1, 2, 3][3])
|
324
|
+
assert_equal(2, List[1, 2, 3][1.1])
|
325
|
+
assert_raise TypeError do
|
326
|
+
List[1, 2, 3]['1']
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
def test_at
|
331
|
+
assert_equal(nil, List[].at(0))
|
332
|
+
assert_equal(1, List[1, 2, 3].at(0))
|
333
|
+
assert_equal(nil, List[1, 2, 3].at(-1))
|
334
|
+
assert_equal(2, List[1, 2, 3].at(1))
|
335
|
+
assert_equal(3, List[1, 2, 3].at(2))
|
336
|
+
assert_equal(nil, List[1, 2, 3].at(3))
|
337
|
+
assert_equal(2, List[1, 2, 3].at(1.1))
|
338
|
+
assert_raise TypeError do
|
339
|
+
List[1, 2, 3].at('1')
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
def test_fetch
|
344
|
+
assert_raise ArgumentError do
|
345
|
+
List[].fetch
|
346
|
+
end
|
347
|
+
|
348
|
+
assert_raise IndexError do
|
349
|
+
List[].fetch(0)
|
350
|
+
end
|
351
|
+
|
352
|
+
assert_equal(1, List[1, 2, 3].fetch(0))
|
353
|
+
|
354
|
+
assert_raise IndexError do
|
355
|
+
List[1, 2, 3].fetch(-1)
|
356
|
+
end
|
357
|
+
|
358
|
+
assert_equal(2, List[1, 2, 3].fetch(1))
|
359
|
+
assert_equal(3, List[1, 2, 3].fetch(2))
|
360
|
+
|
361
|
+
assert_raise IndexError do
|
362
|
+
List[1, 2, 3].fetch(3)
|
363
|
+
end
|
364
|
+
|
365
|
+
assert_equal(2, List[1, 2, 3].fetch(1.1))
|
366
|
+
|
367
|
+
assert_raise TypeError do
|
368
|
+
List[1, 2, 3].fetch('1')
|
369
|
+
end
|
370
|
+
|
371
|
+
assert_equal(9, List[].fetch(0, 9))
|
372
|
+
assert_equal(2, List[1, 2, 3].fetch(1, 9))
|
373
|
+
assert_equal(9, List[1, 2, 3].fetch(4, 9))
|
374
|
+
|
375
|
+
assert_equal(5, List[].fetch(0) {|n| n + 5 })
|
376
|
+
assert_equal(2, List[1, 2, 3].fetch(1) {|n| n + 5 })
|
377
|
+
assert_equal(8, List[1, 2, 3].fetch(4) {|n| n * 2 })
|
378
|
+
|
379
|
+
verbose = $VERBOSE
|
380
|
+
$VERBOSE = nil
|
381
|
+
assert_equal(5, List[].fetch(0, 9) {|n| n + 5 })
|
382
|
+
assert_equal(2, List[1, 2, 3].fetch(1, 9) {|n| n + 5 })
|
383
|
+
assert_equal(8, List[1, 2, 3].fetch(4, 9) {|n| n * 2 })
|
384
|
+
$VERBOSE = verbose
|
231
385
|
end
|
232
386
|
|
233
387
|
def test_take
|
data/test/immutable/test_map.rb
CHANGED
@@ -18,6 +18,11 @@ module Immutable
|
|
18
18
|
assert_equal("Map[:a => 1, :b => 2]", Map[a: 1, b: 2].inspect)
|
19
19
|
end
|
20
20
|
|
21
|
+
def test_to_s
|
22
|
+
assert_equal("Map[]", Map.empty.to_s)
|
23
|
+
assert_equal("Map[:a => 1, :b => 2]", Map[a: 1, b: 2].to_s)
|
24
|
+
end
|
25
|
+
|
21
26
|
def test_insert
|
22
27
|
5.times do
|
23
28
|
map = (1..100).to_a.shuffle.inject(Map.empty) { |m, k|
|
@@ -196,6 +196,43 @@ module Immutable
|
|
196
196
|
s.inspect)
|
197
197
|
end
|
198
198
|
|
199
|
+
def test_to_s
|
200
|
+
s = Stream[]
|
201
|
+
assert_equal('Stream[...]', s.to_s)
|
202
|
+
assert_equal(nil, s[0])
|
203
|
+
assert_equal('Stream[]', s.to_s)
|
204
|
+
s = Stream[1]
|
205
|
+
assert_equal('Stream[...]', s.to_s)
|
206
|
+
assert_equal(1, s[0])
|
207
|
+
assert_equal('Stream[1, ...]', s.to_s)
|
208
|
+
assert_equal(nil, s[1])
|
209
|
+
assert_equal('Stream[1]', s.to_s)
|
210
|
+
s = Stream["foo"]
|
211
|
+
assert_equal("foo", s[0])
|
212
|
+
assert_equal('Stream["foo", ...]', s.to_s)
|
213
|
+
assert_equal(nil, s[1])
|
214
|
+
assert_equal('Stream["foo"]', s.to_s)
|
215
|
+
s = Stream[1, 2, 3]
|
216
|
+
assert_equal('Stream[...]', s.to_s)
|
217
|
+
assert_equal(1, s[0])
|
218
|
+
assert_equal('Stream[1, ...]', s.to_s)
|
219
|
+
assert_equal(2, s[1])
|
220
|
+
assert_equal('Stream[1, 2, ...]', s.to_s)
|
221
|
+
assert_equal(3, s[2])
|
222
|
+
assert_equal('Stream[1, 2, 3, ...]', s.to_s)
|
223
|
+
assert_equal(nil, s[3])
|
224
|
+
assert_equal('Stream[1, 2, 3]', s.to_s)
|
225
|
+
s = Stream[1, 2, 3]
|
226
|
+
assert_equal(2, s[1])
|
227
|
+
assert_equal('Stream[?, 2, ...]', s.to_s)
|
228
|
+
s = Stream[Stream[1, 2], Stream[3, 4]]
|
229
|
+
assert_equal(Stream[1, 2], s[0])
|
230
|
+
assert_equal(Stream[3, 4], s[1])
|
231
|
+
assert_equal(nil, s[2])
|
232
|
+
assert_equal('Stream[Stream[1, 2], Stream[3, 4]]',
|
233
|
+
s.to_s)
|
234
|
+
end
|
235
|
+
|
199
236
|
def test_length
|
200
237
|
assert_equal(0, Stream[].length)
|
201
238
|
assert_equal(1, Stream[1].length)
|
data/test/test_helper.rb
CHANGED
@@ -3,14 +3,18 @@ $VERBOSE = true
|
|
3
3
|
require "test/unit"
|
4
4
|
|
5
5
|
def with_tailcall_optimization
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
if defined?(RubyVM)
|
7
|
+
old_compile_option = RubyVM::InstructionSequence.compile_option
|
8
|
+
RubyVM::InstructionSequence.compile_option = {
|
9
|
+
:tailcall_optimization => true,
|
10
|
+
:trace_instruction => false
|
11
|
+
}
|
12
|
+
begin
|
13
|
+
yield
|
14
|
+
ensure
|
15
|
+
RubyVM::InstructionSequence.compile_option = old_compile_option
|
16
|
+
end
|
17
|
+
else
|
12
18
|
yield
|
13
|
-
ensure
|
14
|
-
RubyVM::InstructionSequence.compile_option = old_compile_option
|
15
19
|
end
|
16
20
|
end
|
metadata
CHANGED
@@ -1,76 +1,66 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: immutable
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
version: 0.3.1
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.2
|
6
5
|
platform: ruby
|
7
|
-
authors:
|
8
|
-
|
6
|
+
authors:
|
7
|
+
- Shugo Maeda
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
|
13
|
-
date: 2012-09-07 00:00:00 Z
|
11
|
+
date: 2016-07-08 00:00:00.000000000 Z
|
14
12
|
dependencies: []
|
15
|
-
|
16
13
|
description:
|
17
14
|
email: shugo@ruby-lang.org
|
18
15
|
executables: []
|
19
|
-
|
20
16
|
extensions: []
|
21
|
-
|
22
17
|
extra_rdoc_files: []
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
- README.md
|
18
|
+
files:
|
19
|
+
- README.md
|
20
|
+
- benchmark/benchmark_deque.rb
|
21
|
+
- benchmark/benchmark_map.rb
|
22
|
+
- benchmark/benchmark_parallel_fib.rb
|
23
|
+
- benchmark/benchmark_queue.rb
|
24
|
+
- lib/immutable.rb
|
25
|
+
- lib/immutable/consable.rb
|
26
|
+
- lib/immutable/deque.rb
|
27
|
+
- lib/immutable/foldable.rb
|
28
|
+
- lib/immutable/headable.rb
|
29
|
+
- lib/immutable/list.rb
|
30
|
+
- lib/immutable/map.rb
|
31
|
+
- lib/immutable/output_restricted_deque.rb
|
32
|
+
- lib/immutable/promise.rb
|
33
|
+
- lib/immutable/queue.rb
|
34
|
+
- lib/immutable/stream.rb
|
35
|
+
- test/immutable/test_deque.rb
|
36
|
+
- test/immutable/test_list.rb
|
37
|
+
- test/immutable/test_map.rb
|
38
|
+
- test/immutable/test_promise.rb
|
39
|
+
- test/immutable/test_queue.rb
|
40
|
+
- test/immutable/test_stream.rb
|
41
|
+
- test/test_helper.rb
|
48
42
|
homepage: http://github.com/shugo/immutable
|
49
43
|
licenses: []
|
50
|
-
|
44
|
+
metadata: {}
|
51
45
|
post_install_message:
|
52
46
|
rdoc_options: []
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
- - ">="
|
66
|
-
- !ruby/object:Gem::Version
|
67
|
-
version: "0"
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
68
59
|
requirements: []
|
69
|
-
|
70
60
|
rubyforge_project:
|
71
|
-
rubygems_version:
|
61
|
+
rubygems_version: 2.5.1
|
72
62
|
signing_key:
|
73
|
-
specification_version:
|
63
|
+
specification_version: 4
|
74
64
|
summary: Immutable data structures for Ruby
|
75
65
|
test_files: []
|
76
|
-
|
66
|
+
has_rdoc:
|