Skip to content

Instantly share code, notes, and snippets.

@dgalichet
Created April 4, 2014 16:06
Show Gist options
  • Save dgalichet/9977782 to your computer and use it in GitHub Desktop.
Save dgalichet/9977782 to your computer and use it in GitHub Desktop.
Generic Reader
package norm1
import java.text.{ParseException, SimpleDateFormat}
import java.util.Date
import play.api.libs.functional._
import play.api.libs.functional.syntax._
/**
* @author David Galichet.
*/
trait Reader[I, A] {
def reads(p: I => Result[String]): Reads[I, A]
}
object Reader {
implicit def StringReader[I] = new Reader[I, String] {
override def reads(p: (I) => Result[String]) = Reads(p)
}
implicit def IntReader[I] = new Reader[I, Int] {
override def reads(p: (I) => Result[String]) = Reads {
s: I =>
p(s) match {
case Success(x) => try {
Success(x.toInt)
} catch {
case e: NumberFormatException => Failure(s"${x} is not an Integer")
}
case failure: Failure => failure
}
}
}
implicit def DateReader[I](implicit dtFormatter: SimpleDateFormat) = new Reader[I, Date] {
override def reads(p: I => Result[String]): Reads[I, Date] = Reads { i: I =>
p(i) match {
case Success(x) => try {
Success(dtFormatter.parse(x))
} catch {
case e: ParseException => Failure(s"Can't parse ${x} as a date using pattern ${dtFormatter.toPattern}")
}
case Failure(x) => Failure(x)
}
}
}
}
case class Reads[I, A](p: I => Result[A]) {
self =>
def apply(s: I): Result[A] = p(s)
def map[B](f: A => B): Reads[I, B] = Reads {
s: I => p(s) match {
case Success(a) => Success(f(a))
case failure: Failure => failure
}
}
def flatMap[B](f: A => Reads[I, B]): Reads[I, B] = Reads {
s: I => p(s) match {
case Success(a) => f(a).apply(s)
case failure: Failure => failure
}
}
def verify(f: A => Result[A]): Reads[I, A] = flatMap {
a: A => Reads { s: I => f(a) }
}
}
object Reads {
implicit def functorReads[I]: Functor[({type ß[A] = Reads[I, A]})#ß] = new Functor[({type ß[A] = Reads[I, A]})#ß] {
override def fmap[A, B](m: Reads[I, A], f: (A) => B) = m.map(f)
}
implicit def readsIsAnApplicative[I]: Applicative[({type ß[A] = Reads[I, A]})#ß] = new Applicative[({type ß[A] = Reads[I, A]})#ß] {
override def apply[A, B](mf: Reads[I, (A) => B], ma: Reads[I, A]) = Reads[I, B] {
s: I => (mf(s), ma(s)) match {
case (Success(f), Success(a)) => Success(f(a))
case (Success(_), failure: Failure) => failure
case (failure: Failure, Success(_)) => failure
case (Failure(l1), Failure(l2)) => Failure(l1 ++ l2)
}
}
override def map[A, B](m: Reads[I, A], f: (A) => B) = m.map(f)
override def pure[A](a: A) = Reads[I, A] { _ => Success(a) }
}
import scala.language.higherKinds
import scala.language.implicitConversions
implicit def fcbReads[I]: FunctionalCanBuild[({type ß[A] = Reads[I, A]})#ß] = functionalCanBuildApplicative[({type ß[A] = Reads[I, A]})#ß]
implicit def fboReads[I, A](a: Reads[I, A])(implicit fcb: FunctionalCanBuild[({type ß[x] = Reads[I, x]})#ß]) = new FunctionalBuilderOps[({type ß[x] = Reads[I, x]})#ß, A](a)(fcb)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment