Skip to content

Instantly share code, notes, and snippets.

@wolfendale
Created October 31, 2015 23:42
Show Gist options
  • Save wolfendale/de5e3399f6bc80d009e2 to your computer and use it in GitHub Desktop.
Save wolfendale/de5e3399f6bc80d009e2 to your computer and use it in GitHub Desktop.
Map[String, String] to Case Class
package wolfendale
import shapeless._
import shapeless.labelled._
import scala.util.{Failure, Success, Try}
trait FromStringMap[A] {
def apply(data: Map[String, String]): Try[A]
}
object FromStringMap {
def apply[A0](implicit from: FromStringMap[A0]): FromStringMap[A0] = from
implicit def fromHnil: FromStringMap[HNil] = new FromStringMap[HNil] {
override def apply(data: Map[String, String]): Try[HNil] = Success(HNil)
}
implicit def fromHcons[H, T <: HList]
(implicit
fromHead: FromStringMap[H],
fromTail: FromStringMap[T]
): FromStringMap[H :: T] = new FromStringMap[H :: T] {
override def apply(data: Map[String, String]): Try[H :: T] =
for {
head <- fromHead(data)
tail <- fromTail(data)
} yield head :: tail
}
implicit def fromField[K <: Symbol, V]
(implicit
witnessK: Witness.Aux[K],
readsV: Reads[V]
): FromStringMap[FieldType[K, V]] = new FromStringMap[FieldType[K, V]] {
override def apply(data: Map[String, String]): Try[FieldType[K, V]] =
data.get(witnessK.value.name).fold[Try[FieldType[K, V]]](Failure(new Exception())) {
(str) => readsV(str) map { field[K](_) }
}
}
implicit def fromOptionField[K <: Symbol, V]
(implicit
witnessK: Witness.Aux[K],
readsV: Reads[V]
): FromStringMap[FieldType[K, Option[V]]] = new FromStringMap[FieldType[K, Option[V]]] {
override def apply(data: Map[String, String]): Try[FieldType[K, Option[V]]] =
data.get(witnessK.value.name).fold[Try[FieldType[K, Option[V]]]](Success(field[K](None))) {
(str) => readsV(str) map { x => field[K](Some(x)) }
}
}
implicit def fromGen[G, Repr <: HList]
(implicit
lgen: LabelledGeneric.Aux[G, Repr],
fromG: FromStringMap[Repr]
): FromStringMap[G] = new FromStringMap[G] {
override def apply(data: Map[String, String]): Try[G] =
fromG(data) map { lgen.from(_) }
}
}
package wolfendale
object FromStringMapApp extends App {
case class Foo(a: String, b: Int, c: Option[String])
val from = FromStringMap[Foo]
println(from(Map("a" -> "foo", "b" -> "123", "c" -> "bar")))
println(from(Map("a" -> "foo", "b" -> "123")))
println(from(Map("a" -> "bar", "b" -> "foo", "c" -> "womble")))
}
package wolfendale
import scala.util.{Success, Try}
trait Reads[A] {
def apply(str: String): Try[A]
}
object Reads {
implicit def readsString: Reads[String] = new Reads[String] {
override def apply(str: String): Try[String] = Success(str)
}
implicit def readsInt: Reads[Int] = new Reads[Int] {
override def apply(str: String): Try[Int] = Try { str.toInt }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment