scalameta注釈マクロを使用してScalaでREST APIモデルを自動生成したい。具体的には、与えられた:Scalameta:特定の注釈を特定する
object User {
case class Get(id: Int, name: String, email: String)
case class Post(name: String, email: String)
case class Patch(name: Option[String])
}
trait UserRepo {
def getAll: Seq[User.Get]
def get(id: Int): User.Get
def create(request: User.Post): User.Get
def replace(id: Int, request: User.Put): User.Get
def update(id: Int, request: User.Patch): User.Get
def delete(id: Int): User.Get
}
私はここで働いて何かを持っている:https://github.com/pathikrit/metarest
は具体的に私はこれをやっている:
import scala.collection.immutable.Seq
import scala.collection.mutable
import scala.annotation.{StaticAnnotation, compileTimeOnly}
import scala.meta._
class get extends StaticAnnotation
class put extends StaticAnnotation
class post extends StaticAnnotation
class patch extends StaticAnnotation
@compileTimeOnly("@metarest.Resource not expanded")
class Resource extends StaticAnnotation {
inline def apply(defn: Any): Any = meta {
val (cls: Defn.Class, companion: Defn.Object) = defn match {
case Term.Block(Seq(cls: Defn.Class, companion: Defn.Object)) => (cls, companion)
case cls: Defn.Class => (cls, q"object ${Term.Name(cls.name.value)} {}")
case _ => abort("@metarest.Resource must annotate a class")
}
val paramsWithAnnotation = for {
Term.Param(mods, name, decltype, default) <- cls.ctor.paramss.flatten
seenMods = mutable.Set.empty[String]
modifier <- mods if seenMods.add(modifier.toString)
(tpe, defArg) <- modifier match {
case mod"@get" | mod"@put" | mod"@post" => Some(decltype -> default)
case mod"@patch" =>
val optDeclType = decltype.collect({case tpe: Type => targ"Option[$tpe]"})
val defaultArg = default match {
case Some(term) => q"Some($term)"
case None => q"None"
}
Some(optDeclType -> Some(defaultArg))
case _ => None
}
} yield modifier -> Term.Param(Nil, name, tpe, defArg)
val models = paramsWithAnnotation
.groupBy(_._1.toString)
.map({case (verb, pairs) =>
val className = Type.Name(verb.stripPrefix("@").capitalize)
val classParams = pairs.map(_._2)
q"case class $className[..${cls.tparams}] (..$classParams)"
})
val newCompanion = companion.copy(
templ = companion.templ.copy(stats = Some(
companion.templ.stats.getOrElse(Nil) ++ models
))
)
Term.Block(Seq(cls, newCompanion))
}
}
私は不幸だ
@Resource case class User(
@get id : Int,
@get @post @patch name : String,
@get @post email : String,
registeredOn : Long
)
は、私が作成したいです次のコードスニップ:
modifier match {
case mod"@get" | mod"@put" | mod"@post" => ...
case mod"@patch" => ...
case _ => None
}
上記のコードは、私が持っているアノテーションに "文字列"のパターンマッチングを行います。これらのためのパターンマッチに私が持っている正確な注釈を再利用するためにとにかくあります:
class get extends StaticAnnotation
class put extends StaticAnnotation
class post extends StaticAnnotation
class patch extends StaticAnnotation
Iがのcontribモジュールに 'SELECT'抽出を追加するscalameta/scalametaでPRを開放するために、いくつかの
@ParamAnnotation
マクロ注釈によって生成することができる定型です。 https://github.com/scalameta/scalameta/pull/800 –私はデフォルトで '@ ParamAnnotation'を提供するスケーラメタ/パラダイスでチケットをオープンしました。https://github.com/scalameta/paradise/issues/193 –