有没有一种方法可以在编译时基于TypesafeConfig对象在特定的类/特征/对象中生成方法?
例如,我有这个:
object Main {
val config: Config = ConfigFactory.parseString(
"""
|object {
| name = "go"
|}
""".stripMargin)
generate(config)
}
预期结果是:
object Main {
val config: Config = ConfigFactory.parseString(
"""
|object {
| name = "go"
|}
""".stripMargin)
def method: Unit = {
print("go") /* the string comes from the config above */
}
}
这个想法是要能够在宏实现的范围内实例化Config对象并使用其属性来生成代码,例如(非常感谢Dmytro Minin的示例):
object GenerateMacro {
def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
import c.universe._
confObj = ... /* somehow get the real object based on macro input */
annottees match {
case q"$mods object $tname extends { ..$earlydefns } with ..$parents { $self => ..$body }" :: Nil =>
q"""$mods object $tname extends { ..$earlydefns } with ..$parents { $self =>
..$body
def method: Unit = {
print(s"${confObj.getString("object.name")}") /* use confObj's property to "embed" the value into the method generated */
}
}"""
}
}
}
答案 0 :(得分:0)
您可以创建宏注释:
macros / scr / main / scala / generate.scala
import com.typesafe.config.Config
import scala.annotation.{StaticAnnotation, compileTimeOnly}
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
@compileTimeOnly("enable macro paradise to expand macro annotations")
class generate extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro GenerateMacro.impl
}
object GenerateMacro {
def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
import c.universe._
val confObj: Config = c.prefix.tree match {
case q"new generate($config)" => c.eval(c.Expr[Config](/*c.untypecheck(*/config/*)*/))
}
println(confObj) //Config(SimpleConfigObject({"object":{"name":"go"}}))
annottees match {
case q"$mods object $tname extends { ..$earlydefns } with ..$parents { $self => ..$body }" :: Nil =>
q"""$mods object $tname extends { ..$earlydefns } with ..$parents { $self =>
..$body
def method: Unit = {
print(${confObj.getString("object.name")})
}
}"""
}
}
}
并使用它:
core / scr / main / scala / Main.scala
@generate(com.typesafe.config.ConfigFactory.parseString(
"""
|object {
| name = "go"
|}
""".stripMargin))
object Main
那你就可以做
Main.method //go
build.sbt
scalaVersion := "2.12.6"
lazy val commonSettings = Seq(
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full)
)
lazy val macros: Project = (project in file("macros")).settings(
commonSettings,
libraryDependencies += scalaOrganization.value % "scala-reflect" % scalaVersion.value
)
lazy val core: Project = (project in file("core")).aggregate(macros).dependsOn(macros).settings(
commonSettings,
libraryDependencies += "com.typesafe" % "config" % "1.3.2"
)