Skip to content

Commit

Permalink
Merge pull request #7 from rchillyard/V1_0_4
Browse files Browse the repository at this point in the history
V1 0 4
  • Loading branch information
rchillyard authored Apr 15, 2019
2 parents 72c4ff4 + 685536e commit c70bb36
Show file tree
Hide file tree
Showing 10 changed files with 294 additions and 166 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ organization := "com.phasmidsoftware"

name := "TableParser"

version := "1.0.3"
version := "1.0.4"

scalaVersion := "2.12.6"

Expand Down
39 changes: 36 additions & 3 deletions src/main/scala/com/phasmidsoftware/render/Renderer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

package com.phasmidsoftware.render

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.
Expand All @@ -26,7 +28,17 @@ 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)

/**
* 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.
Expand All @@ -38,7 +50,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.
Expand All @@ -62,10 +74,31 @@ 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, indexStyle: 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](indexStyle) {}
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))
Expand Down
341 changes: 189 additions & 152 deletions src/main/scala/com/phasmidsoftware/render/Renderers.scala

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions src/main/scala/com/phasmidsoftware/render/TreeWriter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

15 changes: 15 additions & 0 deletions src/main/scala/com/phasmidsoftware/table/Row.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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(_))
}
8 changes: 5 additions & 3 deletions src/main/scala/com/phasmidsoftware/table/Table.scala
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,14 @@ 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 uo: Option[U] = maybeHeader map (headerRenderer.render(_))
implicitly[TreeWriter[U]].node(style, attributes, uo.toSeq ++ Seq(rowsRenderer.render(Indexed.index(rows))))
}
}

Expand Down
34 changes: 31 additions & 3 deletions src/test/scala/com/phasmidsoftware/render/RendererSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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", "th", 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] {
Expand Down Expand Up @@ -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)))
Expand All @@ -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)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
}


Expand Down
4 changes: 3 additions & 1 deletion src/test/scala/com/phasmidsoftware/table/TableSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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("", "th", 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())))))))
}


Expand Down

0 comments on commit c70bb36

Please sign in to comment.