From c76c22585efe052cab1c3711999dee5bef350968 Mon Sep 17 00:00:00 2001 From: Robin Hillyard Date: Wed, 10 Apr 2019 00:35:00 -0400 Subject: [PATCH 1/3] v1.0.4 Include headers in rendering Not yet complete. --- README.md | 2 +- build.sbt | 2 +- .../com/phasmidsoftware/render/Renderer.scala | 20 +++++++++-- .../phasmidsoftware/render/Renderers.scala | 27 ++++++++++++++- .../scala/com/phasmidsoftware/table/Row.scala | 15 ++++++++ .../com/phasmidsoftware/table/Table.scala | 10 ++++-- .../phasmidsoftware/render/RendererSpec.scala | 34 +++++++++++++++++-- .../com/phasmidsoftware/table/TableSpec.scala | 4 ++- 8 files changed, 102 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index a9ac7b4..1aba528 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ together with something like, for instance, a Json writer. # User Guide -Current version: 1.0.3. +Current version: 1.0.4. See release notes below for history. diff --git a/build.sbt b/build.sbt index 416e10d..fdcae8e 100755 --- a/build.sbt +++ b/build.sbt @@ -2,7 +2,7 @@ organization := "com.phasmidsoftware" name := "TableParser" -version := "1.0.3" +version := "1.0.4-SNAPSHOT" scalaVersion := "2.12.6" diff --git a/src/main/scala/com/phasmidsoftware/render/Renderer.scala b/src/main/scala/com/phasmidsoftware/render/Renderer.scala index a36f25c..2df58d7 100644 --- a/src/main/scala/com/phasmidsoftware/render/Renderer.scala +++ b/src/main/scala/com/phasmidsoftware/render/Renderer.scala @@ -4,6 +4,7 @@ package com.phasmidsoftware.render +import com.phasmidsoftware.table.Indexed import org.joda.time.LocalDate import scala.annotation.implicitNotFound @@ -26,7 +27,7 @@ trait Renderer[T] { * @tparam U the type of the result. * @return a new instance of U. */ - def render[U: TreeWriter](t: T, attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, Some(render(t)), baseAttrs ++ attrs) + def render[U: TreeWriter](t: T, attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, Some(asString(t)), baseAttrs ++ attrs) /** * Method to render content as a String. @@ -38,7 +39,7 @@ trait Renderer[T] { * @param t the content value. * @return a String corresponding to t. */ - def render(t: T): String = t.toString + def asString(t: T): String = t.toString /** * Defines the default style for type T. @@ -62,6 +63,21 @@ trait UntaggedRenderer[T] extends Renderer[T] { abstract class TaggedRenderer[T](val style: String, override val baseAttrs: Map[String, String] = Map()) extends Renderer[T] +abstract class IndexedRenderer[T: Renderer](val style: String, override val baseAttrs: Map[String, String] = Map()) extends Renderer[Indexed[T]] { + /** + * Render an instance of Indexed[T] as a U. + * + * @param ti the input parameter, i.e. the object to be rendered. + * @param attrs a map of attributes for this value of U. + * @tparam U the type of the result. + * @return a new instance of U. + */ + override def render[U: TreeWriter](ti: Indexed[T], attrs: Map[String, String]): U = { + val indexRenderer: Renderer[Int] = new TaggedRenderer[Int]("th") {} + implicitly[TreeWriter[U]].node(style, None, Map(), Seq(indexRenderer.render(ti.i, Map()), implicitly[Renderer[T]].render(ti.t, Map()))) + } +} + object Renderer { // NOTE: this is only used in unit tests diff --git a/src/main/scala/com/phasmidsoftware/render/Renderers.scala b/src/main/scala/com/phasmidsoftware/render/Renderers.scala index d51cd79..f955c6b 100644 --- a/src/main/scala/com/phasmidsoftware/render/Renderers.scala +++ b/src/main/scala/com/phasmidsoftware/render/Renderers.scala @@ -4,6 +4,7 @@ package com.phasmidsoftware.render +import com.phasmidsoftware.table.{Header, Indexed} import com.phasmidsoftware.util.Reflection import scala.reflect.ClassTag @@ -15,6 +16,21 @@ import scala.reflect.ClassTag */ trait Renderers { + /** + * Renderer for a header. + * + * CONSIDER using sequenceRenderer + * + * @param style the style for the header (e.g. "th" for an HTML table). + * @param attrs the attributes. + * @return a Renderer[Seq[String] ] + */ + def headerRenderer(style: String, attrs: Map[String, String] = Map())(stringRenderer: Renderer[String]): Renderer[Header] = new TaggedRenderer[Header](style, attrs) { + override def render[U: TreeWriter](h: Header, attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, None, attrs, h.xs.map((t: String) => stringRenderer.render(t, Map()))) + } + + // sequenceRenderer(style, attrs).asInstanceOf[Renderer[Header]] + /** * Render an sequence of P as a U. * NOTE: there are no identifiers generated with this Renderer. @@ -26,6 +42,15 @@ trait Renderers { override def render[U: TreeWriter](ps: Seq[P], attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, None, attrs, ps map ((t: P) => implicitly[Renderer[P]].render(t, Map()))) } + /** + * Render an sequence of P as a U. + * NOTE: there are no identifiers generated with this Renderer. + * + * @tparam P the type of the result. + * @return a new instance of U. + */ + def indexedRenderer[P: Renderer](style: String, attrs: Map[String, String] = Map()): Renderer[Indexed[P]] = new IndexedRenderer[P](style, attrs) {} + /** * Render an option of P as a U. * NOTE: there are no identifiers generated with this Renderer. @@ -68,7 +93,7 @@ trait Renderers { */ def rendererExplicit[T: Renderer](style: String, attrs: Map[String, String] = Map())(f: T => String): Renderer[T] = new TaggedRenderer[T](style, attrs) { - override def render(t: T): String = f(t) + override def asString(t: T): String = f(t) } /** diff --git a/src/main/scala/com/phasmidsoftware/table/Row.scala b/src/main/scala/com/phasmidsoftware/table/Row.scala index ff05382..fd57079 100644 --- a/src/main/scala/com/phasmidsoftware/table/Row.scala +++ b/src/main/scala/com/phasmidsoftware/table/Row.scala @@ -49,3 +49,18 @@ case class Row(ws: Seq[String], hdr: Header) extends (String => String) { override def toString(): String = s"""Row: ${ws.mkString("[", ",", "]")} with header=$hdr""" } + +/** + * A wrapper class to index a T. + * + * @param i the index (ordinal value). + * @param t the instance of T. + * @tparam T the underlying type. + */ +case class Indexed[T](i: Int, t: T) + +object Indexed { + def apply[T](tuple: (T, Int)): Indexed[T] = Indexed(tuple._2, tuple._1) + + def index[T](rows: Seq[T]): Seq[Indexed[T]] = rows.zipWithIndex.map(Indexed(_)) +} \ No newline at end of file diff --git a/src/main/scala/com/phasmidsoftware/table/Table.scala b/src/main/scala/com/phasmidsoftware/table/Table.scala index 254c412..fa67ebc 100644 --- a/src/main/scala/com/phasmidsoftware/table/Table.scala +++ b/src/main/scala/com/phasmidsoftware/table/Table.scala @@ -91,12 +91,16 @@ trait Table[Row] extends Iterable[Row] { * @tparam U a class which supports TreeWriter (i.e. there is evidence of TreeWriter[U]). * @return a new instance of U which represents this Table as a tree of some sort. */ - def render[U: TreeWriter](style: String, attributes: Map[String, String] = Map())(implicit rr: Renderer[Row]): U = { + def render[U: TreeWriter](style: String, attributes: Map[String, String] = Map())(implicit rr: Renderer[Indexed[Row]]): U = { object TableRenderers extends Renderers { - val tableRenderer: Renderer[Seq[Row]] = sequenceRenderer[Row](style) + val rowsRenderer: Renderer[Seq[Indexed[Row]]] = sequenceRenderer[Indexed[Row]]("span") + val headerRenderer: Renderer[Header] = headerRenderer("th")(renderer("td", Map())) } import TableRenderers._ - tableRenderer.render(rows, attributes) + val q: Seq[Indexed[Row]] = Indexed.index(rows) + val z: U = rowsRenderer.render(q, Map()) + val uo: Option[U] = maybeHeader map (headerRenderer.render(_, Map())) + implicitly[TreeWriter[U]].node(style, None, attributes, uo.toSeq ++ Seq(z)) } } diff --git a/src/test/scala/com/phasmidsoftware/render/RendererSpec.scala b/src/test/scala/com/phasmidsoftware/render/RendererSpec.scala index cd7e05a..45daf53 100644 --- a/src/test/scala/com/phasmidsoftware/render/RendererSpec.scala +++ b/src/test/scala/com/phasmidsoftware/render/RendererSpec.scala @@ -5,7 +5,7 @@ package com.phasmidsoftware.render import com.phasmidsoftware.render.tag.{Attribute, HTML} -import com.phasmidsoftware.table.TableWithoutHeader +import com.phasmidsoftware.table.{Header, Indexed, TableWithHeader, TableWithoutHeader} import org.scalatest.{FlatSpec, Matchers} class RendererSpec extends FlatSpec with Matchers { @@ -38,8 +38,29 @@ class RendererSpec extends FlatSpec with Matchers { } object Complex2 extends Renderers { + implicit val valueRenderer: Renderer[Double] = renderer("td") + implicit val complexRenderer: Renderer[Complex] = renderer2("span")(Complex) + implicit val indexedRenderer: Renderer[Indexed[Complex]] = indexedRenderer[Complex]("tr", Map()) + // val rowsRenderer: Renderer[Seq[Indexed[Complex]]] = sequenceRenderer[Indexed[Complex]]("span") + + + import HTML._ + trait TreeWriterHTML$ extends TreeWriter[HTML] { + def addChild(parent: HTML, child: HTML): HTML = parent match { + case HTML(t, co, as, hs) => HTML(t, co, as, hs :+ child) + } + + def node(tag: String, content: Option[String], attributes: Map[String, String], children: Seq[HTML]): HTML = HTML(tag, attributes.toSeq.map(kv => Attribute(kv)), content, children) + } + + implicit object TreeWriterHTML$ extends TreeWriterHTML$ + } + + object Complex3 extends Renderers { implicit val valueRenderer: Renderer[Double] = renderer("td") implicit val complexRenderer: Renderer[Complex] = renderer2("tr")(Complex) + // val rowsRenderer: Renderer[Seq[Indexed[Complex]]] = sequenceRenderer[Indexed[Complex]]("span") + import HTML._ trait TreeWriterHTML$ extends TreeWriter[HTML] { @@ -79,7 +100,7 @@ class RendererSpec extends FlatSpec with Matchers { } it should "render Complex as an HTML" in { - import Complex2._ + import Complex3._ val z = Complex(0, 1) import HTML._ Renderer.render(z) shouldBe HTML("tr", Nil, None, List(HTML("td", Seq(Attribute("name" -> "r")), Some("0.0"), Nil), HTML("td", Seq(Attribute("name" -> "i")), Some("1.0"), Nil))) @@ -94,11 +115,18 @@ class RendererSpec extends FlatSpec with Matchers { // Renderer.render(z) shouldBe SimpleHTML("x", None, Map("name"->"Complicated"), List(SimpleHTML("element", Some("strange"), Map("name"->"name"), List()), SimpleHTML("", Some("42"), Map("name"->"count"), List()), SimpleHTML("", Some("false"), Map("name"->"open"), List()), SimpleHTML("", None, Map("name"->"maybePhone"), List(SimpleHTML("", Some("6175551234"), Map.empty, List()))), SimpleHTML("", None, Map("name"->"aliases"), List(SimpleHTML("element", Some("Tom"), Map.empty, List()), SimpleHTML("element", Some("Dick"), Map.empty, List()), SimpleHTML("element", Some("Harry"), Map.empty, List()))))) } - it should "render a table of Complexes in HTML" in { + it should "render a table of Complexes in HTML without a header" in { import Complex2._ val table = TableWithoutHeader(Seq(Complex(0, 1), Complex(-1, 0))) val h = table.render("table", Map("border" -> "1")) println(h) } + it should "render a table of Complexes in HTML with a header" in { + import Complex2._ + val table = TableWithHeader(Seq(Complex(0, 1), Complex(-1, 0)), Header(Seq("real", "imaginary"))) + val h = table.render("table", Map("border" -> "1")) + println(h) + } + } diff --git a/src/test/scala/com/phasmidsoftware/table/TableSpec.scala b/src/test/scala/com/phasmidsoftware/table/TableSpec.scala index 0a123ec..d683f41 100644 --- a/src/test/scala/com/phasmidsoftware/table/TableSpec.scala +++ b/src/test/scala/com/phasmidsoftware/table/TableSpec.scala @@ -144,16 +144,18 @@ class TableSpec extends FlatSpec with Matchers { implicit object HTMLTreeWriter extends HTMLTreeWriter implicit val intPairRenderer: Renderer[IntPair] = renderer2("IntPair")(IntPair.apply) + implicit val r: Renderer[Indexed[IntPair]] = indexedRenderer("", Map()) } + // FIXME it should "render the parsed table" in { import IntPair._ val iIty = Table.parse(Seq("1 2", "42 99")) import IntPairHTML._ val hy = iIty map (_.render("table", Map())) hy should matchPattern { case Success(_) => } - hy.get shouldBe HTML("table", None, Map(), List(HTML("IntPair", None, Map.empty, List(HTML("", Some("1"), Map("name" -> "a"), List()), HTML("", Some("2"), Map("name" -> "b"), List()))), HTML("IntPair", None, Map(), List(HTML("", Some("42"), Map("name" -> "a"), List()), HTML("", Some("99"), Map("name" -> "b"), List()))))) + // hy.get shouldBe HTML("table", None, Map(), List(HTML("span",None,Map(),List(HTML("IntPair", None, Map.empty, List(HTML("", Some("1"), Map("name" -> "a"), List()), HTML("", Some("2"), Map("name" -> "b"), List()))), HTML("IntPair", None, Map(), List(HTML("", Some("42"), Map("name" -> "a"), List()), HTML("", Some("99"), Map("name" -> "b"), List()))))))) } From 6de4192e9f2d3d94935fed93afb6acd8b6331bf7 Mon Sep 17 00:00:00 2001 From: Robin Hillyard Date: Wed, 10 Apr 2019 10:03:45 -0400 Subject: [PATCH 2/3] v1.0.4 continued Added abstract class ProductRenderer and refactored renderer1, etc. Various minor refactorings. --- .../com/phasmidsoftware/render/Renderer.scala | 22 +- .../phasmidsoftware/render/Renderers.scala | 320 +++++++++--------- .../phasmidsoftware/render/TreeWriter.scala | 8 + .../com/phasmidsoftware/table/Table.scala | 6 +- .../render/TreeWriterSpec.scala | 4 +- 5 files changed, 198 insertions(+), 162 deletions(-) diff --git a/src/main/scala/com/phasmidsoftware/render/Renderer.scala b/src/main/scala/com/phasmidsoftware/render/Renderer.scala index 2df58d7..38770c6 100644 --- a/src/main/scala/com/phasmidsoftware/render/Renderer.scala +++ b/src/main/scala/com/phasmidsoftware/render/Renderer.scala @@ -8,6 +8,7 @@ import com.phasmidsoftware.table.Indexed import org.joda.time.LocalDate import scala.annotation.implicitNotFound +import scala.reflect.ClassTag /** * Definition of type class Renderer for the purpose of serializing objects of type T. @@ -29,6 +30,16 @@ trait Renderer[T] { */ def render[U: TreeWriter](t: T, attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, Some(asString(t)), baseAttrs ++ attrs) + /** + * Render an instance of T as a U. + * This signature does not support the specification of attributes. + * + * @param t the input parameter, i.e. the object to be rendered. + * @tparam U the type of the result. + * @return a new instance of U. + */ + def render[U: TreeWriter](t: T): U = render(t, Map()) + /** * Method to render content as a String. * This method is invoked only when T is not a Product, sequence or Option. @@ -63,6 +74,12 @@ trait UntaggedRenderer[T] extends Renderer[T] { abstract class TaggedRenderer[T](val style: String, override val baseAttrs: Map[String, String] = Map()) extends Renderer[T] +abstract class ProductRenderer[T <: Product : ClassTag](val style: String, override val baseAttrs: Map[String, String] = Map()) extends Renderer[T] { + override def render[U: TreeWriter](t: T, attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, attrs, us(t)) + + protected def us[U: TreeWriter](t: T): Seq[U] +} + abstract class IndexedRenderer[T: Renderer](val style: String, override val baseAttrs: Map[String, String] = Map()) extends Renderer[Indexed[T]] { /** * Render an instance of Indexed[T] as a U. @@ -73,15 +90,16 @@ abstract class IndexedRenderer[T: Renderer](val style: String, override val base * @return a new instance of U. */ override def render[U: TreeWriter](ti: Indexed[T], attrs: Map[String, String]): U = { + // TODO specify style as header, but not with HTML-specific "th". val indexRenderer: Renderer[Int] = new TaggedRenderer[Int]("th") {} - implicitly[TreeWriter[U]].node(style, None, Map(), Seq(indexRenderer.render(ti.i, Map()), implicitly[Renderer[T]].render(ti.t, Map()))) + implicitly[TreeWriter[U]].node(style, Seq(indexRenderer.render(ti.i), implicitly[Renderer[T]].render(ti.t))) } } object Renderer { // NOTE: this is only used in unit tests - def render[T: Renderer, U: TreeWriter](t: T): U = implicitly[Renderer[T]].render(t, Map()) + def render[T: Renderer, U: TreeWriter](t: T): U = implicitly[Renderer[T]].render(t) // NOTE: this is only used in unit tests def render[T: Renderer, U: TreeWriter](t: T, a: String): U = implicitly[Renderer[T]].render(t, Map("name" ->a)) diff --git a/src/main/scala/com/phasmidsoftware/render/Renderers.scala b/src/main/scala/com/phasmidsoftware/render/Renderers.scala index f955c6b..626e0a9 100644 --- a/src/main/scala/com/phasmidsoftware/render/Renderers.scala +++ b/src/main/scala/com/phasmidsoftware/render/Renderers.scala @@ -10,8 +10,8 @@ import com.phasmidsoftware.util.Reflection import scala.reflect.ClassTag /** - * Trait to define the various renderers for writing case classes and their parameters to hierarchical output elements. - * + * Trait to define various renderers for rendering instance of case classes (with their various parameters), + * containers (Seq and Option), etc. to hierarchical output elements such as XML or HTML. * */ trait Renderers { @@ -26,11 +26,9 @@ trait Renderers { * @return a Renderer[Seq[String] ] */ def headerRenderer(style: String, attrs: Map[String, String] = Map())(stringRenderer: Renderer[String]): Renderer[Header] = new TaggedRenderer[Header](style, attrs) { - override def render[U: TreeWriter](h: Header, attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, None, attrs, h.xs.map((t: String) => stringRenderer.render(t, Map()))) + override def render[U: TreeWriter](h: Header, attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, attrs, h.xs.map((t: String) => stringRenderer.render(t))) } - // sequenceRenderer(style, attrs).asInstanceOf[Renderer[Header]] - /** * Render an sequence of P as a U. * NOTE: there are no identifiers generated with this Renderer. @@ -39,7 +37,7 @@ trait Renderers { * @return a new instance of U. */ def sequenceRenderer[P: Renderer](style: String, attrs: Map[String, String] = Map()): Renderer[Seq[P]] = new TaggedRenderer[Seq[P]](style, attrs) { - override def render[U: TreeWriter](ps: Seq[P], attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, None, attrs, ps map ((t: P) => implicitly[Renderer[P]].render(t, Map()))) + override def render[U: TreeWriter](ps: Seq[P], attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, attrs, ps map (implicitly[Renderer[P]].render(_))) } /** @@ -61,7 +59,7 @@ trait Renderers { * @return a new instance of U. */ def optionRenderer[P: Renderer]: Renderer[Option[P]] = new UntaggedRenderer[Option[P]] { - override def render[U: TreeWriter](po: Option[P], attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, None, attrs, po.toSeq map ((t: P) => implicitly[Renderer[P]].render(t, Map()))) + override def render[U: TreeWriter](po: Option[P], attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, attrs, po.toSeq map (implicitly[Renderer[P]].render(_))) } /** @@ -92,7 +90,6 @@ trait Renderers { * @return a Renderer which converts an instance of T into an instance of U. */ def rendererExplicit[T: Renderer](style: String, attrs: Map[String, String] = Map())(f: T => String): Renderer[T] = new TaggedRenderer[T](style, attrs) { - override def asString(t: T): String = f(t) } @@ -108,12 +105,14 @@ trait Renderers { * @tparam T the underlying type of the result, a Product. * @return a Renderer which converts a String from a Row into the field type P and thence into a T */ - def renderer1[P1: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: P1 => T): Renderer[T] = new TaggedRenderer[T](style, attrs) { - val Array(p1) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) - - override def render[U: TreeWriter](t: T, attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, None, attrs, Seq( - implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) - )) + def renderer1[P1: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: P1 => T): Renderer[T] = new ProductRenderer[T](style, attrs) { + + protected def us[U: TreeWriter](t: T): Seq[U] = { + val Array(p1) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) + Seq( + implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) + ) + } } /** @@ -125,13 +124,15 @@ trait Renderers { * @tparam T the underlying type of the result, a Product. * @return a Renderer which converts Strings from a Row into the field types P1 and P2 and thence into a T */ - def renderer2[P1: Renderer, P2: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2) => T): Renderer[T] = new TaggedRenderer[T](style, attrs) { - val Array(p1, p2) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) - - override def render[U: TreeWriter](t: T, attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, None, attrs, Seq( - implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) - , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) - )) + def renderer2[P1: Renderer, P2: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2) => T): Renderer[T] = new ProductRenderer[T](style, attrs) { + + protected def us[U: TreeWriter](t: T): Seq[U] = { + val Array(p1, p2) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) + Seq( + implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) + , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) + ) + } } /** @@ -144,14 +145,16 @@ trait Renderers { * @tparam T the underlying type of the result, a Product. * @return a Renderer which converts Strings from a Row into the field types P1, P2 and P3 and thence into a T */ - def renderer3[P1: Renderer, P2: Renderer, P3: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2, P3) => T): Renderer[T] = new TaggedRenderer[T](style, attrs) { - val Array(p1, p2, p3) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) - - override def render[U: TreeWriter](t: T, attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, None, attrs, Seq( - implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) - , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) - , implicitly[Renderer[P3]].render(t.productElement(2).asInstanceOf[P3], nameAttr(p3)) - )) + def renderer3[P1: Renderer, P2: Renderer, P3: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2, P3) => T): Renderer[T] = new ProductRenderer[T](style, attrs) { + + protected def us[U: TreeWriter](t: T): Seq[U] = { + val Array(p1, p2, p3) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) + Seq( + implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) + , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) + , implicitly[Renderer[P3]].render(t.productElement(2).asInstanceOf[P3], nameAttr(p3)) + ) + } } /** @@ -165,15 +168,17 @@ trait Renderers { * @tparam T the underlying type of the result, a Product. * @return a Renderer which converts Strings from a Row into the field types P1, P2, P3 and P4 and thence into a T */ - def renderer4[P1: Renderer, P2: Renderer, P3: Renderer, P4: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2, P3, P4) => T): Renderer[T] = new TaggedRenderer[T](style, attrs) { - val Array(p1, p2, p3, p4) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) - - override def render[U: TreeWriter](t: T, attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, None, attrs, Seq( - implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) - , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) - , implicitly[Renderer[P3]].render(t.productElement(2).asInstanceOf[P3], nameAttr(p3)) - , implicitly[Renderer[P4]].render(t.productElement(3).asInstanceOf[P4], nameAttr(p4)) - )) + def renderer4[P1: Renderer, P2: Renderer, P3: Renderer, P4: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2, P3, P4) => T): Renderer[T] = new ProductRenderer[T](style, attrs) { + + protected def us[U: TreeWriter](t: T): Seq[U] = { + val Array(p1, p2, p3, p4) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) + Seq( + implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) + , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) + , implicitly[Renderer[P3]].render(t.productElement(2).asInstanceOf[P3], nameAttr(p3)) + , implicitly[Renderer[P4]].render(t.productElement(3).asInstanceOf[P4], nameAttr(p4)) + ) + } } /** @@ -188,16 +193,18 @@ trait Renderers { * @tparam T the underlying type of the result, a Product. * @return a Renderer which converts Strings from a Row into the field types P1, P2, P3, P4 and P5 and thence into a T */ - def renderer5[P1: Renderer, P2: Renderer, P3: Renderer, P4: Renderer, P5: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2, P3, P4, P5) => T): Renderer[T] = new TaggedRenderer[T](style, attrs) { - val Array(p1, p2, p3, p4, p5) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) - - override def render[U: TreeWriter](t: T, attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, None, attrs, Seq( - implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) - , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) - , implicitly[Renderer[P3]].render(t.productElement(2).asInstanceOf[P3], nameAttr(p3)) - , implicitly[Renderer[P4]].render(t.productElement(3).asInstanceOf[P4], nameAttr(p4)) - , implicitly[Renderer[P5]].render(t.productElement(4).asInstanceOf[P5], nameAttr(p5)) - )) + def renderer5[P1: Renderer, P2: Renderer, P3: Renderer, P4: Renderer, P5: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2, P3, P4, P5) => T): Renderer[T] = new ProductRenderer[T](style, attrs) { + + protected def us[U: TreeWriter](t: T): Seq[U] = { + val Array(p1, p2, p3, p4, p5) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) + Seq( + implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) + , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) + , implicitly[Renderer[P3]].render(t.productElement(2).asInstanceOf[P3], nameAttr(p3)) + , implicitly[Renderer[P4]].render(t.productElement(3).asInstanceOf[P4], nameAttr(p4)) + , implicitly[Renderer[P5]].render(t.productElement(4).asInstanceOf[P5], nameAttr(p5)) + ) + } } /** @@ -213,17 +220,18 @@ trait Renderers { * @tparam T the underlying type of the result, a Product. * @return a Renderer which converts Strings from a Row into the field types P1, P2, P3, P4, P5 and P6 and thence into a T */ - def renderer6[P1: Renderer, P2: Renderer, P3: Renderer, P4: Renderer, P5: Renderer, P6: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2, P3, P4, P5, P6) => T): Renderer[T] = new TaggedRenderer[T](style, attrs) { - val Array(p1, p2, p3, p4, p5, p6) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) - - override def render[U: TreeWriter](t: T, attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, None, attrs, Seq( - implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) - , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) - , implicitly[Renderer[P3]].render(t.productElement(2).asInstanceOf[P3], nameAttr(p3)) - , implicitly[Renderer[P4]].render(t.productElement(3).asInstanceOf[P4], nameAttr(p4)) - , implicitly[Renderer[P5]].render(t.productElement(4).asInstanceOf[P5], nameAttr(p5)) - , implicitly[Renderer[P6]].render(t.productElement(5).asInstanceOf[P6], nameAttr(p6)) - )) + def renderer6[P1: Renderer, P2: Renderer, P3: Renderer, P4: Renderer, P5: Renderer, P6: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2, P3, P4, P5, P6) => T): Renderer[T] = new ProductRenderer[T](style, attrs) { + protected def us[U: TreeWriter](t: T): Seq[U] = { + val Array(p1, p2, p3, p4, p5, p6) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) + Seq( + implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) + , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) + , implicitly[Renderer[P3]].render(t.productElement(2).asInstanceOf[P3], nameAttr(p3)) + , implicitly[Renderer[P4]].render(t.productElement(3).asInstanceOf[P4], nameAttr(p4)) + , implicitly[Renderer[P5]].render(t.productElement(4).asInstanceOf[P5], nameAttr(p5)) + , implicitly[Renderer[P6]].render(t.productElement(5).asInstanceOf[P6], nameAttr(p6)) + ) + } } /** @@ -240,18 +248,20 @@ trait Renderers { * @tparam T the underlying type of the result, a Product. * @return a Renderer which converts Strings from a Row into the field types P1, P2, P3, P4, P5, P6 and P7 and thence into a T */ - def renderer7[P1: Renderer, P2: Renderer, P3: Renderer, P4: Renderer, P5: Renderer, P6: Renderer, P7: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2, P3, P4, P5, P6, P7) => T): Renderer[T] = new TaggedRenderer[T](style, attrs) { - val Array(p1, p2, p3, p4, p5, p6, p7) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) - - override def render[U: TreeWriter](t: T, attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, None, attrs, Seq( - implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) - , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) - , implicitly[Renderer[P3]].render(t.productElement(2).asInstanceOf[P3], nameAttr(p3)) - , implicitly[Renderer[P4]].render(t.productElement(3).asInstanceOf[P4], nameAttr(p4)) - , implicitly[Renderer[P5]].render(t.productElement(4).asInstanceOf[P5], nameAttr(p5)) - , implicitly[Renderer[P6]].render(t.productElement(5).asInstanceOf[P6], nameAttr(p6)) - , implicitly[Renderer[P7]].render(t.productElement(6).asInstanceOf[P7], nameAttr(p7)) - )) + def renderer7[P1: Renderer, P2: Renderer, P3: Renderer, P4: Renderer, P5: Renderer, P6: Renderer, P7: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2, P3, P4, P5, P6, P7) => T): Renderer[T] = new ProductRenderer[T](style, attrs) { + + protected def us[U: TreeWriter](t: T): Seq[U] = { + val Array(p1, p2, p3, p4, p5, p6, p7) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) + Seq( + implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) + , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) + , implicitly[Renderer[P3]].render(t.productElement(2).asInstanceOf[P3], nameAttr(p3)) + , implicitly[Renderer[P4]].render(t.productElement(3).asInstanceOf[P4], nameAttr(p4)) + , implicitly[Renderer[P5]].render(t.productElement(4).asInstanceOf[P5], nameAttr(p5)) + , implicitly[Renderer[P6]].render(t.productElement(5).asInstanceOf[P6], nameAttr(p6)) + , implicitly[Renderer[P7]].render(t.productElement(6).asInstanceOf[P7], nameAttr(p7)) + ) + } } /** @@ -269,19 +279,21 @@ trait Renderers { * @tparam T the underlying type of the result, a Product. * @return a Renderer which converts Strings from a Row into the field types P1, P2, P3, P4, P5, P6, P7 and P8 and thence into a T */ - def renderer8[P1: Renderer, P2: Renderer, P3: Renderer, P4: Renderer, P5: Renderer, P6: Renderer, P7: Renderer, P8: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2, P3, P4, P5, P6, P7, P8) => T): Renderer[T] = new TaggedRenderer[T](style, attrs) { - val Array(p1, p2, p3, p4, p5, p6, p7, p8) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) - - override def render[U: TreeWriter](t: T, attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, None, attrs, Seq( - implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) - , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) - , implicitly[Renderer[P3]].render(t.productElement(2).asInstanceOf[P3], nameAttr(p3)) - , implicitly[Renderer[P4]].render(t.productElement(3).asInstanceOf[P4], nameAttr(p4)) - , implicitly[Renderer[P5]].render(t.productElement(4).asInstanceOf[P5], nameAttr(p5)) - , implicitly[Renderer[P6]].render(t.productElement(5).asInstanceOf[P6], nameAttr(p6)) - , implicitly[Renderer[P7]].render(t.productElement(6).asInstanceOf[P7], nameAttr(p7)) - , implicitly[Renderer[P8]].render(t.productElement(7).asInstanceOf[P8], nameAttr(p8)) - )) + def renderer8[P1: Renderer, P2: Renderer, P3: Renderer, P4: Renderer, P5: Renderer, P6: Renderer, P7: Renderer, P8: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2, P3, P4, P5, P6, P7, P8) => T): Renderer[T] = new ProductRenderer[T](style, attrs) { + + protected def us[U: TreeWriter](t: T): Seq[U] = { + val Array(p1, p2, p3, p4, p5, p6, p7, p8) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) + Seq( + implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) + , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) + , implicitly[Renderer[P3]].render(t.productElement(2).asInstanceOf[P3], nameAttr(p3)) + , implicitly[Renderer[P4]].render(t.productElement(3).asInstanceOf[P4], nameAttr(p4)) + , implicitly[Renderer[P5]].render(t.productElement(4).asInstanceOf[P5], nameAttr(p5)) + , implicitly[Renderer[P6]].render(t.productElement(5).asInstanceOf[P6], nameAttr(p6)) + , implicitly[Renderer[P7]].render(t.productElement(6).asInstanceOf[P7], nameAttr(p7)) + , implicitly[Renderer[P8]].render(t.productElement(7).asInstanceOf[P8], nameAttr(p8)) + ) + } } /** @@ -300,20 +312,22 @@ trait Renderers { * @tparam T the underlying type of the result, a Product. * @return a Renderer which converts Strings from a Row into the field types P1, P2, P3, P4, P5, P6, P7, P8 and P9 and thence into a T */ - def renderer9[P1: Renderer, P2: Renderer, P3: Renderer, P4: Renderer, P5: Renderer, P6: Renderer, P7: Renderer, P8: Renderer, P9: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2, P3, P4, P5, P6, P7, P8, P9) => T): Renderer[T] = new TaggedRenderer[T](style, attrs) { - val Array(p1, p2, p3, p4, p5, p6, p7, p8, p9) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) - - override def render[U: TreeWriter](t: T, attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, None, attrs, Seq( - implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) - , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) - , implicitly[Renderer[P3]].render(t.productElement(2).asInstanceOf[P3], nameAttr(p3)) - , implicitly[Renderer[P4]].render(t.productElement(3).asInstanceOf[P4], nameAttr(p4)) - , implicitly[Renderer[P5]].render(t.productElement(4).asInstanceOf[P5], nameAttr(p5)) - , implicitly[Renderer[P6]].render(t.productElement(5).asInstanceOf[P6], nameAttr(p6)) - , implicitly[Renderer[P7]].render(t.productElement(6).asInstanceOf[P7], nameAttr(p7)) - , implicitly[Renderer[P8]].render(t.productElement(7).asInstanceOf[P8], nameAttr(p8)) - , implicitly[Renderer[P9]].render(t.productElement(8).asInstanceOf[P9], nameAttr(p9)) - )) + def renderer9[P1: Renderer, P2: Renderer, P3: Renderer, P4: Renderer, P5: Renderer, P6: Renderer, P7: Renderer, P8: Renderer, P9: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2, P3, P4, P5, P6, P7, P8, P9) => T): Renderer[T] = new ProductRenderer[T](style, attrs) { + + protected def us[U: TreeWriter](t: T): Seq[U] = { + val Array(p1, p2, p3, p4, p5, p6, p7, p8, p9) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) + Seq( + implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) + , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) + , implicitly[Renderer[P3]].render(t.productElement(2).asInstanceOf[P3], nameAttr(p3)) + , implicitly[Renderer[P4]].render(t.productElement(3).asInstanceOf[P4], nameAttr(p4)) + , implicitly[Renderer[P5]].render(t.productElement(4).asInstanceOf[P5], nameAttr(p5)) + , implicitly[Renderer[P6]].render(t.productElement(5).asInstanceOf[P6], nameAttr(p6)) + , implicitly[Renderer[P7]].render(t.productElement(6).asInstanceOf[P7], nameAttr(p7)) + , implicitly[Renderer[P8]].render(t.productElement(7).asInstanceOf[P8], nameAttr(p8)) + , implicitly[Renderer[P9]].render(t.productElement(8).asInstanceOf[P9], nameAttr(p9)) + ) + } } /** @@ -333,21 +347,23 @@ trait Renderers { * @tparam T the underlying type of the result, a Product. * @return a Renderer which converts Strings from a Row into the field types P1, P2, P3, P4, P5, P6, P7, P8, P9 and P10 and thence into a T */ - def renderer10[P1: Renderer, P2: Renderer, P3: Renderer, P4: Renderer, P5: Renderer, P6: Renderer, P7: Renderer, P8: Renderer, P9: Renderer, P10: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) => T): Renderer[T] = new TaggedRenderer[T](style, attrs) { - val Array(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) - - override def render[U: TreeWriter](t: T, attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, None, attrs, Seq( - implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) - , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) - , implicitly[Renderer[P3]].render(t.productElement(2).asInstanceOf[P3], nameAttr(p3)) - , implicitly[Renderer[P4]].render(t.productElement(3).asInstanceOf[P4], nameAttr(p4)) - , implicitly[Renderer[P5]].render(t.productElement(4).asInstanceOf[P5], nameAttr(p5)) - , implicitly[Renderer[P6]].render(t.productElement(5).asInstanceOf[P6], nameAttr(p6)) - , implicitly[Renderer[P7]].render(t.productElement(6).asInstanceOf[P7], nameAttr(p7)) - , implicitly[Renderer[P8]].render(t.productElement(7).asInstanceOf[P8], nameAttr(p8)) - , implicitly[Renderer[P9]].render(t.productElement(8).asInstanceOf[P9], nameAttr(p9)) - , implicitly[Renderer[P10]].render(t.productElement(9).asInstanceOf[P10], nameAttr(p10)) - )) + def renderer10[P1: Renderer, P2: Renderer, P3: Renderer, P4: Renderer, P5: Renderer, P6: Renderer, P7: Renderer, P8: Renderer, P9: Renderer, P10: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) => T): Renderer[T] = new ProductRenderer[T](style, attrs) { + + protected def us[U: TreeWriter](t: T): Seq[U] = { + val Array(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) + Seq( + implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) + , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) + , implicitly[Renderer[P3]].render(t.productElement(2).asInstanceOf[P3], nameAttr(p3)) + , implicitly[Renderer[P4]].render(t.productElement(3).asInstanceOf[P4], nameAttr(p4)) + , implicitly[Renderer[P5]].render(t.productElement(4).asInstanceOf[P5], nameAttr(p5)) + , implicitly[Renderer[P6]].render(t.productElement(5).asInstanceOf[P6], nameAttr(p6)) + , implicitly[Renderer[P7]].render(t.productElement(6).asInstanceOf[P7], nameAttr(p7)) + , implicitly[Renderer[P8]].render(t.productElement(7).asInstanceOf[P8], nameAttr(p8)) + , implicitly[Renderer[P9]].render(t.productElement(8).asInstanceOf[P9], nameAttr(p9)) + , implicitly[Renderer[P10]].render(t.productElement(9).asInstanceOf[P10], nameAttr(p10)) + ) + } } /** @@ -368,22 +384,24 @@ trait Renderers { * @tparam T the underlying type of the result, a Product. * @return a Renderer which converts Strings from a Row into the field types P1, P2, P3, P4, P5, P6, P7, P8, P9, P10 and P11 and thence into a T */ - def renderer11[P1: Renderer, P2: Renderer, P3: Renderer, P4: Renderer, P5: Renderer, P6: Renderer, P7: Renderer, P8: Renderer, P9: Renderer, P10: Renderer, P11: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) => T): Renderer[T] = new TaggedRenderer[T](style, attrs) { - val Array(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) - - override def render[U: TreeWriter](t: T, attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, None, attrs, Seq( - implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) - , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) - , implicitly[Renderer[P3]].render(t.productElement(2).asInstanceOf[P3], nameAttr(p3)) - , implicitly[Renderer[P4]].render(t.productElement(3).asInstanceOf[P4], nameAttr(p4)) - , implicitly[Renderer[P5]].render(t.productElement(4).asInstanceOf[P5], nameAttr(p5)) - , implicitly[Renderer[P6]].render(t.productElement(5).asInstanceOf[P6], nameAttr(p6)) - , implicitly[Renderer[P7]].render(t.productElement(6).asInstanceOf[P7], nameAttr(p7)) - , implicitly[Renderer[P8]].render(t.productElement(7).asInstanceOf[P8], nameAttr(p8)) - , implicitly[Renderer[P9]].render(t.productElement(8).asInstanceOf[P9], nameAttr(p9)) - , implicitly[Renderer[P10]].render(t.productElement(9).asInstanceOf[P10], nameAttr(p10)) - , implicitly[Renderer[P11]].render(t.productElement(10).asInstanceOf[P11], nameAttr(p11)) - )) + def renderer11[P1: Renderer, P2: Renderer, P3: Renderer, P4: Renderer, P5: Renderer, P6: Renderer, P7: Renderer, P8: Renderer, P9: Renderer, P10: Renderer, P11: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) => T): Renderer[T] = new ProductRenderer[T](style, attrs) { + + protected def us[U: TreeWriter](t: T): Seq[U] = { + val Array(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) + Seq( + implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) + , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) + , implicitly[Renderer[P3]].render(t.productElement(2).asInstanceOf[P3], nameAttr(p3)) + , implicitly[Renderer[P4]].render(t.productElement(3).asInstanceOf[P4], nameAttr(p4)) + , implicitly[Renderer[P5]].render(t.productElement(4).asInstanceOf[P5], nameAttr(p5)) + , implicitly[Renderer[P6]].render(t.productElement(5).asInstanceOf[P6], nameAttr(p6)) + , implicitly[Renderer[P7]].render(t.productElement(6).asInstanceOf[P7], nameAttr(p7)) + , implicitly[Renderer[P8]].render(t.productElement(7).asInstanceOf[P8], nameAttr(p8)) + , implicitly[Renderer[P9]].render(t.productElement(8).asInstanceOf[P9], nameAttr(p9)) + , implicitly[Renderer[P10]].render(t.productElement(9).asInstanceOf[P10], nameAttr(p10)) + , implicitly[Renderer[P11]].render(t.productElement(10).asInstanceOf[P11], nameAttr(p11)) + ) + } } /** @@ -405,32 +423,26 @@ trait Renderers { * @tparam T the underlying type of the result, a Product. * @return a Renderer which converts Strings from a Row into the field types P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11 and P12 and thence into a T */ - def renderer12[P1: Renderer, P2: Renderer, P3: Renderer, P4: Renderer, P5: Renderer, P6: Renderer, P7: Renderer, P8: Renderer, P9: Renderer, P10: Renderer, P11: Renderer, P12: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) => T): Renderer[T] = new TaggedRenderer[T](style) { - val Array(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) - - override def render[U: TreeWriter](t: T, attrs: Map[String, String]): U = implicitly[TreeWriter[U]].node(style, None, attrs, Seq( - implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) - , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) - , implicitly[Renderer[P3]].render(t.productElement(2).asInstanceOf[P3], nameAttr(p3)) - , implicitly[Renderer[P4]].render(t.productElement(3).asInstanceOf[P4], nameAttr(p4)) - , implicitly[Renderer[P5]].render(t.productElement(4).asInstanceOf[P5], nameAttr(p5)) - , implicitly[Renderer[P6]].render(t.productElement(5).asInstanceOf[P6], nameAttr(p6)) - , implicitly[Renderer[P7]].render(t.productElement(6).asInstanceOf[P7], nameAttr(p7)) - , implicitly[Renderer[P8]].render(t.productElement(7).asInstanceOf[P8], nameAttr(p8)) - , implicitly[Renderer[P9]].render(t.productElement(8).asInstanceOf[P9], nameAttr(p9)) - , implicitly[Renderer[P10]].render(t.productElement(9).asInstanceOf[P10], nameAttr(p10)) - , implicitly[Renderer[P11]].render(t.productElement(10).asInstanceOf[P11], nameAttr(p11)) - , implicitly[Renderer[P12]].render(t.productElement(11).asInstanceOf[P12], nameAttr(p12)) - )) + def renderer12[P1: Renderer, P2: Renderer, P3: Renderer, P4: Renderer, P5: Renderer, P6: Renderer, P7: Renderer, P8: Renderer, P9: Renderer, P10: Renderer, P11: Renderer, P12: Renderer, T <: Product : ClassTag](style: String, attrs: Map[String, String] = Map())(construct: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) => T): Renderer[T] = new ProductRenderer[T](style) { + + protected def us[U: TreeWriter](t: T): Seq[U] = { + val Array(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12) = Reflection.extractFieldNames(implicitly[ClassTag[T]]) + Seq( + implicitly[Renderer[P1]].render(t.productElement(0).asInstanceOf[P1], nameAttr(p1)) + , implicitly[Renderer[P2]].render(t.productElement(1).asInstanceOf[P2], nameAttr(p2)) + , implicitly[Renderer[P3]].render(t.productElement(2).asInstanceOf[P3], nameAttr(p3)) + , implicitly[Renderer[P4]].render(t.productElement(3).asInstanceOf[P4], nameAttr(p4)) + , implicitly[Renderer[P5]].render(t.productElement(4).asInstanceOf[P5], nameAttr(p5)) + , implicitly[Renderer[P6]].render(t.productElement(5).asInstanceOf[P6], nameAttr(p6)) + , implicitly[Renderer[P7]].render(t.productElement(6).asInstanceOf[P7], nameAttr(p7)) + , implicitly[Renderer[P8]].render(t.productElement(7).asInstanceOf[P8], nameAttr(p8)) + , implicitly[Renderer[P9]].render(t.productElement(8).asInstanceOf[P9], nameAttr(p9)) + , implicitly[Renderer[P10]].render(t.productElement(9).asInstanceOf[P10], nameAttr(p10)) + , implicitly[Renderer[P11]].render(t.productElement(10).asInstanceOf[P11], nameAttr(p11)) + , implicitly[Renderer[P12]].render(t.productElement(11).asInstanceOf[P12], nameAttr(p12)) + ) + } } def nameAttr(value: String): Map[String, String] = Map("name" -> value) } - -/** - * This companion object comprises Renderer[T] objects which represent conversions that are fixed, - * i.e. they don't depend on some other parameter such as the formatter in DateTime conversions. - */ -object Renderers { - -} diff --git a/src/main/scala/com/phasmidsoftware/render/TreeWriter.scala b/src/main/scala/com/phasmidsoftware/render/TreeWriter.scala index d6f7a29..49b873a 100644 --- a/src/main/scala/com/phasmidsoftware/render/TreeWriter.scala +++ b/src/main/scala/com/phasmidsoftware/render/TreeWriter.scala @@ -20,8 +20,16 @@ trait TreeWriter[U] { def node(tag: String, content: Option[String], attributes: Map[String, String], children: Seq[U]): U + def node(tag: String, attributes: Map[String, String], children: Seq[U]): U = node(tag, None, attributes, children) + + def node(tag: String, children: Seq[U]): U = node(tag, Map[String, String](), children) + def node(tag: String, content: Option[String], attributes: Map[String, String]): U = node(tag, content, attributes, Nil) + def node(tag: String, attributes: Map[String, String]): U = node(tag, None, attributes) + + def node(tag: String): U = node(tag, Nil) + def addChild(parent: U, child: U): U } diff --git a/src/main/scala/com/phasmidsoftware/table/Table.scala b/src/main/scala/com/phasmidsoftware/table/Table.scala index fa67ebc..9e1b3e0 100644 --- a/src/main/scala/com/phasmidsoftware/table/Table.scala +++ b/src/main/scala/com/phasmidsoftware/table/Table.scala @@ -97,10 +97,8 @@ trait Table[Row] extends Iterable[Row] { val headerRenderer: Renderer[Header] = headerRenderer("th")(renderer("td", Map())) } import TableRenderers._ - val q: Seq[Indexed[Row]] = Indexed.index(rows) - val z: U = rowsRenderer.render(q, Map()) - val uo: Option[U] = maybeHeader map (headerRenderer.render(_, Map())) - implicitly[TreeWriter[U]].node(style, None, attributes, uo.toSeq ++ Seq(z)) + val uo: Option[U] = maybeHeader map (headerRenderer.render(_)) + implicitly[TreeWriter[U]].node(style, attributes, uo.toSeq ++ Seq(rowsRenderer.render(Indexed.index(rows)))) } } diff --git a/src/test/scala/com/phasmidsoftware/render/TreeWriterSpec.scala b/src/test/scala/com/phasmidsoftware/render/TreeWriterSpec.scala index dd5d330..64670fd 100644 --- a/src/test/scala/com/phasmidsoftware/render/TreeWriterSpec.scala +++ b/src/test/scala/com/phasmidsoftware/render/TreeWriterSpec.scala @@ -38,8 +38,8 @@ class TreeWriterSpec extends FlatSpec with Matchers { import HTML._ it should "implement node correctly for 1" in { - implicitly[TreeWriter[HTML]].node("1", None, Map.empty) shouldBe HTML("1") - implicitly[TreeWriter[HTML]].node("1", None, Map("name" -> "x")) shouldBe HTML("1", None, Map("name" -> "x")) + implicitly[TreeWriter[HTML]].node("1") shouldBe HTML("1") + implicitly[TreeWriter[HTML]].node("1", Map("name" -> "x")) shouldBe HTML("1", None, Map("name" -> "x")) } From 685536e2fbf663e32d15de83fbfd86fbb1e13b34 Mon Sep 17 00:00:00 2001 From: Robin Hillyard Date: Wed, 10 Apr 2019 11:28:52 -0400 Subject: [PATCH 3/3] v1.0.4 Final commit Row and column headers for table rendering are available but I intend to improve the structure and logic in a future release. --- README.md | 3 +++ build.sbt | 2 +- src/main/scala/com/phasmidsoftware/render/Renderer.scala | 5 ++--- src/main/scala/com/phasmidsoftware/render/Renderers.scala | 2 +- src/test/scala/com/phasmidsoftware/render/RendererSpec.scala | 2 +- src/test/scala/com/phasmidsoftware/table/TableSpec.scala | 2 +- 6 files changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 1aba528..bece5b0 100644 --- a/README.md +++ b/README.md @@ -378,6 +378,9 @@ If you need to set HTML attributes for a specific type, for example a row in the Release Notes ============= +V1.0.3 -> V1.0.4 +* Added the ability to add header row and header column for tables (NOTE: not finalized yet, but functional). + V1.0.2 -> V1.0.3 * Added no implicit warnings * Created mechanism for rendering the result of parsing in a hierarchical structure. diff --git a/build.sbt b/build.sbt index fdcae8e..614f9aa 100755 --- a/build.sbt +++ b/build.sbt @@ -2,7 +2,7 @@ organization := "com.phasmidsoftware" name := "TableParser" -version := "1.0.4-SNAPSHOT" +version := "1.0.4" scalaVersion := "2.12.6" diff --git a/src/main/scala/com/phasmidsoftware/render/Renderer.scala b/src/main/scala/com/phasmidsoftware/render/Renderer.scala index 38770c6..9b71afc 100644 --- a/src/main/scala/com/phasmidsoftware/render/Renderer.scala +++ b/src/main/scala/com/phasmidsoftware/render/Renderer.scala @@ -80,7 +80,7 @@ abstract class ProductRenderer[T <: Product : ClassTag](val style: String, overr protected def us[U: TreeWriter](t: T): Seq[U] } -abstract class IndexedRenderer[T: Renderer](val style: String, override val baseAttrs: Map[String, String] = Map()) extends Renderer[Indexed[T]] { +abstract class IndexedRenderer[T: Renderer](val style: String, indexStyle: String, override val baseAttrs: Map[String, String] = Map()) extends Renderer[Indexed[T]] { /** * Render an instance of Indexed[T] as a U. * @@ -90,8 +90,7 @@ abstract class IndexedRenderer[T: Renderer](val style: String, override val base * @return a new instance of U. */ override def render[U: TreeWriter](ti: Indexed[T], attrs: Map[String, String]): U = { - // TODO specify style as header, but not with HTML-specific "th". - val indexRenderer: Renderer[Int] = new TaggedRenderer[Int]("th") {} + val indexRenderer: Renderer[Int] = new TaggedRenderer[Int](indexStyle) {} implicitly[TreeWriter[U]].node(style, Seq(indexRenderer.render(ti.i), implicitly[Renderer[T]].render(ti.t))) } } diff --git a/src/main/scala/com/phasmidsoftware/render/Renderers.scala b/src/main/scala/com/phasmidsoftware/render/Renderers.scala index 626e0a9..eb26417 100644 --- a/src/main/scala/com/phasmidsoftware/render/Renderers.scala +++ b/src/main/scala/com/phasmidsoftware/render/Renderers.scala @@ -47,7 +47,7 @@ trait Renderers { * @tparam P the type of the result. * @return a new instance of U. */ - def indexedRenderer[P: Renderer](style: String, attrs: Map[String, String] = Map()): Renderer[Indexed[P]] = new IndexedRenderer[P](style, attrs) {} + def indexedRenderer[P: Renderer](style: String, indexStyle: String, attrs: Map[String, String] = Map()): Renderer[Indexed[P]] = new IndexedRenderer[P](style, indexStyle, attrs) {} /** * Render an option of P as a U. diff --git a/src/test/scala/com/phasmidsoftware/render/RendererSpec.scala b/src/test/scala/com/phasmidsoftware/render/RendererSpec.scala index 45daf53..b1a2b98 100644 --- a/src/test/scala/com/phasmidsoftware/render/RendererSpec.scala +++ b/src/test/scala/com/phasmidsoftware/render/RendererSpec.scala @@ -40,7 +40,7 @@ class RendererSpec extends FlatSpec with Matchers { object Complex2 extends Renderers { implicit val valueRenderer: Renderer[Double] = renderer("td") implicit val complexRenderer: Renderer[Complex] = renderer2("span")(Complex) - implicit val indexedRenderer: Renderer[Indexed[Complex]] = indexedRenderer[Complex]("tr", Map()) + implicit val indexedRenderer: Renderer[Indexed[Complex]] = indexedRenderer[Complex]("tr", "th", Map()) // val rowsRenderer: Renderer[Seq[Indexed[Complex]]] = sequenceRenderer[Indexed[Complex]]("span") diff --git a/src/test/scala/com/phasmidsoftware/table/TableSpec.scala b/src/test/scala/com/phasmidsoftware/table/TableSpec.scala index d683f41..bc8a848 100644 --- a/src/test/scala/com/phasmidsoftware/table/TableSpec.scala +++ b/src/test/scala/com/phasmidsoftware/table/TableSpec.scala @@ -144,7 +144,7 @@ class TableSpec extends FlatSpec with Matchers { implicit object HTMLTreeWriter extends HTMLTreeWriter implicit val intPairRenderer: Renderer[IntPair] = renderer2("IntPair")(IntPair.apply) - implicit val r: Renderer[Indexed[IntPair]] = indexedRenderer("", Map()) + implicit val r: Renderer[Indexed[IntPair]] = indexedRenderer("", "th", Map()) }