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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- OTg0MWE1NTE4M2IyYmVjN2UxZjQ1NGM4YTdjNTQwZTAxNzkzOWQ5NQ==
4
+ ZDhiOWFhY2M0MTBiNGZiZjRjZThiYmE4OTg4ZTc3OGZlODkzZjA0ZA==
5
5
  data.tar.gz: !binary |-
6
- ZTg4YWE1NWIxMDViZDA3YThiZDliYTI3MjY0MTQ2YTU5Nzc2MmI0YQ==
6
+ MzE5MWUwYjVjNTU0YmFjZmE1MjNkZjdiMDBiZWI2MDc3OWE2MWVjZQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MmRiYzljMTVhNzhmNDk0MDdlZTZmOTViNTIyZmZjM2FhZTBkZjZmYmUzNTlm
10
- ZTA0NWU5ZDYyNDhjNmY0YWNhYjA5MzBhNjc1NzJhZTA0MzgxZTc0NzVhMzRm
11
- MDE0NjcyYjI0ZDAyZjVkMWJiZmU1ZThjNWZiNjFmZDU5NjViNDg=
9
+ ODBiYmZjNTE2NzAzNmQwY2JkMGU0Njk3MTAyYTMxOTY0ZTJkYzQ1MWE2YWEx
10
+ NjQzZjU1ZTE0Mjg2ZjE2MGY5Yjc0Yjk3YzhjNjEyNWQ2MmRhZGI3NmMxYWU5
11
+ NDI2ODBmZjUzYjI3NDczZjczYzg1NmQxM2U4OTkzZjJmZjNhMDY=
12
12
  data.tar.gz: !binary |-
13
- NTQwZDkzMzVmYWYzMzRjYWI1OGIwMzUzODEyN2U4MzFlZmJhNGJiODBmMDg2
14
- YmNlNWIyYzM4ZjA5M2VkMzhjODA5MzYxZmM1MWMxZDAwNTZkNjg3ODRkM2Iw
15
- MzAyYmVlYjhiNWY3ZTMzYmVjMjI2YjAyMmNhNDQ0ZmM2OWY1ZDg=
13
+ YjM4NzdhNjFkNThkYWUwNTMxMjVlMDBhMmM3N2NkMTRhN2YxYjM3M2MyMDAy
14
+ N2M0NTVhMDdkZDdlNjNkZDEwMGJkOTY2MTZhMWJhYzkyYmVlMGRlNjg0OTE3
15
+ ZTY5YzQxZmQwYWYyZGM5YTc4ZDM2ZjgyZjg3YjM2YzA4MmU1NWY=
data/.gitignore CHANGED
@@ -1 +1,2 @@
1
1
  coverage
2
+ pkg
@@ -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 = '0.1.0'
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'
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Fzip
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -1,14 +1,22 @@
1
1
  module Fzip
2
2
  class Zipper
3
- attr_reader :adapter, :parent, :path, :node, :lefts, :rights, :at_end
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
- #def rightmost
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
- # def leftmost
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
- # def prev
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
- # def remove
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
@@ -1,6 +1,4 @@
1
- $LOAD_PATH.unshift(Pathname(__FILE__).dirname.parent.join('lib'))
2
-
3
- require 'fzip'
1
+ require 'spec_helper'
4
2
 
5
3
  describe Fzip, 'array' do
6
4
  let(:tree) {
@@ -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
@@ -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
@@ -0,0 +1,3 @@
1
+ $LOAD_PATH.unshift(Pathname(__FILE__).dirname.parent.join('lib'))
2
+
3
+ require 'fzip'
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.1.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-01-31 00:00:00.000000000 Z
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