-
-
Save tbrown1979/9993f07c8f4fa2786c83 to your computer and use it in GitHub Desktop.
The idea with this is to provide ways for a List[String] to be converted to a case class. At the bottom you can see a working example. You can create an implicit Reader for a case class of arbitrary size and then .read a list and it will convert it to the case class appropriately. The issue I've run into with this is with the 'non-working exampl…
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 scala.util._ | |
import shapeless._ | |
import scalaz.NonEmptyList | |
import scalaz.Scalaz._ | |
import scalaz.Semigroup | |
import scalaz.Validation | |
import scalaz.{Failure, Success, ValidationNel} | |
trait Reader[+A] { self => | |
def read(ls: List[String]): ValidationNel[String, A] | |
def map[B](f: A => B): Reader[B] = new Reader[B] { | |
def read(ls: List[String]): ValidationNel[String, B] = self.read(ls).map(f) | |
} | |
} | |
object Reader { | |
def apply[A: Reader]: Reader[A] = implicitly[Reader[A]] | |
def read[A: Reader](ls: List[String]): ValidationNel[String, A] = implicitly[Reader[A]].read(ls) | |
implicit object StringReader extends Reader[String] { | |
def read(ls: List[String]) = ls.headOption.fold(s"Invalid String: $ls".failureNel[String])(s => s.successNel[String]) | |
} | |
implicit object IntReader extends Reader[Int] { | |
def read(ls: List[String]) = Try {ls.head.toInt}.toOption.fold("Invalid Integer".failureNel[Int])(i => i.successNel[String]) | |
} | |
implicit object HNilReader extends Reader[HNil] { | |
def read(ls: List[String]) = | |
if (ls.isEmpty) HNil.successNel[String] | |
else "Expected empty, but contained value".failureNel[HNil] | |
} | |
implicit def HListReader[A : Reader, H <: HList : Reader]: Reader[A :: H] = new Reader[A :: H] { | |
def read(ls: List[String]): ValidationNel[String, A :: H] = { | |
lazy val before: ValidationNel[String, A] = Reader.read[A](ls.take(1)) | |
lazy val after = Reader.read[H](ls.drop(1)) | |
(before |@| after) {(a, b) => a :: b} | |
} | |
} | |
} | |
////Working Example//// | |
case class Foo(a: Int, s: String) | |
object Foo { | |
implicit val FooReader : Reader[Foo] = | |
Reader[Int :: String :: HNil].map(Generic[Foo].from _) | |
} | |
val read: ValidationNel[String, Foo] = Reader.read[Foo](List("12", "text")) | |
println(read)//Success(Foo(12, "text")) | |
/////////////////////////// | |
////Non-working Example//// | |
case class Test(a: Int, b: String) | |
object Test { | |
implicit val TestReader: Reader[Test] = | |
Reader[Int :: String :: HNil].map(Generic[Test].from _) | |
} | |
case class Bar(c: Test) | |
object Bar { | |
implicit val BarReader: Reader[Bar] = | |
Reader[Test :: HNil].map(Generic[Bar].from _) | |
} | |
val barRead = Reader.read[Bar](List("21", "string")) | |
println(barRead) //Failure(NonEmptyList("Invalid String: List()", "Exepected empty, but contained value")) | |
////////////////////////// |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment