From: PHO Date: Thu, 16 Oct 2014 09:22:23 +0000 (+0900) Subject: adopt the new format X-Git-Url: http://git.cielonegro.org/gitweb.cgi?p=task-reporter.git;a=commitdiff_plain;h=3b81fbc877a2b1e346d8f09cb215661cfe2dde30 adopt the new format --- diff --git a/src/main/scala/jp/ymir/taskReporter/core/LTSV.scala b/src/main/scala/jp/ymir/taskReporter/core/LTSV.scala new file mode 100644 index 0000000..5550c54 --- /dev/null +++ b/src/main/scala/jp/ymir/taskReporter/core/LTSV.scala @@ -0,0 +1,27 @@ +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 diff --git a/src/main/scala/jp/ymir/taskReporter/core/ReportSet.scala b/src/main/scala/jp/ymir/taskReporter/core/ReportSet.scala index 66a5d6d..19747b3 100644 --- a/src/main/scala/jp/ymir/taskReporter/core/ReportSet.scala +++ b/src/main/scala/jp/ymir/taskReporter/core/ReportSet.scala @@ -21,7 +21,7 @@ class ReportSet(private var _file: Option[File]) 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 } @@ -32,22 +32,6 @@ class ReportSet(private var _file: Option[File]) } } -/* - 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 diff --git a/src/main/scala/jp/ymir/taskReporter/core/TSV.scala b/src/main/scala/jp/ymir/taskReporter/core/TSV.scala index 817d950..c83594c 100644 --- a/src/main/scala/jp/ymir/taskReporter/core/TSV.scala +++ b/src/main/scala/jp/ymir/taskReporter/core/TSV.scala @@ -7,7 +7,7 @@ import scala.language.reflectiveCalls 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] { @@ -85,6 +85,9 @@ object TSV { 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] @@ -122,18 +125,6 @@ object TSV { 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]] = { @@ -164,3 +155,19 @@ object TSV { } } } + +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 diff --git a/src/main/scala/jp/ymir/taskReporter/core/Task.scala b/src/main/scala/jp/ymir/taskReporter/core/Task.scala index 7152694..d6ed1d8 100644 --- a/src/main/scala/jp/ymir/taskReporter/core/Task.scala +++ b/src/main/scala/jp/ymir/taskReporter/core/Task.scala @@ -21,10 +21,9 @@ object Task { 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] { @@ -40,10 +39,9 @@ object Task { 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] } @@ -53,12 +51,12 @@ object Task { 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)