Skip to content

Instantly share code, notes, and snippets.

@EtaCassiopeia
Created October 25, 2023 16:50
Show Gist options
  • Save EtaCassiopeia/92e44e4dc688883b77493a0dc49d63ee to your computer and use it in GitHub Desktop.
Save EtaCassiopeia/92e44e4dc688883b77493a0dc49d63ee to your computer and use it in GitHub Desktop.
import scala.meta._
class ExtendWith(additionalFields: (String, Type)*) extends scala.annotation.StaticAnnotation {
inline def apply(defn: Any): Any = meta {
// Extract the original case class fields
val q"..$mods case class $tname[..$tparams] $ctorMods(...$paramss) extends $template" = defn
// Create new fields using the additionalFields provided
val newFields = additionalFields.map {
case (name, tpe) => param"$name: $tpe"
}
// Combine original fields with new fields
val allFields = paramss.flatten ++ newFields
// Generate the extended case class
val extendedDefn = q"""
..$mods case class ${Type.Name(s"Extended${tname.value}")}[..$tparams] (...$allFields) extends $template
"""
// Return both the original and the extended case class
Term.Block(Seq(defn, extendedDefn))
}
}
/*
@ExtendWith(("address", "String"), ("phone", "Int"))
case class Person(name: String, age: Int)
Scalameta macro annotations were not supported in the main Scala compiler as of Scala 2.13, so you'd need to use the paradise compiler plugin to enable them. Ensure you've added the necessary dependencies and compiler plugins.
This approach modifies the Abstract Syntax Tree (AST) at compile time and generates the extended case class, making it available for use in your project.
Remember to adjust your build tool to take the generated source directory into account. If you're using sbt, you might need to modify the sourceDirectories setting to include the directory where the generated code is placed.
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment