lib/stupidedi/zipper/path.rb
# frozen_string_literal: true
module Stupidedi
using Refinements
module Zipper
class AbstractPath
abstract :root?
# @return [AbstractPath]
abstract :parent
# Contains the node's leftward siblings, sorted nearest to furthest
#
# @return [Array<#leaf?, #children, #copy>]
abstract :left
# Contains the node's rightward siblings, sorted nearest to furthest
#
# @return [Array<#leaf?, #children, #copy>]
abstract :right
# True when the node has no rightward siblings
abstract :last?
# True when the node has no leftward siblings
abstract :first?
# Distance from the root node
#
# @return [Integer]
abstract :depth
end
# @private
Root = Class.new(AbstractPath) do
def root?
true
end
# @return self
def parent
self
end
# (see AbstractPath#left)
def left
[]
end
# (see AbstractPath#right)
def right
[]
end
# (see AbstractPath#last?)
# @return true
def last?
true
end
# (see AbstractPath#first?)
# @return true
def first?
true
end
# (see AbstractPath#depth)
def depth
0
end
def position
nil
end
# @return [String]
def inspect
"root"
end
end.new
class Hole < AbstractPath
# (see AbstractPath#right)
attr_reader :left
# @return [AbstractPath]
attr_reader :parent
# (see AbstractPath#left)
attr_reader :right
def initialize(left, parent, right)
@left, @parent, @right =
left, parent, right
end
def root?
false
end
# (see AbstractPath#last?)
def last?
@right.empty?
end
# (see AbstractPath#first?)
def first?
@left.empty?
end
# (see AbstractPath#depth)
def depth
1 + @parent.depth
end
def position
@left.length
end
# @return [String]
def inspect
"#{@parent.inspect}/#{@left.length}"
end
# @return [Boolean]
def ==(other)
depth == other.depth and
position == other.position
end
end
end
end