Created
May 5, 2017 09:08
-
-
Save dgouyette/2777b950dbf209acc5ef6881a821af41 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import jto.validation._ | |
sealed trait Color | |
object Color { | |
case object Red extends Color | |
case object Orange extends Color | |
case object Green extends Color | |
val colorR : Rule[String, Color] = Rule.fromMapping { | |
case "Red" => Valid(Red) | |
case "Orange" => Valid(Orange) | |
case "Green" => Valid(Green) | |
case other => Invalid(Seq(ValidationError("unhandled.value", other))) | |
} | |
} | |
Color.colorR.validate("aaa")//Invalid(List((/,List(ValidationError(List(unhandled.value),WrappedArray(aaa)))))) | |
Color.colorR.validate("Red")//Valid(Red) |
could be based on something like
package scalaworld.macros
import scala.collection.immutable.Seq
import scala.meta._
class enum extends scala.annotation.StaticAnnotation {
inline def apply(defn: Any): Any = meta {
defn match {
case Term.Block(
Seq(t @ ClassOrTrait(mods, name), companion: Defn.Object)) if Hierarchy.isSealed(mods) =>
val companionStatements = companion.templ.stats.getOrElse(Nil)
val subTypes = companionStatements.collect {
case t: Defn.Object if Hierarchy.inherits(name)(t) => t
}
val newStatements =
Hierarchy.mkApply(name, subTypes) +: companionStatements
val newCompanion =
companion.copy(templ = companion.templ.copy(stats = Some(newStatements)))
Term.Block(Seq(t, newCompanion))
}
}
}
object Hierarchy {
def inherits(superType: Type.Name)(cls: Defn.Object): Boolean =
cls.templ.parents.headOption.exists {
case q"$parent()" => parent.syntax == superType.syntax
case _ => false
}
def isSealed(mods: Seq[Mod]): Boolean = mods.exists(_.syntax == "sealed")
def mkApply(name: Type.Name, subTypes: Seq[Defn.Object]):Stat={
val cases: Seq[Case] = subTypes.map {
case cls =>
val name= cls.name.value
val term = q"""Some(${Term.Name(name)})"""
p"case ${Lit(cls.name.value)} => $term"
}
q"""
def apply(s:String):Option[$name]=s match {
..case $cases
}
"""
}
}
- reading http://scalameta.org/tutorial/
Thank you, I will look at this carefully
import scala.meta._
import collection.immutable.Seq
object Hierarchy {
def inherits(superType: Type.Name)(cls: Defn.Object): Boolean =
cls.templ.parents.headOption.exists {
case q"$parent()" => parent.syntax == superType.syntax
case _ => false
}
def isSealed(mods: Seq[Mod]): Boolean = mods.exists(_.syntax == "sealed")
}
class Reader extends scala.annotation.StaticAnnotation {
inline def apply(defn: Any): Any = meta {
defn match {
case Term.Block(Seq(t@ClassOrTrait(mods, name), companion: Defn.Object)) if Hierarchy.isSealed(mods) =>
val oldTemplStats = companion.templ.stats.getOrElse(Nil)
val caseObjectNames : Seq[scala.meta.Case] = oldTemplStats.collect {
case t: Defn.Object => scala.meta.Case(
Lit.String(t.name.value),
None,
q"""cats.data.Validated.Valid(${t.name}) """
)
}
val plus =q"""implicit val rule : jto.validation.Rule[String,$name] = jto.validation.Rule.fromMapping {
..${caseObjectNames.map(n => q"{case $n }" )}
}"""
val updatedCompanion = companion.copy(templ = companion.templ.copy(stats = Some(oldTemplStats:+plus)))
val resul = Term.Block(Seq(t, updatedCompanion))
println("------------")
println(resul.syntax)
println("------------")
resul
case _ => abort("Reader must annotate sealed trait")
}
}
}
object ClassOrTrait {
def unapply(any: Defn): Option[(Seq[Mod], Type.Name)] = any match {
case t: Defn.Class => Some((t.mods, t.name))
case t: Defn.Trait => Some((t.mods, t.name))
case _ => None
}
}
Avec le code ci dessous, j'obtiens le code suivant :
sealed trait Color
object Color {
case object Red extends Color()
case object Orange extends Color()
case object Green extends Color()
implicit val rule: jto.validation.Rule[String, Color] = jto.validation.Rule.fromMapping {
{
case "Red" =>
cats.data.Validated.Valid(Red)
}
{
case "Orange" =>
cats.data.Validated.Valid(Orange)
}
{
case "Green" =>
cats.data.Validated.Valid(Green)
}
}
}
}
Si tu as une idée pour applatir les cases, je suis preneur
It's work with this version :
package validation
import scala.meta._
import collection.immutable.Seq
object Hierarchy {
def inherits(superType: Type.Name)(cls: Defn.Object): Boolean =
cls.templ.parents.headOption.exists {
case q"$parent()" => parent.syntax == superType.syntax
case _ => false
}
def isSealed(mods: Seq[Mod]): Boolean = mods.exists(_.syntax == "sealed")
}
class Reader extends scala.annotation.StaticAnnotation {
inline def apply(defn: Any): Any = meta {
defn match {
case Term.Block(Seq(t@ClassOrTrait(mods, name), companion: Defn.Object)) if Hierarchy.isSealed(mods) =>
val oldTemplStats = companion.templ.stats.getOrElse(Nil)
val cases = oldTemplStats.collect{
case t: Defn.Object =>
val name = t.name.value
val term = q"""cats.data.Validated.Valid(${t.name}) """
p"""case ${Lit.String(name)} => $term """
}
val plus =
q"""implicit val rule : jto.validation.Rule[String,$name] = jto.validation.Rule.fromMapping {
..case $cases
}"""
val updatedCompanion = companion.copy(templ = companion.templ.copy(stats = Some(oldTemplStats:+plus)))
val resul = Term.Block(Seq(t, updatedCompanion))
println("------------")
println(resul.syntax)
println("------------")
resul
case _ => abort("Reader must annotate sealed trait")
}
}
}
object ClassOrTrait {
def unapply(any: Defn): Option[(Seq[Mod], Type.Name)] = any match {
case t: Defn.Class => Some((t.mods, t.name))
case t: Defn.Trait => Some((t.mods, t.name))
case _ => None
}
}
ça vaudrait le coup de regarder dans contrib si il y a pas des trucs a réutiliser plutôt que de les redéfinir je pense en particulier a Class Or Trait ou a Hierarchy
genre https://github.com/scalameta/scalameta/blob/master/scalameta/contrib/shared/src/main/scala/scala/meta/contrib/TreeOps.scala#L58 pour hierarchy .. ?
Bonne idée. Maintenant que cela fonctionne, je vais essayer de simplifier mon code.
Merci pour l'info
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
et une petite macro scala meta our generer ca automatiquement ...