Skip to content

Instantly share code, notes, and snippets.

@tbrown1979
Last active August 29, 2015 14:23
Show Gist options
  • Save tbrown1979/9993f07c8f4fa2786c83 to your computer and use it in GitHub Desktop.
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…
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