Commit 82f7e181 authored by Romain Reuillon's avatar Romain Reuillon

[Core] enh: reimplement array on row

parent 3bfb2665
......@@ -33,54 +33,47 @@ package object csv {
import scala.annotation.tailrec
def moreThanOneElement(l: List[_]) = !l.isEmpty && !l.tail.isEmpty
object CSVData {
def toList(d: CSVData) =
d match {
case d: ArrayData d.v
case s: ScalarData List(s.v)
}
sealed trait CSVData
case class ScalarData(v: Any) extends CSVData
case class ArrayData(v: List[Any]) extends CSVData
}
import CSVData._
def valuesToData(values: Seq[Any]) =
values.map {
case v: Array[_] ArrayData(v.toList)
case l: List[_] ArrayData(l)
case v ScalarData(v)
}.toList
def header(prototypes: Seq[Val[_]], values: Seq[Any], arrayOnRow: Boolean) =
if (!arrayOnRow) prototypes.map(_.name).mkString(",")
else {
def arrayHeaders(v: Any, h: String): Seq[String] =
v match {
case v: Array[_] (v zipWithIndex).flatMap { case (e, i) arrayHeaders(e, s"${h}$$${i}") }
case v: Seq[_] (v zipWithIndex).flatMap { case (e, i) arrayHeaders(e, s"${h}$$${i}") }
case v Seq(h)
}
def header(prototypes: Seq[Val[_]]) = prototypes.map(_.name).mkString(",")
(prototypes zip values).flatMap {
case (p, v) arrayHeaders(v, "").map(h s"${p.name}$h")
}.mkString(",")
}
def writeVariablesToCSV(
output: PrintStream,
header: Option[String] = None,
values: Seq[Any],
unrollArray: Boolean = false): Unit = {
unrollArray: Boolean = false,
arrayOnRow: Boolean = false): Unit = {
header.foreach(h output.appendLine { h })
def quote(v: Any): String =
v match {
case v: Array[_] s""""${format(v)}""""
case v: Seq[_] s""""${format(v)}""""
case v v.prettify()
}
def csvLine(v: Seq[Any]): String = {
def format(v: Any): String =
v match {
case v: Array[_] s"[${v.map(format).mkString(",")}]"
case v: Seq[_] s"[${v.map(format).mkString(",")}]"
case v v.prettify()
}
def format(v: Any): String =
v match {
case v: Array[_] s"[${v.map(format).mkString(",")}]"
case v: Seq[_] s"[${v.map(format).mkString(",")}]"
case v v.prettify()
}
def quote(v: Any): String =
v match {
case v: Array[_] s""""${format(v)}""""
case v: Seq[_] s""""${format(v)}""""
case v v.prettify()
}
def csvLine(v: Seq[Any]): String = v.map(quote).mkString(",")
v.map(quote).mkString(",")
}
def unroll(v: Seq[Any]) = {
def writeLines(lists: Seq[List[Any]]): Unit = {
......@@ -108,7 +101,19 @@ package object csv {
writeLines(lists)
}
def onRow(v: Seq[Any]) = {
def arrayValues(v: Any): Seq[Any] =
v match {
case v: Array[_] v.flatMap(arrayValues)
case v: Seq[_] v.flatMap(arrayValues)
case v Seq(v)
}
output.appendLine(csvLine(arrayValues(v)))
}
if (unrollArray) unroll(values)
else if (arrayOnRow) onRow(values)
else output.appendLine(csvLine(values))
}
......
......@@ -5,6 +5,7 @@ import java.io.PrintStream
import org.openmole.tool.stream.StringOutputStream
import org.scalatest._
import org.scalatest.junit._
import org.openmole.core.context._
class CSVSpec extends FlatSpec with Matchers {
......@@ -24,10 +25,33 @@ class CSVSpec extends FlatSpec with Matchers {
)
assert(
result(writeVariablesToCSV(_, None, Seq(42, 56, Array(89, 101)), unrollArrays = true)) ===
result(writeVariablesToCSV(_, None, Seq(42, 56, Array(89, 101)), unrollArray = true)) ===
"""42,56,89
|42,56,101
|""".stripMargin
)
}
"ArrayOnRow" should "generate one column by element" in {
val i = Val[Array[Int]]
val j = Val[Array[Array[Int]]]
val k = Val[String]
def iValues = Array(89, 88, 72)
def jValue = Array(Array(iValues, iValues), Array(65))
def headerValue = header(Seq(i, j, k), Seq(iValues, jValue, "youpi"), arrayOnRow = true)
assert(
headerValue === "i$0,i$1,i$2,j$0$0$0,j$0$0$1,j$0$0$2,j$0$1$0,j$0$1$1,j$0$1$2,j$1$0,k"
)
assert(
result(writeVariablesToCSV(_, Some(headerValue), Seq(iValues, jValue, "youpi"), arrayOnRow = true)) ==
"""i$0,i$1,i$2,j$0$0$0,j$0$0$1,j$0$0$2,j$0$1$0,j$0$1$1,j$0$1$2,j$1$0,k
|89,88,72,89,88,72,89,88,72,65,youpi
|""".stripMargin
)
}
}
......@@ -18,7 +18,7 @@ object CSVHook {
values: Seq[Val[_]] = Vector.empty,
exclude: Seq[Val[_]] = Vector.empty,
header: OptionalArgument[FromContext[String]] = None,
unrollArray: Boolean = true,
unrollArray: Boolean = false,
overwrite: Boolean = false)(implicit name: sourcecode.Name, definitionScope: DefinitionScope): mole.FromContextHook =
FormattedFileHook(
format = CSVOutputFormat(header = header, unrollArray = unrollArray, append = !overwrite),
......@@ -34,7 +34,7 @@ object CSVHook {
override def write(format: CSVOutputFormat, output: WritableOutput, variables: Seq[Variable[_]]): FromContext[Unit] = FromContext { p
import p._
def headerLine = format.header.map(_.from(context)) getOrElse csv.header(variables.map(_.prototype))
def headerLine = format.header.map(_.from(context)) getOrElse csv.header(variables.map(_.prototype), variables.map(_.value), arrayOnRow = format.arrayOnRow)
output match {
case WritableOutput.FileValue(file)
......@@ -43,13 +43,13 @@ object CSVHook {
val h = if (f.isEmpty) Some(headerLine) else None
if (create) f.atomicWithPrintStream { ps csv.writeVariablesToCSV(ps, h, variables.map(_.value), unrollArray = format.unrollArray) }
else f.withPrintStream(append = true, create = true) { ps csv.writeVariablesToCSV(ps, h, variables.map(_.value), unrollArray = format.unrollArray) }
if (create) f.atomicWithPrintStream { ps csv.writeVariablesToCSV(ps, h, variables.map(_.value), unrollArray = format.unrollArray, arrayOnRow = format.arrayOnRow) }
else f.withPrintStream(append = true, create = true) { ps csv.writeVariablesToCSV(ps, h, variables.map(_.value), unrollArray = format.unrollArray, arrayOnRow = format.arrayOnRow) }
case WritableOutput.StreamValue(ps, prelude)
prelude.foreach(ps.print)
val header = Some(headerLine)
csv.writeVariablesToCSV(ps, header, variables, unrollArray = format.unrollArray)
csv.writeVariablesToCSV(ps, header, variables, unrollArray = format.unrollArray, arrayOnRow = format.arrayOnRow)
}
}
......@@ -65,6 +65,7 @@ object CSVHook {
case class CSVOutputFormat(
header: OptionalArgument[FromContext[String]] = None,
unrollArray: Boolean = false,
arrayOnRow: Boolean = false,
append: Boolean = false)
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment