aboutsummaryrefslogtreecommitdiff
path: root/library
diff options
context:
space:
mode:
authorFelix Mulder <felix.mulder@gmail.com>2016-12-14 16:40:31 +0100
committerGitHub <noreply@github.com>2016-12-14 16:40:31 +0100
commitba06bf06721f1a8de7d68d22ad7eba27fff90c43 (patch)
treea02167f1d4d786c027c600c0070c36055cbc2622 /library
parent19bc03c840f0d6f0678775625562cea5ad7193e7 (diff)
parent35e8fcb805e7780555cf48160f90c9da71bb1811 (diff)
downloaddotty-ba06bf06721f1a8de7d68d22ad7eba27fff90c43.tar.gz
dotty-ba06bf06721f1a8de7d68d22ad7eba27fff90c43.tar.bz2
dotty-ba06bf06721f1a8de7d68d22ad7eba27fff90c43.zip
Merge pull request #1761 from dotty-staging/topic/product-show
[REPL] Add show capability to common types
Diffstat (limited to 'library')
-rw-r--r--library/src/dotty/Show.scala102
-rw-r--r--library/test/dotty/ShowTests.scala69
2 files changed, 171 insertions, 0 deletions
diff --git a/library/src/dotty/Show.scala b/library/src/dotty/Show.scala
new file mode 100644
index 000000000..2feeb29ef
--- /dev/null
+++ b/library/src/dotty/Show.scala
@@ -0,0 +1,102 @@
+package dotty
+
+import scala.annotation.implicitNotFound
+
+@implicitNotFound("No member of type class Show could be found for ${T}")
+trait Show[-T] {
+ def show(t: T): String
+}
+
+/** Ideally show would only contain `defaultShow` and the pimped generic class,
+ * but since we can't change the current stdlib, we're stuck with providing
+ * default instances in this object
+ */
+object Show {
+ private[this] val defaultShow: Show[Any] = new Show[Any] {
+ def show(x: Any) = x.toString
+ }
+
+ /** This class implements pimping of all types to provide a show method.
+ * Currently it is quite permissive, if there's no instance of `Show[T]` for
+ * any `T`, we default to `T#toString`.
+ */
+ implicit class ShowValue[V](val v: V) extends AnyVal {
+ def show(implicit ev: Show[V] = defaultShow): String =
+ ev.show(v)
+ }
+
+ implicit val stringShow: Show[String] = new Show[String] {
+ // From 2.12 spec, `charEscapeSeq`:
+ // ‘\‘ (‘b‘ | ‘t‘ | ‘n‘ | ‘f‘ | ‘r‘ | ‘"‘ | ‘'‘ | ‘\‘)
+ def show(str: String) =
+ "\"" + {
+ val sb = new StringBuilder
+ str.foreach {
+ case '\b' => sb.append("\\b")
+ case '\t' => sb.append("\\t")
+ case '\n' => sb.append("\\n")
+ case '\f' => sb.append("\\f")
+ case '\r' => sb.append("\\r")
+ case '\'' => sb.append("\\'")
+ case '\"' => sb.append("\\\"")
+ case c => sb.append(c)
+ }
+ sb.toString
+ } + "\""
+ }
+
+ implicit val intShow: Show[Int] = new Show[Int] {
+ def show(i: Int) = i.toString
+ }
+
+ implicit val floatShow: Show[Float] = new Show[Float] {
+ def show(f: Float) = f + "f"
+ }
+
+ implicit val doubleShow: Show[Double] = new Show[Double] {
+ def show(d: Double) = d.toString
+ }
+
+ implicit val charShow: Show[Char] = new Show[Char] {
+ def show(c: Char) = "'" + (c match {
+ case '\b' => "\\b"
+ case '\t' => "\\t"
+ case '\n' => "\\n"
+ case '\f' => "\\f"
+ case '\r' => "\\r"
+ case '\'' => "\\'"
+ case '\"' => "\\\""
+ case c => c
+ }) + "'"
+ }
+
+ implicit def showList[T](implicit st: Show[T]): Show[List[T]] = new Show[List[T]] {
+ def show(xs: List[T]) =
+ if (xs.isEmpty) "Nil"
+ else "List(" + xs.map(_.show).mkString(", ") + ")"
+ }
+
+ implicit val showNil: Show[Nil.type] = new Show[Nil.type] {
+ def show(xs: Nil.type) = "Nil"
+ }
+
+ implicit def showOption[T](implicit st: Show[T]): Show[Option[T]] = new Show[Option[T]] {
+ def show(ot: Option[T]): String = ot match {
+ case Some(t) => "Some("+ st.show(t) + ")"
+ case none => "None"
+ }
+ }
+
+ implicit val showNone: Show[None.type] = new Show[None.type] {
+ def show(n: None.type) = "None"
+ }
+
+ implicit def showMap[K,V](implicit sk: Show[K], sv: Show[V]): Show[Map[K,V]] = new Show[Map[K,V]] {
+ def show(m: Map[K, V]) =
+ "Map(" + m.map { case (k, v) => sk.show(k) + " -> " + sv.show(v) } .mkString (", ") + ")"
+ }
+
+ implicit def showMapOfNothing: Show[Map[Nothing,Nothing]] = new Show[Map[Nothing,Nothing]] {
+ def show(m: Map[Nothing, Nothing]) = m.toString
+ }
+}
diff --git a/library/test/dotty/ShowTests.scala b/library/test/dotty/ShowTests.scala
new file mode 100644
index 000000000..7230106d5
--- /dev/null
+++ b/library/test/dotty/ShowTests.scala
@@ -0,0 +1,69 @@
+package dotty
+
+import org.junit.Test
+import org.junit.Assert._
+
+class ShowTests {
+ import Show._
+
+ @Test def showString = {
+ assertEquals("\"\\thello world!\"", "\thello world!".show)
+ assertEquals("\"\\nhello world!\"", "\nhello world!".show)
+ assertEquals("\"\\rhello world!\"", "\rhello world!".show)
+ assertEquals("\"\\b\\t\\n\\f\\r\\\'\\\"\"", "\b\t\n\f\r\'\"".show)
+ }
+
+ @Test def showFloat = {
+ assertEquals("1.0f", 1.0f.show)
+ assertEquals("1.0f", 1.0F.show)
+ }
+
+ @Test def showDouble = {
+ assertEquals("1.0", 1.0d.show)
+ assertEquals("1.0", 1.0.show)
+ }
+
+ @Test def showChar = {
+ assertEquals("'\\b'", '\b'.show)
+ assertEquals("'\\t'", '\t'.show)
+ assertEquals("'\\n'", '\n'.show)
+ assertEquals("'\\f'", '\f'.show)
+ assertEquals("'\\r'", '\r'.show)
+ assertEquals("'\\''", '\''.show)
+ assertEquals("'\\\"'", '\"'.show)
+ }
+
+ @Test def showCar = {
+ case class Car(model: String, manufacturer: String, year: Int)
+ implicit val showCar = new Show[Car] {
+ def show(c: Car) =
+ "Car(" + c.model.show + ", " + c.manufacturer.show + ", " + c.year.show + ")"
+ }
+
+ case class Shop(xs: List[Car], name: String)
+ implicit val showShop = new Show[Shop] {
+ def show(sh: Shop) =
+ "Shop(" + sh.xs.show + ", " + sh.name.show + ")"
+ }
+
+ assertEquals("Car(\"Mustang\", \"Ford\", 1967)", Car("Mustang", "Ford", 1967).show)
+ }
+
+ @Test def showOptions = {
+ assertEquals("None", None.show)
+ assertEquals("None", (None: Option[String]).show)
+ assertEquals("Some(\"hello opt\")", Some("hello opt").show)
+ }
+
+ @Test def showMaps = {
+ val mp = scala.collection.immutable.Map("str1" -> "val1", "str2" -> "val2")
+ assertEquals("Map(\"str1\" -> \"val1\", \"str2\" -> \"val2\")", mp.show)
+ }
+
+ @Test def withoutShow = {
+ case class Car(model: String, manufacturer: String, year: Int)
+
+ assertEquals("Car(Mustang,Ford,1967)", Car("Mustang", "Ford", 1967).show)
+ assertEquals("Map()", Map().show)
+ }
+}