
scales.utils.collection.path.PathFolds.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scales-xml_2.11 Show documentation
Show all versions of scales-xml_2.11 Show documentation
An alternate Scala Xml processing library
The newest version!
package scales.utils.collection.path
import scala.collection.generic.CanBuildFrom
import scales.utils.collection.{SeqLikeThing, Tree}
import scales.utils.{FoldR, ItemOrTree, LeftLike, PathFoldR, TreeCBF, deepestLast, top}
/**
* Represents the base for operations that fold over a list of paths
*/
sealed trait FoldOperation[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[_]] {
implicit val seqLikeThing: SeqLikeThing[CC[_], ItemOrTree[Item, Section, CC], CC]
protected def rootChangeAllowed = false
def perform(path: Path[Item, Section, CC]): FoldR[Item, Section, CC]
protected def add(path: Path[Item, Section, CC], direction: Int, newPath: Iterable[ItemOrTree[Item, Section, CC]]) : FoldR[Item, Section, CC] = {
// need to go up to replace
val parent = path.zipUp
if (path.top.isLeft && !rootChangeAllowed)
Right(AddedBeforeOrAfterRoot)
else
Left(parent.
modify { x =>
val tree = x.right.get;
val index = path.node.index + direction
val (pre,pos) = seqLikeThing.splitAt(tree.children)(index)
val newChildren = seqLikeThing.++((seqLikeThing.++(pre)(newPath)))( seqLikeThing.seq(pos))
Tree(tree.section, newChildren.asInstanceOf[CC[ItemOrTree[Item, Section, CC]]]) // actually the same
})
}
}
case class Remove[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[_]]()(implicit val seqLikeThing: SeqLikeThing[CC[_], ItemOrTree[Item, Section, CC], CC]) extends FoldOperation[Item, Section, CC] {
def perform(path: Path[Item, Section, CC]): FoldR[Item, Section, CC] = {
val ores = path.removeAndUp();
if (ores.isDefined) Left(ores.get)
else Right(RemovedRoot)
}
}
case class AddBefore[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[_]](newPath: ItemOrTree[Item, Section, CC])(implicit val seqLikeThing: SeqLikeThing[CC[_], ItemOrTree[Item, Section, CC], CC]) extends FoldOperation[Item, Section, CC] {
def perform(path: Path[Item, Section, CC]): FoldR[Item, Section, CC] = add(path, 0, List(newPath))
}
case class AddAfter[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[_]](newPath: ItemOrTree[Item, Section, CC])(implicit val seqLikeThing: SeqLikeThing[CC[_], ItemOrTree[Item, Section, CC], CC]) extends FoldOperation[Item, Section, CC] {
def perform(path: Path[Item, Section, CC]): FoldR[Item, Section, CC] = add(path, 1, List(newPath))
}
/**
* Use to make it easier to filter out large sets (for those that aren't interesting simply asis them, see tests for use case)
*/
case class AsIs[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[_]]()(implicit val seqLikeThing: SeqLikeThing[CC[_], ItemOrTree[Item, Section, CC], CC]) extends FoldOperation[Item, Section, CC] {
def perform(path: Path[Item, Section, CC]): FoldR[Item, Section, CC] = Left(path)
}
object Replace {
/**
* Simpler interface
*/
def apply[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[_]](replaceWith: ItemOrTree[Item, Section, CC]*)(implicit seqLikeThing: SeqLikeThing[CC[_], ItemOrTree[Item, Section, CC], CC]) = new Replace[Item, Section, CC](replaceWith)
}
/**
* Allows replacing one path with many, may be easier to use the * version however
*/
case class Replace[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[_]](replaceWith: Iterable[ItemOrTree[Item, Section, CC]])(implicit val seqLikeThing: SeqLikeThing[CC[_], ItemOrTree[Item, Section, CC], CC]) extends FoldOperation[Item, Section, CC] {
override def rootChangeAllowed = true
def perform(path: Path[Item, Section, CC]): FoldR[Item, Section, CC] = {
// modify with tail
val tpath = path.modify(_ => replaceWith.head)
add(tpath, 1, replaceWith.tail)
}
}
/**
* Allows foldPositions to be nested, only replace and delete makes sense here (afaict).
*
* As such, when wholeTree is false, the path (which must be a tree) is transformed
*
* p => top(p.tree)
*
* and a special case for "deletes" is made - when RemovedRoot is returned from the transformation a delete will take place on the Path. This enforces that only replace and removes are possible and function appropriately.
*
* Warning:
*
* When wholeTree is true the function f is passed the Path (or item) in the original tree, any transformations are then conusmed across the whole tree, which is likely not desired.
*/
case class ReplaceWith[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[_]](f: PathFoldR[Item, Section, CC], wholeTree : Boolean = false)
(implicit val seqLikeThing: SeqLikeThing[CC[_], ItemOrTree[Item, Section, CC], CC]) extends FoldOperation[Item, Section, CC] {
def perform(path: Path[Item, Section, CC]): FoldR[Item, Section, CC] =
// modify back in (allows changes), or pass on the error
f( if (wholeTree)
path
else
top(path.tree) ).
fold(fres =>
Left(path.modify(_ =>
fres.tree
)),
x => {
if ((x eq RemovedRoot) &&
(!wholeTree))
// delete the node - special case as per doc
Remove[Item, Section, CC]().perform(path) // it might itself be the root but thats fine
else
Right(x)
}
)
}
sealed trait FoldError
case object NoPaths extends FoldError
case object NoSingleRoot extends FoldError
case object RemovedRoot extends FoldError
case object AddedBeforeOrAfterRoot extends FoldError
© 2015 - 2025 Weber Informatics LLC | Privacy Policy