Scala - how to print case classes like (pretty printed) tree

前端 未结 10 1844
情歌与酒
情歌与酒 2020-12-07 22:35

I\'m making a parser with Scala Combinators. It is awesome. What I end up with is a long list of entagled case classes, like: ClassDecl(Complex,List(VarDecl(Real,float

10条回答
  •  [愿得一人]
    2020-12-07 23:04

    Here's my solution which greatly improves how http://www.lihaoyi.com/PPrint/ handles the case-classes (see https://github.com/lihaoyi/PPrint/issues/4 ).

    e.g. it prints this:

    for such a usage:

      pprint2 = pprint.copy(additionalHandlers = pprintAdditionalHandlers)
    
      case class Author(firstName: String, lastName: String)
      case class Book(isbn: String, author: Author)
      val b = Book("978-0486282114", Author("first", "last"))
      pprint2.pprintln(b)
    

    code:

    import pprint.{PPrinter, Tree, Util}
    object PPrintUtils {
      // in scala 2.13 this would be even simpler/cleaner due to added product.productElementNames
      protected def caseClassToMap(cc: Product): Map[String, Any] = {
        val fieldValues = cc.productIterator.toSet
        val fields = cc.getClass.getDeclaredFields.toSeq
          .filterNot(f => f.isSynthetic || java.lang.reflect.Modifier.isStatic(f.getModifiers))
        fields.map { f =>
          f.setAccessible(true)
          f.getName -> f.get(cc)
        }.filter { case (k, v) => fieldValues.contains(v) }
          .toMap
      }
    
      var pprint2: PPrinter = _
    
      protected def pprintAdditionalHandlers: PartialFunction[Any, Tree] = {
        case x: Product =>
          val className = x.getClass.getName
          // see source code for pprint.treeify()
          val shouldNotPrettifyCaseClass = x.productArity == 0 || (x.productArity == 2 && Util.isOperator(x.productPrefix)) || className.startsWith(pprint.tuplePrefix) || className == "scala.Some"
    
          if (shouldNotPrettifyCaseClass)
            pprint.treeify(x)
          else {
            val fieldMap = caseClassToMap(x)
            pprint.Tree.Apply(
              x.productPrefix,
              fieldMap.iterator.flatMap { case (k, v) =>
                val prettyValue: Tree = pprintAdditionalHandlers.lift(v).getOrElse(pprint2.treeify(v))
                Seq(pprint.Tree.Infix(Tree.Literal(k), "=", prettyValue))
              }
            )
          }
      }
    
      pprint2 = pprint.copy(additionalHandlers = pprintAdditionalHandlers)
    }
    
    // usage
    pprint2.println(SomeFancyObjectWithNestedCaseClasses(...))
    

提交回复
热议问题