Last active
August 29, 2015 14:24
-
-
Save kkismd/b8aa1170ab74d58caea9 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
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) | |
} |
This file contains hidden or 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 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 | |
} | |
} |
This file contains hidden or 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 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) | |
} | |
} | |
This file contains hidden or 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 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