How do I create a class or object in Scala macros?
I'm trying to create a companion object from a case class using macros, but I'm having a very hard time finding examples of how to do this.
For example:
case class Person(name: String, age: Int, id: Option[Int] = None)
If I do this:
object PersonTable extends TypedTable[Person]
I want it to generate:
object PersonTable extends Table("PERSON") {
val name = column[String]("NAME")
val age = column[Int]("AGE")
val id = column[Option[Int]]("ID")
}
Also, I want to be able to extend it and add additional fields:
object PersonTable extends TypedTable[Person] {
val created = column[Timestamp]("TIMESTAMP")
}
And it will generate:
object PersonTable extends Table("PERSON") {
val name = column[String]("NAME")
val age = column[Int]("AGE")
val id = column[Option[Int]]("ID")
val created = column[Timestamp]("TIMESTAMP")
}
Edit
After reading the macros (thanks to Eugene and Mario), I created the following code:
class table[T] extends StaticAnnotation {
def macroTransform(annottees: Any*) = macro TableGenerator.impl
}
object TableGenerator {
def impl(c: whitebox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
def modifiedObject(objectDef: ModuleDef): c.Expr[Any] = {
val ModuleDef(_, objectName, template) = objectDef
val ret = q"""
object $objectName {
def test() = println("Wahoo!")
}
"""
c.Expr[Any](ret)
}
annottees.map(_.tree) match {
case (objectDecl: ModuleDef) :: _ => modifiedObject(objectDecl)
case x => c.abort(c.enclosingPosition, s"@table can only be applied to an object, not to $x")
}
}
}
And then tried to use it like this:
@table[String] object MyCoolObject
MyCoolObject.test()
The first line works fine, but the second line says it can't find a test method. How do I make the validation method visible?
Unfortunately, it is very difficult to find good examples of Macros online - especially for 2.11. I was finally able to get everything to work, so I would like to provide a link to the code for anyone struggling with the same issues later.
https://github.com/outr/scalarelational/blob/master/mapper/src/main/scala/org/scalarelational/mapper/typedTable.scala
Thanks again to Eugene and Mario for your wonderful answers that led me to find my answer.