fzip 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.gitignore +1 -0
- data/fzip.gemspec +1 -1
- data/lib/fzip/adapter.rb +8 -0
- data/lib/fzip/version.rb +1 -1
- data/lib/fzip/zipper.rb +65 -9
- data/spec/fzip_spec.rb +1 -3
- data/spec/next_spec.rb +49 -0
- data/spec/remove_spec.rb +77 -0
- data/spec/spec_helper.rb +3 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZDhiOWFhY2M0MTBiNGZiZjRjZThiYmE4OTg4ZTc3OGZlODkzZjA0ZA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MzE5MWUwYjVjNTU0YmFjZmE1MjNkZjdiMDBiZWI2MDc3OWE2MWVjZQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ODBiYmZjNTE2NzAzNmQwY2JkMGU0Njk3MTAyYTMxOTY0ZTJkYzQ1MWE2YWEx
|
10
|
+
NjQzZjU1ZTE0Mjg2ZjE2MGY5Yjc0Yjk3YzhjNjEyNWQ2MmRhZGI3NmMxYWU5
|
11
|
+
NDI2ODBmZjUzYjI3NDczZjczYzg1NmQxM2U4OTkzZjJmZjNhMDY=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YjM4NzdhNjFkNThkYWUwNTMxMjVlMDBhMmM3N2NkMTRhN2YxYjM3M2MyMDAy
|
14
|
+
N2M0NTVhMDdkZDdlNjNkZDEwMGJkOTY2MTZhMWJhYzkyYmVlMGRlNjg0OTE3
|
15
|
+
ZTY5YzQxZmQwYWYyZGM5YTc4ZDM2ZjgyZjg3YjM2YzA4MmU1NWY=
|
data/.gitignore
CHANGED
data/fzip.gemspec
CHANGED
@@ -2,7 +2,7 @@ require File.expand_path('../lib/fzip/version', __FILE__)
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |gem|
|
4
4
|
gem.name = 'fzip'
|
5
|
-
gem.version =
|
5
|
+
gem.version = Fzip::VERSION
|
6
6
|
gem.authors = [ 'Arne Brasseur' ]
|
7
7
|
gem.email = [ 'arne@arnebrasseur.net' ]
|
8
8
|
gem.description = 'Functional zipper class'
|
data/lib/fzip/adapter.rb
CHANGED
@@ -1,11 +1,19 @@
|
|
1
1
|
module FZip
|
2
2
|
class Adapter
|
3
|
+
# Can the node have children
|
4
|
+
#
|
5
|
+
# Returns true if the node can have even if it currently doesn't.
|
3
6
|
def branch?(node)
|
4
7
|
end
|
5
8
|
|
9
|
+
# The children of a node
|
10
|
+
#
|
11
|
+
# Return an array, or an object that responds to first, drop and +
|
6
12
|
def children(node)
|
7
13
|
end
|
8
14
|
|
15
|
+
# Given a node and an array of children, returns a new branch node of the
|
16
|
+
# same type with the supplied children.
|
9
17
|
def make_node(node, children)
|
10
18
|
end
|
11
19
|
end
|
data/lib/fzip/version.rb
CHANGED
data/lib/fzip/zipper.rb
CHANGED
@@ -1,14 +1,22 @@
|
|
1
1
|
module Fzip
|
2
2
|
class Zipper
|
3
|
-
attr_reader :adapter
|
3
|
+
attr_reader :adapter
|
4
|
+
attr_reader :parent
|
5
|
+
attr_reader :path
|
6
|
+
attr_reader :node
|
7
|
+
attr_reader :lefts
|
8
|
+
attr_reader :rights
|
9
|
+
attr_reader :at_end
|
4
10
|
|
5
11
|
def initialize(adapter, node, lefts = nil, path = nil, parent = nil, rights = nil, changed = false, at_end = false)
|
6
12
|
@adapter = adapter
|
13
|
+
|
7
14
|
@node = node
|
8
15
|
@lefts = lefts
|
9
|
-
@path = path
|
10
|
-
@parent = parent
|
11
16
|
@rights = rights
|
17
|
+
|
18
|
+
@path = path # Array[Node]
|
19
|
+
@parent = parent # Zipper
|
12
20
|
@changed = changed
|
13
21
|
@at_end = at_end
|
14
22
|
end
|
@@ -48,7 +56,7 @@ module Fzip
|
|
48
56
|
end
|
49
57
|
|
50
58
|
def down
|
51
|
-
if branch? && children
|
59
|
+
if branch? && children.any?
|
52
60
|
new(
|
53
61
|
node: children.first,
|
54
62
|
lefts: [],
|
@@ -64,7 +72,7 @@ module Fzip
|
|
64
72
|
return parent unless changed?
|
65
73
|
parent_path = path.drop(1)
|
66
74
|
new(
|
67
|
-
node: make_node(node, lefts + [node] + rights),
|
75
|
+
node: make_node(parent.node, lefts + [node] + rights),
|
68
76
|
lefts: parent.lefts,
|
69
77
|
path: parent_path.empty? ? nil : parent_path,
|
70
78
|
parent: parent.parent,
|
@@ -88,7 +96,14 @@ module Fzip
|
|
88
96
|
end
|
89
97
|
end
|
90
98
|
|
91
|
-
|
99
|
+
def rightmost
|
100
|
+
return self unless path && rights && !rights.empty?
|
101
|
+
new(
|
102
|
+
node: rights.last,
|
103
|
+
lefts: (lefts + [node] + rights)[0..-2],
|
104
|
+
rights: []
|
105
|
+
)
|
106
|
+
end
|
92
107
|
|
93
108
|
def left
|
94
109
|
if path && lefts && !lefts.empty?
|
@@ -100,7 +115,14 @@ module Fzip
|
|
100
115
|
end
|
101
116
|
end
|
102
117
|
|
103
|
-
|
118
|
+
def leftmost
|
119
|
+
return self unless path && lefts && !lefts.empty?
|
120
|
+
new(
|
121
|
+
node: lefts.first,
|
122
|
+
lefts: [],
|
123
|
+
rights: (lefts + [node] + rights).drop(1)
|
124
|
+
)
|
125
|
+
end
|
104
126
|
|
105
127
|
def insert_left(item)
|
106
128
|
raise "insert at top" unless path
|
@@ -152,9 +174,38 @@ module Fzip
|
|
152
174
|
backtrack.(self)
|
153
175
|
end
|
154
176
|
|
155
|
-
|
177
|
+
def prev
|
178
|
+
return up unless loc = left
|
179
|
+
loop do
|
180
|
+
if child = loc.branch? && loc.down
|
181
|
+
loc = child.rightmost
|
182
|
+
else
|
183
|
+
return loc
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
156
187
|
|
157
|
-
#
|
188
|
+
# Removes the node at loc, returning the loc that would have preceded
|
189
|
+
# it in a depth-first walk.
|
190
|
+
def remove
|
191
|
+
raise "Remove at top" unless path
|
192
|
+
if lefts.empty?
|
193
|
+
parent.new(
|
194
|
+
node: make_node(parent.node, rights),
|
195
|
+
changed: true
|
196
|
+
)
|
197
|
+
else
|
198
|
+
loc = new(
|
199
|
+
node: lefts.first,
|
200
|
+
lefts: lefts.drop(1),
|
201
|
+
changed: true
|
202
|
+
)
|
203
|
+
loop do
|
204
|
+
return loc unless child = loc.branch? && loc.down
|
205
|
+
loc = child.rightmost
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
158
209
|
|
159
210
|
def each
|
160
211
|
return to_enum unless block_given?
|
@@ -165,3 +216,8 @@ module Fzip
|
|
165
216
|
end
|
166
217
|
end
|
167
218
|
end
|
219
|
+
|
220
|
+
# Notes on the port from zip.clj :
|
221
|
+
# Gave these variables a different name
|
222
|
+
# pnodes => path
|
223
|
+
# ppath => parent
|
data/spec/fzip_spec.rb
CHANGED
data/spec/next_spec.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fzip::Zipper, 'next' do
|
4
|
+
let(:tree) {
|
5
|
+
[
|
6
|
+
['x', '+', 'y'],
|
7
|
+
['a', '*', 'b']
|
8
|
+
]
|
9
|
+
}
|
10
|
+
let(:zipper) { Fzip.array(tree) }
|
11
|
+
|
12
|
+
let(:sequence) {
|
13
|
+
[
|
14
|
+
tree,
|
15
|
+
['x', '+', 'y'],
|
16
|
+
'x',
|
17
|
+
'+',
|
18
|
+
'y',
|
19
|
+
['a', '*', 'b'],
|
20
|
+
'a',
|
21
|
+
'*',
|
22
|
+
'b'
|
23
|
+
]
|
24
|
+
}
|
25
|
+
|
26
|
+
it 'should go depth first' do
|
27
|
+
sequence.each.with_index do |n, idx|
|
28
|
+
nth = (0...idx).inject(zipper) {|z| z.next}
|
29
|
+
expect(nth.node).to eq n
|
30
|
+
|
31
|
+
p nth.node
|
32
|
+
sequence.first(idx+1).reverse.each.with_index do |p, pidx|
|
33
|
+
puts " => #{p.inspect}"
|
34
|
+
pth = (0...pidx).inject(nth) {|n| n.prev}
|
35
|
+
expect(pth.node).to eq p
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should go to the end' do
|
41
|
+
z = zipper
|
42
|
+
9.times do
|
43
|
+
expect(z.end?).to be_false
|
44
|
+
z = z.next
|
45
|
+
end
|
46
|
+
expect(z.end?).to be_true
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
data/spec/remove_spec.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fzip::Zipper, 'remove' do
|
4
|
+
let(:tree) {
|
5
|
+
[
|
6
|
+
['x', '+', 'y'],
|
7
|
+
['a', '*', 'b']
|
8
|
+
]
|
9
|
+
}
|
10
|
+
|
11
|
+
let(:zipper) { Fzip.array(tree) }
|
12
|
+
|
13
|
+
context 'when removing the top node' do
|
14
|
+
it 'should raise an exception' do
|
15
|
+
expect { zipper.remove }.to raise_error
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when removing a node that has a left sibling' do
|
20
|
+
let(:zipper) { super().down.down.right }
|
21
|
+
|
22
|
+
it 'should remove the node' do
|
23
|
+
expect(zipper.remove.root).to eq [
|
24
|
+
['x', 'y'],
|
25
|
+
['a', '*', 'b']
|
26
|
+
]
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should return the zipper pointing to the left sibling' do
|
30
|
+
expect(zipper.remove.node).to eq 'x'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'without left siblings' do
|
35
|
+
let(:zipper) { super().down.down }
|
36
|
+
|
37
|
+
it 'should remove the node' do
|
38
|
+
expect(zipper.remove.root).to eq [
|
39
|
+
[ '+', 'y'],
|
40
|
+
['a', '*', 'b']
|
41
|
+
]
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should point to the parent' do
|
45
|
+
expect(zipper.remove.node).to eq [ '+', 'y' ]
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'without right siblings' do
|
49
|
+
let(:tree) {
|
50
|
+
[
|
51
|
+
[ 'z' ]
|
52
|
+
]
|
53
|
+
}
|
54
|
+
|
55
|
+
it 'should remove the node' do
|
56
|
+
expect(zipper.remove.root).to eq [ [] ]
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should point to the parent node' do
|
60
|
+
expect(zipper.remove.node).to eq []
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'with left cousins' do
|
66
|
+
let(:zipper) { super().down.right }
|
67
|
+
|
68
|
+
it 'should remove the node' do
|
69
|
+
expect(zipper.remove.root).to eq [ ['x', '+', 'y'] ]
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should point to the rightmost left cousin' do
|
73
|
+
expect(zipper.remove.root).to eq [ ['x', '+', 'y'] ]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fzip
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arne Brasseur
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-02-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
prerelease: false
|
@@ -57,6 +57,9 @@ files:
|
|
57
57
|
- lib/fzip/version.rb
|
58
58
|
- lib/fzip/zipper.rb
|
59
59
|
- spec/fzip_spec.rb
|
60
|
+
- spec/next_spec.rb
|
61
|
+
- spec/remove_spec.rb
|
62
|
+
- spec/spec_helper.rb
|
60
63
|
homepage: https://github.com/plexus/fzip
|
61
64
|
licenses:
|
62
65
|
- MIT
|
@@ -83,3 +86,6 @@ specification_version: 4
|
|
83
86
|
summary: Functional zipper class
|
84
87
|
test_files:
|
85
88
|
- spec/fzip_spec.rb
|
89
|
+
- spec/next_spec.rb
|
90
|
+
- spec/remove_spec.rb
|
91
|
+
- spec/spec_helper.rb
|