Skip to content

Instantly share code, notes, and snippets.

@longshorej
Forked from carymrobbins/pretty-print.scala
Created October 28, 2016 18:34
Show Gist options
  • Save longshorej/e96ffd05b4cecd3e02c7187007bba6a9 to your computer and use it in GitHub Desktop.
Save longshorej/e96ffd05b4cecd3e02c7187007bba6a9 to your computer and use it in GitHub Desktop.
Pretty print Scala case classes and other data structures.
import com.typesafe.scalalogging.LazyLogging
object toPrettyString extends LazyLogging {
def apply(a: Any): String = {
try {
/* pretty printing uses reflection which could fail in odd environments, so we default toString in that case */
prettyPrint(a)
} catch {
case t: Throwable =>
logger.error(s"Error calling toPrettyString with: $a", t)
a.toString
}
}
/* https://gist.github.com/carymrobbins/7b8ed52cd6ea186dbdf8/revisions */
private def prettyPrint(a: Any, indentSize: Int = 2, maxElementWidth: Int = 30, depth: Int = 0): String = {
val indent = " " * depth * indentSize
val fieldIndent = indent + (" " * indentSize)
val nextDepth = prettyPrint(_: Any, indentSize, maxElementWidth, depth + 1)
a match {
case s: String =>
// Make Strings look similar to their literal form.
val replaceMap = Seq(
"\n" -> "\\n",
"\r" -> "\\r",
"\t" -> "\\t",
"\"" -> "\\\""
)
'"' + replaceMap.foldLeft(s) { case (acc, (c, r)) => acc.replace(c, r) } + '"'
case some: Some[_] =>
s"Some(\n$fieldIndent${nextDepth(some.get)}\n$indent)"
case it: Iterable[_] =>
if (it.isEmpty) {
it.toString
} else {
val result = it.map(x => s"$fieldIndent${nextDepth(x)}").mkString(",\n")
s"${it.stringPrefix}(\n$result\n$indent)"
}
case p: Product =>
val prefix = p.productPrefix
// We'll use reflection to get the constructor arg names and values.
val cls = p.getClass
val fields = cls.getDeclaredFields.filterNot(_.isSynthetic).map(_.getName)
val values = p.productIterator.toSeq
if (fields.length != values.length) {
// If we weren't able to match up fields/values, fall back to toString.
p.toString
} else {
fields.zip(values).toList match {
case Nil =>
p.toString
case kvps =>
val prettyFields = kvps.map { case (k, v) => s"$fieldIndent$k = ${nextDepth(v)}" }
s"$prefix(\n${prettyFields.mkString(",\n")}\n$indent)"
}
}
case _ =>
a.toString
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment