scalaz/scalaz-stream — pull request #93 by fthomas (2014-02-05 19:46:41+00:00)
Title: repartition combinator

This PR adds the `repartition` combinator. It is inspired by @dickwall's `splitBytesIntoRecords`, see https://github.com/dickwall/scalaz-stream/commit/2157255e98f5f38b0a28808f5a87af1e521b2201#diff-3d5a785f2f5c63059ae38b926be53055R65 Dick, I hope you don't mind that I transformed your idea into this PR.

Here is a simple example how `repartition` can be used:

Process("Hel", "l", "o Wor", "ld").repartition(_.split(" ").toIndexedSeq).toList ==
List("Hello", "World")

Regardless of how the strings are emitted by the first process, `repartition` emits them as they were one string which is then split by `_.split(" ").toIndexedSeq`.

Another use case is when you want to transform a process of `Bytes` of any length (which came from a file for example) into `Bytes` that represents lines. With this function, that splits `Bytes` into lines:

def splitLines(bytes: Bytes): Vector[Bytes] = {
def go(bytes: Bytes, acc: Vector[Bytes]): Vector[Bytes] =
bytes.span(_ != '\n'.toByte) match {
case (line, Bytes.empty) => acc :+ line
case (line, rest) => go(rest.drop(1), acc :+ line)
}
go(bytes, Vector())
}

one could write something like `repartition(splitLines)` and have a process that transforms any `Bytes` regardless of their sizes into complete lines.

`repartition` only requires a `Semigroup` instance for it's input type.