Skip to content

Instantly share code, notes, and snippets.

@kkismd
Last active August 29, 2015 14:24
Show Gist options
  • Save kkismd/b8aa1170ab74d58caea9 to your computer and use it in GitHub Desktop.
Save kkismd/b8aa1170ab74d58caea9 to your computer and use it in GitHub Desktop.
import play.api.libs.functional.Applicative
type ESTR[A] = Either[String,A]
implicit def applicativeEither: Applicative[ESTR] = new Applicative[ESTR] {
override def apply[A, B](mf: ESTR[A => B], ma: ESTR[A]): ESTR[B] = mf.right.flatMap(f => ma.right.map(f))
override def pure[A](a: A): ESTR[A] = Right(a)
override def map[A, B](m: ESTR[A], f: (A) => B): ESTR[B] = m.right.map(f)
}
package xmlreader
import java.time.{LocalDateTime, LocalDate}
import scala.language.higherKinds
import scala.util.{Success, Failure, Try}
import scala.xml.Node
import scalaz._
import syntax.either._
import syntax.validation._
object Convert {
class ElementNotFoundException extends RuntimeException
private def wrap[A](f: String => A): Option[String] => Try[A] = {
case Some(s) => Try(f(s))
case None => Failure(throw new ElementNotFoundException)
}
private val string: String => String = _.toString
private val int: String => Int = _.toInt
private val double: String => Double = _.toDouble
private val date: String => LocalDate = LocalDate.parse(_)
private val dateTime: String => LocalDateTime = LocalDateTime.parse(_)
def toEither[A](ta: Try[A]) = ta match {
case Success(a) => a.right
case Failure(t) => t.toString.left[A]
}
def toValidation[A](va: Try[A]) = va match {
case Success(a) => a.successNel
case Failure(t) => t.toString.successNel
}
val toIntEither = wrap[Int](int) andThen toEither
val toDoubleEither = wrap[Double](double) andThen toEither
val toStringEither = wrap[String](string) andThen toEither
val toDateEither = wrap[LocalDate](date) andThen toEither
val toDateTimeEither = wrap[LocalDateTime](dateTime) andThen toEither
}
object X {
type Read[A,M[_]] = Node => M[A]
trait NodeReader[A,M[_]] {
def read(name: String): Read[A,M]
def text(node: Node, name: String): Option[String] =
(node \\ name).headOption.map(_.text)
}
def read[A,M[_]](name: String)(implicit ev: NodeReader[A,M]): Read[A,M] = ev.read(name)
type StrEither[A] = \/[String,A]
implicit val StrReader = new NodeReader[String,StrEither] {
def read(name: String): Read[String,StrEither] = (node: Node) =>
Convert.toStringEither(text(node, name))
}
implicit val IntReader = new NodeReader[Int,StrEither] {
def read(name: String): Read[Int,StrEither] = (node: Node) =>
Convert.toIntEither(text(node, name))
}
implicit val DoubleReader = new NodeReader[Double,StrEither] {
def read(name: String): Read[Double,StrEither] = (node: Node) =>
Convert.toDoubleEither(text(node, name))
}
implicit val DateReader = new NodeReader[LocalDate,StrEither] {
def read(name: String): Read[LocalDate,StrEither] = (node: Node) =>
Convert.toDateEither(text(node, name))
}
implicit val DateTimeReader = new NodeReader[LocalDateTime,StrEither] {
def read(name: String): Read[LocalDateTime,StrEither] = (node: Node) =>
Convert.toDateTimeEither(text(node, name))
}
}
object Example {
import X._
case class Person(name: String, birthday: LocalDate, height: Double, number: Int)
def main(args: Array[String]) {
val xml =
<people>
<person>
<name>Taro Hara</name>
<birthday>2001-03-12</birthday>
<height>140.5</height>
<number>1</number>
</person>
<person>
<name>Yoko Yamada</name>
<birthday>2005-11-01</birthday>
<height>136.7</height>
<number>2</number>
</person>
</people>
val name = read[String,StrEither]("name")
val birthday = read[LocalDate,StrEither]("birthday")
val height = read[Double,StrEither]("height")
val number = read[Int,StrEither]("number")
val pz = (xml \\ "person").map { node =>
for {
n <- name(node)
b <- birthday (node)
h <- height(node)
m <- number(node)
} yield n
}
println(pz)
val str1 = "foo".right
val str2 = "bar".right
val foobar = for {
foo <- str1
bar <- str2
} yield foo + bar
println(foobar)
// name |@| birthday
}
}
package examples
import scala.xml.Node
import scala.util.control.Exception.allCatch
import play.api.libs.functional.syntax._
object Example {
def str(node: Node, key: String): Option[String] = (node \\ key).headOption.map(_.text)
def int(node: Node, key: String): Option[Int] = allCatch opt { str(node, key).map(_.toInt).get }
case class Person(name: String, age: Int)
def main(args: Array[String]) {
val xml =
<people>
<person>
<name>Taro Hara</name>
<age>14</age>
</person>
<person>
<name>Yoko Yamada</name>
<age>15</age>
</person>
</people>
val people = (xml \\ "person") flatMap { node =>
( str(node, "name") ~ int(node, "age") )(Person)
}
println(people)
}
}
package services
import scala.xml.Node
object Example {
type Read[A,M[_]] = Node => M[A]
trait Reader[A,M[_]] {
def read(name: String): Read[A,M]
def text(node: Node, name: String): M[String]
}
def read[A,M](name: String)(implicit ev: Reader[A,M]): Read[A,M] = ev.read(name)
// 失敗するとNoneを返す
trait OptionReader[A] extends Reader[A,Option] {
def text(node: Node, name: String): Option[String] =
(node \\ name).headOption.map(_.text)
}
type ESTR[A] = Either[String,A]
type NFE = NumberFormatException
// 失敗するとLeft[String]を返す
trait EitherReader[A] extends Reader[A,ESTR] {
def text(node: Node, name: String): Either[String,String] =
(node \\ name).headOption.map(_.text).toRight(s"node $name not found")
}
// ESTR[String]型のインスタンス
implicit val stringReader = new EitherReader[String] {
def read(name: String): Read[String,ESTR] = (node: Node) => text(node, name)
}
// ESTR[Int]型のインスタンス
implicit val intReader = new EitherReader[Int] {
def read(name: String): Read[Int,ESTR] = (node: Node) =>
text(node, name) match {
case Right(string) => try Right(string.toInt) catch { case e: NFE => Left(e.toString) }
case Left(string) => Left(string)
}
}
case class Person(name: String, age: Int)
def main(args: Array[String]) {
val xml =
<people>
<person>
<name>Taro Hara</name>
<age>14</age>
</person>
<person>
<name>Yoko Yamada</name>
<age>15</age>
</person>
</people>
val name = read[String,ESTR]("name")
val age = read[Int,ESTR]("age")
// 本当はこう書きたい
// import play.api.libs.functional.syntax._
// val person = (name ~ age)(Person)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment