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