samedi 8 avril 2017

Scala: Build String and Execute as Code at Compile-time

I am using Argonaut for JSON serialization in Scala. Invoking the casecodec methods usually involves some boilerplate that I'd like to reduce.

// fabulous domain-driven case class
case class Person(
                   name: String,
                   birthdate: Long,
                   birthloc: String,
                   genome: List[Int],
                   mother: Option[Person],
                   father: Option[Person],
                   cokeAndNotPepsi: Boolean
                 )

// generate JSON codec for it
implicit val personCodec: argonaut.CodecJson[Person] =
  argonaut.Argonaut.casecodec7(Person.apply, Person.unapply)(
    "name", "birthdate", "birthloc", "genome", "mother", "father", "cokeAndNotPepsi"
  )

Using ClassTags, I can construct a string that resembles the casecodec invocation:

def makeCaseCodec[T](implicit tag: ClassTag[T]): String = {
  val clazz = tag.runtimeClass
  val name = clazz.toString.split("\\$")(1)
  val arity = clazz.getDeclaredFields.length
  val names = clazz.getDeclaredFields
    .map(field => s""""${field.getName}"""").mkString(", ")
  s"implicit val codec$name = argonaut.Argonaut.casecodec$arity($name.apply, $name.unapply)($names)"
}

So then makeCaseCodec[Person] returns the string literal below:

res1> implicit val codecPerson = argonaut.Argonaut.casecodec7(Person.apply, Person.unapply)("name", "birthdate", "birthloc", "genome", "mother", "father", "cokeAndNotPepsi")

How can I execute this string-building-function, say in a macro, at compile-time?





Aucun commentaire:

Enregistrer un commentaire