lib/fzip/zipper.rb in fzip-0.1.0 vs lib/fzip/zipper.rb in fzip-0.2.0
- old
+ new
@@ -1,16 +1,24 @@
module Fzip
class Zipper
- attr_reader :adapter, :parent, :path, :node, :lefts, :rights, :at_end
+ attr_reader :adapter
+ attr_reader :parent
+ attr_reader :path
+ attr_reader :node
+ attr_reader :lefts
+ attr_reader :rights
+ attr_reader :at_end
def initialize(adapter, node, lefts = nil, path = nil, parent = nil, rights = nil, changed = false, at_end = false)
@adapter = adapter
+
@node = node
@lefts = lefts
- @path = path
- @parent = parent
@rights = rights
+
+ @path = path # Array[Node]
+ @parent = parent # Zipper
@changed = changed
@at_end = at_end
end
def new(changes = {})
@@ -46,11 +54,11 @@
def end?
@at_end
end
def down
- if branch? && children
+ if branch? && children.any?
new(
node: children.first,
lefts: [],
path: path ? [node] + path : [node],
parent: self,
@@ -62,11 +70,11 @@
def up
if path
return parent unless changed?
parent_path = path.drop(1)
new(
- node: make_node(node, lefts + [node] + rights),
+ node: make_node(parent.node, lefts + [node] + rights),
lefts: parent.lefts,
path: parent_path.empty? ? nil : parent_path,
parent: parent.parent,
rights: parent.rights
)
@@ -86,11 +94,18 @@
rights: rights.drop(1)
)
end
end
- #def rightmost
+ def rightmost
+ return self unless path && rights && !rights.empty?
+ new(
+ node: rights.last,
+ lefts: (lefts + [node] + rights)[0..-2],
+ rights: []
+ )
+ end
def left
if path && lefts && !lefts.empty?
new(
node: lefts.last,
@@ -98,11 +113,18 @@
rights: [node] + rights
)
end
end
- # def leftmost
+ def leftmost
+ return self unless path && lefts && !lefts.empty?
+ new(
+ node: lefts.first,
+ lefts: [],
+ rights: (lefts + [node] + rights).drop(1)
+ )
+ end
def insert_left(item)
raise "insert at top" unless path
new(
lefts: lefts + [item],
@@ -150,18 +172,52 @@
(branch? && down) ||
right ||
backtrack.(self)
end
- # def prev
+ def prev
+ return up unless loc = left
+ loop do
+ if child = loc.branch? && loc.down
+ loc = child.rightmost
+ else
+ return loc
+ end
+ end
+ end
- # def remove
+ # Removes the node at loc, returning the loc that would have preceded
+ # it in a depth-first walk.
+ def remove
+ raise "Remove at top" unless path
+ if lefts.empty?
+ parent.new(
+ node: make_node(parent.node, rights),
+ changed: true
+ )
+ else
+ loc = new(
+ node: lefts.first,
+ lefts: lefts.drop(1),
+ changed: true
+ )
+ loop do
+ return loc unless child = loc.branch? && loc.down
+ loc = child.rightmost
+ end
+ end
+ end
def each
return to_enum unless block_given?
loc = self
until (loc = loc.next).end?
yield loc
end
end
end
end
+
+# Notes on the port from zip.clj :
+# Gave these variables a different name
+# pnodes => path
+# ppath => parent