Skip to content

Instantly share code, notes, and snippets.

@dgouyette
Created May 5, 2017 09:08
Show Gist options
  • Save dgouyette/2777b950dbf209acc5ef6881a821af41 to your computer and use it in GitHub Desktop.
Save dgouyette/2777b950dbf209acc5ef6881a821af41 to your computer and use it in GitHub Desktop.
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)
@dgouyette
Copy link
Author

dgouyette commented May 9, 2017

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

@dgouyette
Copy link
Author

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
  }
}

@jeantil
Copy link

jeantil commented May 9, 2017

ç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 .. ?

@dgouyette
Copy link
Author

dgouyette commented May 10, 2017

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