fr 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/README.md +0 -0
  2. data/Rakefile +81 -0
  3. data/lib/fr.rb +44 -0
  4. data/lib/fr/applicative.rb +0 -0
  5. data/lib/fr/array.rb +168 -0
  6. data/lib/fr/boolean.rb +15 -0
  7. data/lib/fr/either.rb +94 -0
  8. data/lib/fr/errors.rb +5 -0
  9. data/lib/fr/errors/zipper_error.rb +8 -0
  10. data/lib/fr/functor.rb +11 -0
  11. data/lib/fr/functor/array.rb +15 -0
  12. data/lib/fr/functor/either.rb +17 -0
  13. data/lib/fr/functor/maybe.rb +17 -0
  14. data/lib/fr/maybe.rb +76 -0
  15. data/lib/fr/monad.rb +236 -0
  16. data/lib/fr/monad/array.rb +21 -0
  17. data/lib/fr/monad/either.rb +18 -0
  18. data/lib/fr/monad/maybe.rb +24 -0
  19. data/lib/fr/monad/random.rb +50 -0
  20. data/lib/fr/monad/reader.rb +45 -0
  21. data/lib/fr/monad/state.rb +62 -0
  22. data/lib/fr/monad/writer.rb +49 -0
  23. data/lib/fr/monoid.rb +52 -0
  24. data/lib/fr/monoid/array.rb +13 -0
  25. data/lib/fr/monoid/boolean.rb +23 -0
  26. data/lib/fr/monoid/either.rb +13 -0
  27. data/lib/fr/monoid/maybe.rb +15 -0
  28. data/lib/fr/monoid/numeric.rb +31 -0
  29. data/lib/fr/monoid/string.rb +11 -0
  30. data/lib/fr/numeric.rb +1 -0
  31. data/lib/fr/object.rb +45 -0
  32. data/lib/fr/string.rb +1 -0
  33. data/lib/fr/szipper.rb +36 -0
  34. data/lib/fr/szipper/abstract_cursor.rb +63 -0
  35. data/lib/fr/szipper/edited_cursor.rb +62 -0
  36. data/lib/fr/szipper/enumerable.rb +266 -0
  37. data/lib/fr/szipper/head_cursor.rb +71 -0
  38. data/lib/fr/szipper/head_prev_cursor.rb +112 -0
  39. data/lib/fr/szipper/memoized_cursor.rb +59 -0
  40. data/lib/fr/szipper/node.rb +67 -0
  41. data/lib/fr/szipper/tail_next_cursor.rb +68 -0
  42. data/lib/fr/thunk.rb +73 -0
  43. data/lib/fr/tzipper.rb +38 -0
  44. data/lib/fr/tzipper/abstract_cursor.rb +351 -0
  45. data/lib/fr/tzipper/dangling_cursor.rb +107 -0
  46. data/lib/fr/tzipper/edited_cursor.rb +161 -0
  47. data/lib/fr/tzipper/memoized_cursor.rb +129 -0
  48. data/lib/fr/tzipper/node.rb +57 -0
  49. data/lib/fr/tzipper/path.rb +125 -0
  50. data/lib/fr/tzipper/root_cursor.rb +124 -0
  51. data/lib/fr/unfold.rb +93 -0
  52. data/spec/examples/array.example +0 -0
  53. data/spec/examples/monads/array.example +0 -0
  54. data/spec/examples/monads/maybe.example +0 -0
  55. data/spec/examples/monads/random.example +0 -0
  56. data/spec/examples/monads/state.example +0 -0
  57. data/spec/examples/szipper.example +652 -0
  58. data/spec/examples/thunk.example +0 -0
  59. data/spec/examples/tzipper.example +0 -0
  60. data/spec/examples/unfold.example +90 -0
  61. data/spec/spec_helper.rb +23 -0
  62. data/spec/support/szipper/model.rb +225 -0
  63. data/spec/support/szipper/nodel.rb +144 -0
  64. metadata +116 -0
@@ -0,0 +1,125 @@
1
+ module Fr
2
+ module TZipper
3
+
4
+ class AbstractPath
5
+
6
+ # @return [AbstractPath]
7
+ # abstract :parent
8
+
9
+ # Contains the node's leftward siblings, sorted nearest to furthest
10
+ #
11
+ # @return [Array<#leaf?, #children, #copy>]
12
+ # abstract :left
13
+
14
+ # Contains the node's rightward siblings, sorted nearest to furthest
15
+ #
16
+ # @return [Array<#leaf?, #children, #copy>]
17
+ # abstract :right
18
+
19
+ # True when the node has no rightward siblings
20
+ # abstract :last?
21
+
22
+ # True when the node has no leftward siblings
23
+ # abstract :first?
24
+
25
+ # Distance from the root node
26
+ #
27
+ # @return [Integer]
28
+ # abstract :depth
29
+ end
30
+
31
+ # @private
32
+ Root = Class.new(AbstractPath) do
33
+
34
+ # @return self
35
+ def parent
36
+ self
37
+ end
38
+
39
+ # (see AbstractPath#left)
40
+ def left
41
+ []
42
+ end
43
+
44
+ # (see AbstractPath#right)
45
+ def right
46
+ []
47
+ end
48
+
49
+ # (see AbstractPath#last?)
50
+ # @return true
51
+ def last?
52
+ true
53
+ end
54
+
55
+ # (see AbstractPath#first?)
56
+ # @return true
57
+ def first?
58
+ true
59
+ end
60
+
61
+ # (see AbstractPath#depth)
62
+ def depth
63
+ 0
64
+ end
65
+
66
+ def position
67
+ nil
68
+ end
69
+
70
+ # @return [String]
71
+ def inspect
72
+ "root"
73
+ end
74
+ end.new
75
+
76
+ class Hole < AbstractPath
77
+
78
+ # (see AbstractPath#right)
79
+ attr_reader :left
80
+
81
+ # @return [AbstractPath]
82
+ attr_reader :parent
83
+
84
+ # (see AbstractPath#left)
85
+ attr_reader :right
86
+
87
+ def initialize(left, parent, right)
88
+ @left, @parent, @right =
89
+ left, parent, right
90
+ end
91
+
92
+ # (see AbstractPath#last?)
93
+ def last?
94
+ @right.empty?
95
+ end
96
+
97
+ # (see AbstractPath#first?)
98
+ def first?
99
+ @left.empty?
100
+ end
101
+
102
+ # (see AbstractPath#depth)
103
+ def depth
104
+ 1 + @parent.depth
105
+ end
106
+
107
+ def position
108
+ @left.length
109
+ end
110
+
111
+ # @return [String]
112
+ def inspect
113
+ "#{@parent.inspect}/#{@left.length}"
114
+ end
115
+
116
+ # @return [Boolean]
117
+ def ==(other)
118
+ AbstractCursor === other and
119
+ depth == other.depth and
120
+ position == other.position
121
+ end
122
+ end
123
+
124
+ end
125
+ end
@@ -0,0 +1,124 @@
1
+ module Fr
2
+ module TZipper
3
+
4
+ class RootCursor < AbstractCursor
5
+
6
+ # @return [AbstractNode]
7
+ attr_reader :node
8
+
9
+ # @return [AbstractPath]
10
+ attr_reader :path
11
+
12
+ def initialize(node)
13
+ @node, @path =
14
+ node, Root
15
+ end
16
+
17
+ # @group Query the Tree Location
18
+ #########################################################################
19
+
20
+ # (see AbstractCursor#depth)
21
+ def depth
22
+ 0
23
+ end
24
+
25
+ # (see AbstractCursor#first?)
26
+ def first?
27
+ true
28
+ end
29
+
30
+ # (see AbstractCursor#last?)
31
+ def last?
32
+ true
33
+ end
34
+
35
+ # (see AbstractCursor#leaf?)
36
+ def leaf?
37
+ @node.leaf? or @node.children.empty?
38
+ end
39
+
40
+ # (see AbstractCursor#root?)
41
+ def root?
42
+ true
43
+ end
44
+
45
+ # @group Traversing the Tree
46
+ #########################################################################
47
+
48
+ # (see AbstractCursor#first)
49
+ def first
50
+ self
51
+ end
52
+
53
+ # (see AbstractCursor#last)
54
+ def last
55
+ self
56
+ end
57
+
58
+ # (see AbstractCursor#next)
59
+ # @return [void]
60
+ def next
61
+ raise Errors::ZipperError,
62
+ "root node has no siblings"
63
+ end
64
+
65
+ # (see AbstractCursor#prev)
66
+ # @return [void]
67
+ def prev
68
+ raise Errors::ZipperError,
69
+ "root node has no siblings"
70
+ end
71
+
72
+ # (see AbstractCursor#root)
73
+ # @return [RootCursor]
74
+ def root
75
+ self
76
+ end
77
+
78
+ # (see AbstractCursor#up)
79
+ # @return [void]
80
+ def up
81
+ raise Errors::ZipperError,
82
+ "root node has no parent"
83
+ end
84
+
85
+ # @group Editing the Tree
86
+ #########################################################################
87
+
88
+ # (see AbstractCursor#append)
89
+ # @return [void]
90
+ def append(node)
91
+ raise Errors::ZipperError,
92
+ "root node has no siblings"
93
+ end
94
+
95
+ # (see AbstractCursor#prepend)
96
+ # @return [void]
97
+ def prepend(node)
98
+ raise Errors::ZipperError,
99
+ "root node has no siblings"
100
+ end
101
+
102
+ # (see AbstractCursor#replace)
103
+ # @return [RootCursor]
104
+ def replace(node)
105
+ RootCursor.new(node)
106
+ end
107
+
108
+ # (see AbstractCursor#delete)
109
+ # @return [void]
110
+ def delete
111
+ raise Errors::ZipperError,
112
+ "cannot delete root node"
113
+ end
114
+
115
+ # @endgroup
116
+ #########################################################################
117
+
118
+ def inspect
119
+ "Cursor(Root, #{@node.inspect})"
120
+ end
121
+ end
122
+
123
+ end
124
+ end
data/lib/fr/unfold.rb ADDED
@@ -0,0 +1,93 @@
1
+ class << Array
2
+ # Recursive version
3
+ def unfold(seed, &block)
4
+ m = yield(seed)
5
+ m.fold([]){|(item, seed)| [item] + unfold(seed, &block) }
6
+ end
7
+
8
+ # First generated element is first in Array
9
+ def unfold(seed)
10
+ [].tap do |xs|
11
+ while true
12
+ yield(seed).fold(false) do |(item,seed_)|
13
+ xs << item
14
+ seed = seed_
15
+ end || break
16
+ end
17
+ end
18
+ end
19
+
20
+ # First generated element is last in Array
21
+ def unfoldR(seed, &block)
22
+ m = yield(seed)
23
+ m.fold([]){|(item, seed)| unfold(seed, &block) + [item] }
24
+ end
25
+
26
+ # First generated element is last in Array
27
+ def unfoldR(seed)
28
+ [].tap do |xs|
29
+ while true
30
+ yield(seed).fold(false) do |(item,seed_)|
31
+ xs.unshift(item)
32
+ seed = seed_
33
+ end || break
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ class << Hash
40
+ # Recursive version
41
+ def unfold(seed, &block)
42
+ m = yield(seed)
43
+ m.fold({}){|(item, seed)| unfold(seed, &block).merge(item) }
44
+ end
45
+
46
+ # Iterative version
47
+ def unfold(seed)
48
+ {}.tap do |xs|
49
+ while true
50
+ yield(seed).fold(false) do |(item,seed_)|
51
+ xs.update(item)
52
+ seed = seed_
53
+ end || break
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ class Set; end
60
+ class << Set
61
+ # Recursive version
62
+ def unfold(seed, &block)
63
+ m = yield(seed)
64
+ m.fold(Set.new){|(item, seed)| unfold(seed, &block) << item }
65
+ end
66
+
67
+ # Iterative version
68
+ def unfold(seed)
69
+ Set.new.tap do |xs|
70
+ while true
71
+ yield(seed).fold(false) do |(item,seed_)|
72
+ xs << item
73
+ seed = seed_
74
+ end || break
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ class << Enumerator
81
+ # First generated element is first in Enumerator
82
+ def unfold(seed)
83
+ Enumerator.new do |yielder|
84
+ while true
85
+ yield(seed).fold(false) do |(item,seed_)|
86
+ yielder.yield item
87
+ seed = seed_
88
+ true
89
+ end || break
90
+ end
91
+ end
92
+ end
93
+ end
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,652 @@
1
+ require "spec_helper"
2
+
3
+ describe Fr::SZipper do
4
+
5
+ let(:z) { Fr::SZipper }
6
+ let(:n) { Fr::SZipper::Node }
7
+
8
+ describe ".build(enum)" do
9
+ context "empty" do
10
+ subject { z.build }
11
+
12
+ it { should be_head }
13
+ it { should be_tail }
14
+ it { should be_empty }
15
+ it { should_not respond_to(:node) }
16
+ end
17
+
18
+ context "non-empty" do
19
+ subject { z.build(n.new("x")) }
20
+
21
+ it { should be_head }
22
+ it { should_not be_empty }
23
+ it { should respond_to(:node) }
24
+ end
25
+ end
26
+
27
+ describe "#head?" do
28
+ subject { z.build(n.build(%w(x y z))) }
29
+
30
+ # The first element (or empty zipper)
31
+ specify { subject.should be_head }
32
+ specify { z.build.should be_head }
33
+ specify { z.build.prev(true).should be_head }
34
+ specify { z.build.next(true).should be_head }
35
+
36
+ # Other elements
37
+ specify { subject.prev(true).should_not be_head }
38
+ specify { subject.next.should_not be_head }
39
+ specify { subject.next.next.should_not be_head }
40
+ specify { subject.next.next.next(true).should_not be_head }
41
+ end
42
+
43
+ describe "#head" do
44
+ let(:x) { n.build(%w(x y z)) }
45
+ subject { z.build(x) }
46
+
47
+ # Empty sequence has no head element
48
+ specify { expect { n.build.head }.to raise_error }
49
+ specify { expect { n.build.prev(true).head }.to raise_error }
50
+ specify { expect { n.build.next(true).head }.to raise_error }
51
+
52
+ # The first element
53
+ specify { subject.head.should eql(subject) }
54
+ specify { subject.head.node.should eql(x) }
55
+
56
+ # Other elements
57
+ specify { subject.prev(true).head.node.should eql(x) }
58
+ specify { subject.next.head.node.should eql(x) }
59
+ specify { subject.next.next.head.node.should eql(x) }
60
+ specify { subject.next.next.next(true).head.node.should eql(x) }
61
+ end
62
+
63
+ describe "#tail?" do
64
+ subject { z.build(n.build(%w(x y z))) }
65
+
66
+ # The last element
67
+ specify { subject.next.next.should be_tail }
68
+ specify { z.build.should be_tail }
69
+ specify { z.build.prev(true).should be_tail }
70
+ specify { z.build.next(true).should be_tail }
71
+
72
+ # Other elements
73
+ specify { subject.should_not be_tail }
74
+ specify { subject.prev(true).should_not be_tail }
75
+ specify { subject.next.should_not be_tail }
76
+ specify { subject.next.next.next(true).should_not be_tail }
77
+ end
78
+
79
+ describe "#tail" do
80
+ let(:x) { n.build(%w(x y z)) }
81
+ subject { z.build(x) }
82
+
83
+ # Empty sequence has no tail element
84
+ specify { expect { z.build.tail }.to raise_error }
85
+
86
+ # Tail element
87
+ specify { subject.tail.should be_tail }
88
+ specify { subject.next.next.tail.node.should eql(x.next.next) }
89
+ specify { subject.next.next.tail.should eql(subject.next.next) }
90
+
91
+ # Other elements
92
+ specify { subject.tail.node.should eql(x.next.next) }
93
+ specify { subject.prev(true).tail.node.should eql(x.next.next) }
94
+ specify { subject.next.tail.node.should eql(x.next.next) }
95
+ specify { subject.next.next.next(true).tail.node.should eql(x.next.next) }
96
+ end
97
+
98
+ describe "#position" do
99
+ subject { z.build(n.build(%w(x y z))) }
100
+
101
+ # Empty sequence
102
+ specify { z.build.position.should == -1 }
103
+
104
+ # Non-empty sequence
105
+ specify { subject.prev(true).position.should == -1 }
106
+ specify { subject.position.should == 0 }
107
+ specify { subject.next.position.should == 1 }
108
+ specify { subject.next.next.position.should == 2 }
109
+ specify { subject.next.next.next(true).position.should == 3 }
110
+ end
111
+
112
+ describe "#empty?" do
113
+ subject { z.build(n.build(%w(x y z))) }
114
+
115
+ # True if no current or following elements
116
+ specify { z.build.should be_empty }
117
+ specify { subject.tail.next(true).should be_empty }
118
+
119
+ # False when on an element or elements follow
120
+ specify { subject.should_not be_empty }
121
+ specify { subject.next.should_not be_empty }
122
+ specify { subject.next.next.should_not be_empty }
123
+ specify { subject.prev(true).should_not be_empty }
124
+ end
125
+
126
+ describe "#prev" do
127
+ let(:x) { n.build(%w(x y z)) }
128
+ subject { z.build(x) }
129
+
130
+ # head.prev is ill-defined
131
+ specify { expect { z.build.prev }.to raise_error }
132
+ specify { expect { subject.prev }.to raise_error }
133
+
134
+ # Empty sequence has no previous element
135
+ specify { z.build.prev(true).should == z.build }
136
+
137
+ # Non-empty sequence
138
+ specify { subject.prev(true).should_not respond_to(:node) }
139
+ specify { subject.tail.prev.node.should eql(x.next) }
140
+ specify { subject.tail.prev.prev.node.should eql(x) }
141
+ end
142
+
143
+ describe "#next" do
144
+ let(:x) { n.build(%w(x y z)) }
145
+ subject { z.build(x) }
146
+
147
+ # tail.next is ill-defined
148
+ specify { expect { z.build.next }.to raise_error }
149
+ specify { expect { subject.tail.next }.to raise_error }
150
+
151
+ # Empty sequence has no next element
152
+ specify { z.build.next(true).should == z.build }
153
+
154
+ # Non-empty sequence
155
+ specify { subject.next.node.should eql(x.next) }
156
+ specify { subject.prev(true).next.node.should eql(x) }
157
+ specify { subject.next.next.node.should eql(x.next.next) }
158
+ specify { subject.next.next.next(true).should_not respond_to(:node) }
159
+ specify { subject.tail.next(true).next(true).should_not respond_to(:node) }
160
+ end
161
+
162
+ describe "#append(node)" do
163
+ let(:x) { n.build(%w(x y z)) }
164
+ subject { z.build(x) }
165
+
166
+ context "on empty stream" do
167
+ # Positioned at newly inserted node
168
+ specify { z.build.append(n.new("_")).node.value.should == "_" }
169
+ specify { z.build.append(n.new("_")).should be_head }
170
+ specify { z.build.append(n.new("_")).should be_tail }
171
+ end
172
+
173
+ context "at head" do
174
+ # Positioned at newly inserted node
175
+ specify { subject.append(n.new("_")).should_not be_head }
176
+ specify { subject.append(n.new("_")).node.value.should == "_" }
177
+ specify { subject.append(n.new("_")).prev.node.value.should == "x" }
178
+ specify { subject.append(n.new("_")).next.node.value.should == "y" }
179
+
180
+ # Previous node's `next` is updated
181
+ specify { subject.append(n.new("_")).prev.next.node.value.should == "_" }
182
+ specify { subject.append(n.new("_")).prev.node.next.value.should == "_" }
183
+ end
184
+
185
+ context "at head.next" do
186
+ # Positioned at newly inserted node
187
+ specify { subject.next.append(n.new("_")).node.value.should == "_" }
188
+ specify { subject.next.append(n.new("_")).prev.node.value.should == "y" }
189
+ specify { subject.next.append(n.new("_")).next.node.value.should == "z" }
190
+
191
+ # Previous node's `next` is updated
192
+ specify { subject.next.append(n.new("_")).prev.next.node.value.should == "_" }
193
+ specify { subject.next.append(n.new("_")).prev.node.next.value.should == "_" }
194
+ end
195
+
196
+ context "at tail" do
197
+ # Positioned at newly inserted node
198
+ specify { subject.tail.append(n.new("_")).node.value.should == "_" }
199
+ specify { subject.tail.append(n.new("_")).prev.node.value.should == "z" }
200
+ specify { subject.tail.append(n.new("_")).should be_tail }
201
+
202
+ # Previous node's `next` is updated
203
+ specify { subject.tail.append(n.new("_")).prev.next.node.value.should == "_" }
204
+ specify { subject.tail.append(n.new("_")).prev.node.next.value.should == "_" }
205
+ end
206
+
207
+ context "at head.prev" do
208
+ # Positioned at newly inserted node
209
+ specify { subject.prev(true).append(n.new("_")).should be_head }
210
+ specify { subject.prev(true).append(n.new("_")).node.value.should == "_" }
211
+ specify { subject.prev(true).append(n.new("_")).next.node.value.should == "x" }
212
+ specify { subject.prev(true).append(n.new("_")).prev(true).position.should == -1 }
213
+ end
214
+
215
+ context "at tail.next" do
216
+ # Positioned at newly inserted node
217
+ specify { subject.tail.next(true).append(n.new("_")).should be_tail }
218
+ specify { subject.tail.next(true).append(n.new("_")).node.value.should == "_" }
219
+ specify { subject.tail.next(true).append(n.new("_")).prev.node.value.should == "z" }
220
+
221
+ # Previous node's `next` is updated
222
+ specify { subject.tail.next(true).append(n.new("_")).prev.next.node.value.should == "_" }
223
+ specify { subject.tail.next(true).append(n.new("_")).prev.node.next.value.should == "_" }
224
+ end
225
+
226
+ context "append(y).prev.append(x)" do
227
+ # todo
228
+ # <x> <y> x y z
229
+ # a <x> <y> b c
230
+ # a b <x> <y> c
231
+ # x y z <x> <y>
232
+ end
233
+ end
234
+
235
+ describe "#prepend(node)" do
236
+ let(:x) { n.build(%w(x y z)) }
237
+ subject { z.build(x) }
238
+
239
+ context "on empty stream" do
240
+ # Positioned at newly inserted node
241
+ specify { z.build.prepend(n.new("_")).node.value.should == "_" }
242
+ specify { z.build.prepend(n.new("_")).should be_head }
243
+ specify { z.build.prepend(n.new("_")).should be_tail }
244
+ end
245
+
246
+ context "at head" do
247
+ # Positioned at newly inserted node
248
+ specify { subject.prepend(n.new("_")).should be_head }
249
+ specify { subject.prepend(n.new("_")).node.value.should == "_" }
250
+ specify { subject.prepend(n.new("_")).next.node.value.should == "x" }
251
+ end
252
+
253
+ context "at head.next" do
254
+ # Positioned at newly inserted node
255
+ specify { subject.next.prepend(n.new("_")).node.value.should == "_" }
256
+ specify { subject.next.prepend(n.new("_")).prev.node.value.should == "x" }
257
+ specify { subject.next.prepend(n.new("_")).next.node.value.should == "y" }
258
+
259
+ # Previous node's `next` is updated
260
+ specify { subject.next.prepend(n.new("_")).prev.next.node.value.should == "_" }
261
+ specify { subject.next.prepend(n.new("_")).prev.node.next.value.should == "_" }
262
+ end
263
+
264
+ context "at tail" do
265
+ # Positioned at newly inserted node
266
+ specify { subject.tail.prepend(n.new("_")).should_not be_tail }
267
+ specify { subject.tail.prepend(n.new("_")).node.value.should == "_" }
268
+ specify { subject.tail.prepend(n.new("_")).prev.node.value.should == "y" }
269
+ specify { subject.tail.prepend(n.new("_")).next.node.value.should == "z" }
270
+
271
+ # Previous node's `next` is updated
272
+ specify { subject.tail.prepend(n.new("_")).prev.next.node.value.should == "_" }
273
+ specify { subject.tail.prepend(n.new("_")).prev.node.next.value.should == "_" }
274
+ end
275
+
276
+ context "at head.prev" do
277
+ # Positioned at newly inserted node
278
+ specify { subject.prev(true).prepend(n.new("_")).should be_head }
279
+ specify { subject.prev(true).prepend(n.new("_")).node.value.should == "_" }
280
+ specify { subject.prev(true).prepend(n.new("_")).next.node.value.should == "x" }
281
+ specify { subject.prev(true).prepend(n.new("_")).prev(true).position.should == -1 }
282
+ end
283
+
284
+ context "at tail.next" do
285
+ # Positioned at newly inserted node
286
+ specify { subject.tail.next(true).prepend(n.new("_")).should be_tail }
287
+ specify { subject.tail.next(true).prepend(n.new("_")).node.value.should == "_" }
288
+ specify { subject.tail.next(true).prepend(n.new("_")).prev.node.value.should == "z" }
289
+
290
+ # Previous node's `next` is updated
291
+ specify { subject.tail.next(true).prepend(n.new("_")).prev.next.node.value.should == "_" }
292
+ specify { subject.tail.next(true).prepend(n.new("_")).prev.node.next.value.should == "_" }
293
+ end
294
+
295
+ context "prepend(y).prev.prepend(x)" do
296
+ # todo
297
+ # <x> <y> x y z
298
+ # <x> a <y> b c
299
+ # a <x> b <y> c
300
+ # x y z <x> <y>
301
+ end
302
+ end
303
+
304
+ describe "#update(node)" do
305
+ let(:x) { n.build(%w(x y z)) }
306
+ let(:m) { n.build(%w(m n o)) }
307
+ subject { z.build(x) }
308
+
309
+ context "on empty stream" do
310
+ # Positioned at newly updated (inserted) node
311
+ specify { z.build.update(m).position.should == 0 }
312
+ specify { z.build.update(m).node.value.should == "m" }
313
+
314
+ # Doesn't copy m's entire chain
315
+ specify { z.build.update(m).should be_head }
316
+ specify { z.build.update(m).should be_tail }
317
+ end
318
+
319
+ context "at head" do
320
+ # Positioned at newly updated node
321
+ specify { subject.update(m).node.value.should == "m" }
322
+
323
+ # Replaces existing node
324
+ specify { subject.update(m).position.should == subject.position }
325
+
326
+ # Doesn't copy m's entire chain
327
+ specify { subject.update(m).node.next.value.should == "y" }
328
+ specify { subject.update(m).next.node.value.should == "y" }
329
+
330
+ # todo: Explain
331
+ specify { subject.update(m).node.next.should eql(x.next) }
332
+ specify { subject.update(m).next.node.should eql(x.next) }
333
+ end
334
+
335
+ context "at head.next" do
336
+ # Positioned at newly updated node
337
+ specify { subject.next.update(m).node.value.should == "m" }
338
+
339
+ # Replaces existing node
340
+ specify { subject.next.update(m).position.should == subject.next.position }
341
+
342
+ # Doesn't copy m's entire chain
343
+ specify { subject.next.update(m).node.next.value.should == "z" }
344
+ specify { subject.next.update(m).next.node.value.should == "z" }
345
+
346
+ # todo: Explain
347
+ specify { subject.next.update(m).node.next.should eql(x.next.next) }
348
+ specify { subject.next.update(m).next.node.should eql(x.next.next) }
349
+ end
350
+
351
+ context "at tail" do
352
+ # Positioned at newly updated node
353
+ specify { subject.tail.update(m).node.value.should == "m" }
354
+
355
+ # Replaces existing node
356
+ specify { subject.tail.update(m).position.should == subject.tail.position }
357
+
358
+ # Doesn't copy m's entire chain
359
+ specify { subject.tail.update(m).should be_tail }
360
+
361
+ # todo: Explain
362
+ specify { subject.tail.update(m).node.next.should be_nil }
363
+ end
364
+
365
+ context "at head.prev" do
366
+ # Positioned at newly updated node
367
+ specify { z.build.prev(true).update(m).node.value.should == "m" }
368
+
369
+ # Creates a new head
370
+ specify { subject.prev(true).update(m).should be_head }
371
+ specify { subject.prev(true).update(m).position.should == subject.position }
372
+
373
+ # Doesn't copy m's entire chain
374
+ specify { subject.prev(true).update(m).node.next.value.should == "x" }
375
+ specify { subject.prev(true).update(m).next.node.value.should == "x" }
376
+
377
+ # todo: Explain
378
+ specify { subject.prev(true).update(m).node.next.should eql(x) }
379
+ specify { subject.prev(true).update(m).next.node.should eql(x) }
380
+ end
381
+
382
+ context "at tail.next" do
383
+ # Positioned at newly updated (inserted) node
384
+ specify { subject.tail.next(true).update(m).node.value.should == "m" }
385
+
386
+ # Creates a new tail
387
+ specify { subject.tail.next(true).update(m).should be_tail }
388
+ specify { subject.tail.next(true).update(m).position.should == subject.tail.position + 1 }
389
+
390
+ # Doesn't copy m's entire chain
391
+ specify { subject.tail.next(true).update(m).node.next.should be_nil }
392
+ end
393
+ end
394
+
395
+ describe "#update{|node| ... }" do
396
+ let(:x) { n.build(%w(x y z)) }
397
+ let(:m) { n.build(%w(m n o)) }
398
+ subject { z.build(x) }
399
+
400
+ context "on empty stream" do
401
+ # Positioned at newly updated (inserted) node
402
+ specify { z.build.update{|_| m }.position.should == 0 }
403
+ specify { z.build.update{|_| m }.node.value.should == "m" }
404
+
405
+ # Doesn't copy m's entire chain
406
+ specify { z.build.update{|_| m }.should be_head }
407
+ specify { z.build.update{|_| m }.should be_tail }
408
+
409
+ # Yields nil
410
+ specify { z.build.update{|_| _.should be_nil; m }}
411
+ end
412
+
413
+ context "at head" do
414
+ # Positioned at newly updated node
415
+ specify { subject.update{|x| m }.node.value.should == "m" }
416
+
417
+ # Replaces existing node
418
+ specify { subject.update{|x| m }.position.should == subject.position }
419
+
420
+ # Doesn't copy m's entire chain
421
+ specify { subject.update{|x| m }.node.next.value.should == "y" }
422
+ specify { subject.update{|x| m }.next.node.value.should == "y" }
423
+
424
+ # todo: Explain
425
+ specify { subject.update{|x| m }.node.next.should eql(x.next) }
426
+ specify { subject.update{|x| m }.next.node.should eql(x.next) }
427
+
428
+ # Yields current node
429
+ specify { subject.update{|o| o.should eql(x); o }}
430
+ end
431
+
432
+ context "at head.next" do
433
+ # Positioned at newly updated node
434
+ specify { subject.next.update{|y| m }.node.value.should == "m" }
435
+
436
+ # Replaces existing node
437
+ specify { subject.next.update{|y| m }.position.should == subject.next.position }
438
+
439
+ # Doesn't copy m's entire chain
440
+ specify { subject.next.update{|y| m }.node.next.value.should == "z" }
441
+ specify { subject.next.update{|y| m }.next.node.value.should == "z" }
442
+
443
+ # todo: Explain
444
+ specify { subject.next.update{|y| m }.node.next.should eql(x.next.next) }
445
+ specify { subject.next.update{|y| m }.next.node.should eql(x.next.next) }
446
+
447
+ # Yields current node
448
+ specify { subject.next.update{|o| o.should eql(x.next); o }}
449
+ end
450
+
451
+ context "at tail" do
452
+ # Positioned at newly updated node
453
+ specify { subject.tail.update{|z| m }.node.value.should == "m" }
454
+
455
+ # Replaces existing node
456
+ specify { subject.tail.update{|z| m }.position.should == subject.tail.position }
457
+
458
+ # Doesn't copy m's entire chain
459
+ specify { subject.tail.update{|z| m }.should be_tail }
460
+
461
+ # todo: Explain
462
+ specify { subject.tail.update{|z| m }.node.next.should be_nil }
463
+
464
+ # Yields current node
465
+ specify { subject.tail.update{|o| o.should eql(x.next.next); o }}
466
+ end
467
+
468
+ context "at head.prev" do
469
+ # Positioned at newly updated node
470
+ specify { z.build.prev(true).update{|_| m }.node.value.should == "m" }
471
+
472
+ # Creates a new head
473
+ specify { subject.prev(true).update{|_| m }.should be_head }
474
+ specify { subject.prev(true).update{|_| m }.position.should == subject.position }
475
+
476
+ # Doesn't copy m's entire chain
477
+ specify { subject.prev(true).update{|_| m }.node.next.value.should == "x" }
478
+ specify { subject.prev(true).update{|_| m }.next.node.value.should == "x" }
479
+
480
+ # todo: Explain
481
+ specify { subject.prev(true).update{|_| m }.node.next.should eql(x) }
482
+ specify { subject.prev(true).update{|_| m }.next.node.should eql(x) }
483
+
484
+ # Yields nil
485
+ specify { subject.prev(true).update{|o| o.should be_nil; m }}
486
+ end
487
+
488
+ context "at tail.next" do
489
+ # Positioned at newly updated (inserted) node
490
+ specify { subject.tail.next(true).update{|_| m }.node.value.should == "m" }
491
+
492
+ # Creates a new tail
493
+ specify { subject.tail.next(true).update{|_| m }.should be_tail }
494
+ specify { subject.tail.next(true).update{|_| m }.position.should == subject.tail.position + 1 }
495
+
496
+ # Doesn't copy m's entire chain
497
+ specify { subject.tail.next(true).update{|_| m }.node.next.should be_nil }
498
+
499
+ # Yields nil
500
+ specify { subject.tail.next(true).update{|o| o.should be_nil; m }}
501
+ end
502
+ end
503
+
504
+ describe "#replace(node)" do
505
+ let(:x) { n.build(%w(x y z)) }
506
+ subject { z.build(x) }
507
+
508
+ context "on empty stream" do
509
+ # todo
510
+ end
511
+
512
+ context "at head" do
513
+ # todo
514
+ end
515
+
516
+ context "at head.next" do
517
+ # todo
518
+ end
519
+
520
+ context "at tail" do
521
+ # todo
522
+ end
523
+
524
+ context "at head.prev" do
525
+ # todo
526
+ end
527
+
528
+ context "at tail.next" do
529
+ # todo
530
+ end
531
+ end
532
+
533
+ describe "#delete" do
534
+ let(:x) { n.build(%w(x y z)) }
535
+ subject { z.build(x) }
536
+
537
+ context "on empty stream" do
538
+ # todo
539
+ end
540
+
541
+ context "at head" do
542
+ # todo
543
+ end
544
+
545
+ context "at head.next" do
546
+ # todo
547
+ end
548
+
549
+ context "at tail" do
550
+ # todo
551
+ end
552
+
553
+ context "at head.prev" do
554
+ # todo
555
+ end
556
+
557
+ context "at tail.next" do
558
+ # todo
559
+ end
560
+ end
561
+
562
+ describe "#truncate" do
563
+ let(:x) { n.build(%w(x y z)) }
564
+ subject { z.build(x) }
565
+
566
+ context "on empty stream" do
567
+ # todo
568
+ end
569
+
570
+ context "at head" do
571
+ # todo
572
+ end
573
+
574
+ context "at head.next" do
575
+ # todo
576
+ end
577
+
578
+ context "at tail" do
579
+ # todo
580
+ end
581
+
582
+ context "at head.prev" do
583
+ # todo
584
+ end
585
+
586
+ context "at tail.next" do
587
+ # todo
588
+ end
589
+ end
590
+
591
+ end
592
+
593
+ describe Fr::SZipper::Enumerable do
594
+
595
+ describe "#each{|cursor| ... }" do
596
+ end
597
+
598
+ describe "#all?{|node| predicate }" do
599
+ end
600
+
601
+ describe "#any?{|node| predicate }" do
602
+ end
603
+
604
+ describe "#none?{|node| predicate }" do
605
+ end
606
+
607
+ describe "#count{|node| predicate }" do
608
+ end
609
+
610
+ describe "#find{|node| predicate }" do
611
+ end
612
+
613
+ describe "#drop(n)" do
614
+ end
615
+
616
+ describe "#entries" do
617
+ end
618
+
619
+ describe "#map{|node| ... }" do
620
+ end
621
+
622
+ describe "#filter{|node| predicate }" do
623
+ end
624
+
625
+ describe "#reject{|node| predicate }" do
626
+ end
627
+
628
+ describe "#index{|node| predicate }" do
629
+ end
630
+
631
+ describe "#grep(pattern)" do
632
+ end
633
+
634
+ describe "#include?(node)" do
635
+ end
636
+
637
+ describe "#foldl(seed){|seed, cursor| ... }" do
638
+ end
639
+
640
+ describe "#reduce{|acursor, bcursor| ... }" do
641
+ end
642
+
643
+ describe "#max_by" do
644
+ end
645
+
646
+ describe "#min_by" do
647
+ end
648
+
649
+ describe "#minmax_by" do
650
+ end
651
+
652
+ end