]> gitweb @ CieloNegro.org - task-reporter.git/blob - src/main/scala/jp/ymir/taskReporter/core/TSV.scala
adopt the new format
[task-reporter.git] / src / main / scala / jp / ymir / taskReporter / core / TSV.scala
1 package jp.ymir.taskReporter.core
2 import scala.collection._
3 import scala.collection.immutable.StringLike
4 import scala.language.higherKinds
5 import scala.language.implicitConversions
6 import scala.language.reflectiveCalls
7 import scalaz._
8 import Scalaz._
9
10 abstract class TSVTypes {
11
12   implicit val ParserFunctor = new Functor[Parser] {
13     def map[A, B](m: Parser[A])(f: A => B) = new Parser[B] {
14       def runParser[F[_], R](kf: Failure[F, R], ks: Success[B, F, R]): F[R] = {
15         def ks_(a: A) = ks(f(a))
16         return m.runParser(kf, ks_)
17       }
18     }
19   }
20
21   implicit val ParserApplicative = new Applicative[Parser] {
22     def point[A](a: => A) = new Parser[A] {
23       def runParser[F[_], R](kf: Failure[F, R], ks: Success[A, F, R]): F[R]
24         = ks(a)
25     }
26     def ap[A, B](m: => Parser[A])(fm: => Parser[A => B]) = new Parser[B] {
27       def runParser[F[_], R](kf: Failure[F, R], ks: Success[B, F, R]): F[R] = {
28         def ks_(f: A => B): F[R] = {
29           def ks__(a: A) = ks(f(a))
30           return m.runParser(kf, ks__)
31         }
32         return fm.runParser(kf, ks_)
33       }
34     }
35   }
36
37   implicit val ParserMonad = new Monad[Parser] {
38     def point[A](a: => A) = a.point[Parser]
39
40     def bind[A, B](m: Parser[A])(f: A => Parser[B]) = new Parser[B] {
41       def runParser[F[_], R](kf: Failure[F, R], ks: Success[B, F, R]): F[R] = {
42         def ks_(a: A) = f(a).runParser(kf, ks)
43         return m.runParser(kf, ks_)
44       }
45     }
46   }
47
48   implicit val ParserMonadError = new MonadError[({type λ[String, α] = Parser[α]})#λ, String] {
49     def point[A](a: => A) = a.point[Parser]
50     def bind[A, B](m: Parser[A])(f: A => Parser[B]) = m.flatMap(f)
51
52     def handleError[A](m: Parser[A])(f: String => Parser[A]) = new Parser[A] {
53       def runParser[F[_], R](kf: Failure[F, R], ks: Success[A, F, R]): F[R] = {
54         def kf_(e: String) = f(e).runParser(kf, ks)
55         return m.runParser(kf_, ks)
56       }
57     }
58
59     def raiseError[A](e: String) = new Parser[A] {
60       def runParser[F[_], R](kf: Failure[F, R], ks: Success[A, F, R]): F[R]
61         = kf(e)
62     }
63   }
64
65   implicit def ToMonadErrorOps[A](m: Parser[A]) = new {
66     def handleError(f: String => Parser[A]): Parser[A]
67       = implicitly[MonadError[({type λ[String, α] = Parser[α]})#λ, String]].handleError(m)(f)
68   }
69
70   implicit def ToMonadErrorIdOps(e: String) = new {
71     def raiseError[A]: Parser[A]
72       = implicitly[MonadError[({type λ[String, α] = Parser[α]})#λ, String]].raiseError(e)
73   }
74
75   type Header = Seq[Symbol]
76
77   case class Field(value: String) {
78     def parseField[A: FromField]
79       = implicitly[FromField[A]].parseField(Field(value))
80   }
81
82   case class Record(value: Map[Symbol, Field]) {
83     def parseRecord[A: FromRecord]
84       = implicitly[FromRecord[A]].parseRecord(Record(value))
85
86     def lookup[A: FromField](name: Symbol): Parser[A]
87       = value.get(name).fold(("no field named " + name.name).raiseError[A])(_.parseField[A])
88
89     def lookup[A: FromField](name: Symbol, default: String): Parser[A]
90       = value.get(name).getOrElse(Field(default)).parseField[A]
91   }
92
93   type Failure[   F[_], R] = String => F[R]
94   type Success[A, F[_], R] = A      => F[R]
95
96   trait Parser[+A] {
97     def runParser[F[_], R](kf: Failure[F, R], ks: Success[A, F, R]): F[R]
98   }
99
100   def runParser[A](p: Parser[A]): Either[String, A] = {
101     type F[R] = Either[String, R]
102     def left (e: String): F[A] = Left(e)
103     def right(x: A     ): F[A] = Right(x)
104     return p.runParser(left, right)
105   }
106
107   trait FromRecord[A] {
108     def parseRecord(r: Record): Parser[A]
109   }
110
111   trait FromField[A] {
112     def parseField(f: Field): Parser[A]
113   }
114
115   trait ToRecord[A] {
116     def toRecord(a: A): Record
117   }
118
119   trait ToField[A] {
120     def toField(a: A): Field
121   }
122
123   class DecodeFailedException private(e: RuntimeException) extends RuntimeException(e) {
124     def this(msg: String) = this(new RuntimeException(msg))
125     def this(msg: String, cause: Throwable) = this(new RuntimeException(msg, cause))
126   }
127
128   // Option[A]
129   implicit def OptionFromField[A: FromField] = new FromField[Option[A]] {
130     def parseField(f: Field): Parser[Option[A]] = {
131       if (f.value.isEmpty) {
132         return None.point[Parser]
133       }
134       else {
135         f.parseField[A].map { Some(_) }
136       }
137     }
138   }
139
140   // String
141   implicit val StringFromField = new FromField[String] {
142     def parseField(f: Field): Parser[String] = f.value.point[Parser]
143   }
144
145   // Int
146   implicit val IntFromField = new FromField[Int] {
147     def parseField(f: Field): Parser[Int] = {
148       try {
149         f.value.toInt.point[Parser]
150       }
151       catch {
152         case e: NumberFormatException =>
153           e.getMessage().raiseError[Int]
154       }
155     }
156   }
157 }
158
159 trait TSVFunctions extends TSVTypes {
160   def decode[A: FromRecord](tsv: StringLike[_]): Seq[A] = {
161     val lines   = tsv.split('\n').filter(!_.isEmpty)
162     val header  = lines.head.split('\t').map(Symbol(_))
163     val records = lines.tail.map(line => Record((header zip line.split('\t').map { Field(_) }).toMap))
164     return records.map { r =>
165       runParser(r.parseRecord[A]) match {
166         case Right(a) => a
167         case Left(e)  => throw new DecodeFailedException(e)
168       }
169     }
170   }
171 }
172
173 object TSV extends TSVTypes with TSVFunctions