--- /dev/null
+package jp.ymir.taskReporter.core
+import scala.collection.immutable.StringLike
+import jp.ymir.taskReporter.core._
+
+trait LTSVFunctions {
+ import TSV._
+
+ def decode[A: FromRecord](tsv: StringLike[_]): Seq[A] = {
+ def toTuple(col: String): (Symbol, Field) = {
+ val pattern = """^([^:]+):(.*)$""".r
+ col match {
+ case pattern(label, value) =>
+ (Symbol(label), Field(value))
+ }
+ }
+ val lines = tsv.split('\n').filter(!_.isEmpty)
+ val records = lines.map(line => Record(line.split('\t').map(toTuple).toMap))
+ return records.map { r =>
+ runParser(r.parseRecord[A]) match {
+ case Right(a) => a
+ case Left(e) => throw new DecodeFailedException(e)
+ }
+ }
+ }
+}
+
+object LTSV extends TSVTypes with LTSVFunctions
var reports = _reports.empty
val src = Source.fromFile(file, "UTF-8")
- TSV.decode(src.mkString).foreach { task =>
+ LTSV.decode[Task](src.mkString).foreach { task =>
if (reports.isDefinedAt(task.date)) {
reports(task.date) += task
}
}
}
-/*
- for (line <- src.getLines) {
- if (!line.isEmpty) {
- val task = new Task(line)
- if (reports.isDefinedAt(task.date)) {
- reports(task.date) += task
- }
- else {
- val report = new Report(task.date)
- report += task
- reports += (report.date -> report)
- }
- }
- }
- */
-
_file = Some(file)
_reports = reports
_dirty = false
import scalaz._
import Scalaz._
-object TSV {
+abstract class TSVTypes {
implicit val ParserFunctor = new Functor[Parser] {
def map[A, B](m: Parser[A])(f: A => B) = new Parser[B] {
def lookup[A: FromField](name: Symbol): Parser[A]
= value.get(name).fold(("no field named " + name.name).raiseError[A])(_.parseField[A])
+
+ def lookup[A: FromField](name: Symbol, default: String): Parser[A]
+ = value.get(name).getOrElse(Field(default)).parseField[A]
}
type Failure[ F[_], R] = String => F[R]
def this(msg: String, cause: Throwable) = this(new RuntimeException(msg, cause))
}
- def decode[A: FromRecord](tsv: StringLike[_]): Seq[A] = {
- val lines = tsv.split('\n').filter(!_.isEmpty)
- val header = lines.head.split('\t').map(Symbol(_))
- val body = lines.tail.map(line => Record((header zip line.split('\t').map { Field(_) }).toMap))
- return body.map { r =>
- runParser(r.parseRecord[A]) match {
- case Right(a) => a
- case Left(e) => throw new DecodeFailedException(e)
- }
- }
- }
-
// Option[A]
implicit def OptionFromField[A: FromField] = new FromField[Option[A]] {
def parseField(f: Field): Parser[Option[A]] = {
}
}
}
+
+trait TSVFunctions extends TSVTypes {
+ def decode[A: FromRecord](tsv: StringLike[_]): Seq[A] = {
+ val lines = tsv.split('\n').filter(!_.isEmpty)
+ val header = lines.head.split('\t').map(Symbol(_))
+ val records = lines.tail.map(line => Record((header zip line.split('\t').map { Field(_) }).toMap))
+ return records.map { r =>
+ runParser(r.parseRecord[A]) match {
+ case Right(a) => a
+ case Left(e) => throw new DecodeFailedException(e)
+ }
+ }
+ }
+}
+
+object TSV extends TSVTypes with TSVFunctions
sealed abstract class Status
object Status {
- case object DoingFine extends Status { override def toString() = "順調" }
- case object Lagging extends Status { override def toString() = "遅延" }
- case object DeadlineChanged extends Status { override def toString() = "期限変更" }
- case object Completed extends Status { override def toString() = "完了" }
+ case object DoingFine extends Status { override def toString() = "順調"}
+ case object Lagging extends Status { override def toString() = "遅延"}
+ case object Completed extends Status { override def toString() = "完了"}
}
implicit val CalendarFromField = new FromField[Calendar] {
implicit val StatusFromField = new FromField[Status] {
def parseField(f: Field): Parser[Status] = f.value match {
- case "順調" => (Status.DoingFine: Status).point[Parser]
- case "遅延" => (Status.Lagging: Status).point[Parser]
- case "期限変更" => (Status.DeadlineChanged: Status).point[Parser]
- case "完了" => (Status.Completed: Status).point[Parser]
+ case "順調" => (Status.DoingFine: Status).point[Parser]
+ case "遅延" => (Status.Lagging: Status).point[Parser]
+ case "完了" => (Status.Completed: Status).point[Parser]
case _ =>
("invalid status: " + f).raiseError[Status]
}
def parseRecord(r: Record): Parser[Task] =
for {
date <- r.lookup[Calendar ]('報告日)
- ticketID <- r.lookup[Option[Int] ]('チケットID)
+ ticketID <- r.lookup[Option[Int] ]('チケットID, "")
title <- r.lookup[String ]('作業名)
expectedCompletionDate <- r.lookup[Calendar ]('作業完了予定年月日)
- deadline <- r.lookup[Option[Calendar]]('タスク期限)
+ deadline <- r.lookup[Option[Calendar]]('タスク期限, "")
status <- r.lookup[Status ]('状態)
- description <- r.lookup[Option[String] ]('説明).handleError(_ => None.point[Parser])
+ description <- r.lookup[Option[String] ]('説明, "")
}
yield Task(date, ticketID, title, expectedCompletionDate,
deadline, status, description)