Created
April 4, 2014 16:06
-
-
Save dgalichet/9977782 to your computer and use it in GitHub Desktop.
Generic Reader
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
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