aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Odersky <jakob@odersky.com>2018-04-08 16:24:00 -0700
committerJakob Odersky <jakob@odersky.com>2018-04-08 16:24:00 -0700
commit3fe7b06c5f357f34a5c227bc040effcbb259aef2 (patch)
tree1f83c575a6f59340403c7cfdd77969d61467f817
parentf1fe50cba0c07d27f109a727c480b02639d140e0 (diff)
downloadyamlesque-3fe7b06c5f357f34a5c227bc040effcbb259aef2.tar.gz
yamlesque-3fe7b06c5f357f34a5c227bc040effcbb259aef2.tar.bz2
yamlesque-3fe7b06c5f357f34a5c227bc040effcbb259aef2.zip
Add spray compatibility layer
-rw-r--r--build.sbt22
-rw-r--r--yamlesque-spray/src/main/scala/formats.scala40
-rw-r--r--yamlesque-spray/src/test/scala/FormatTests.scala53
-rw-r--r--yamlesque/src/main/scala/YamlPrinter.scala (renamed from yamlesque/src/main/scala/printers.scala)0
-rw-r--r--yamlesque/src/main/scala/formats.scala8
-rw-r--r--yamlesque/src/main/scala/package.scala19
-rw-r--r--yamlesque/src/main/scala/yamlValues.scala1
7 files changed, 140 insertions, 3 deletions
diff --git a/build.sbt b/build.sbt
index 0708cb1..5ae0dc5 100644
--- a/build.sbt
+++ b/build.sbt
@@ -1,13 +1,17 @@
// shadow sbt-scalajs' crossProject and CrossType until Scala.js 1.0.0 is released
import sbtcrossproject.{crossProject, CrossType}
+val testSettings = Seq(
+ libraryDependencies += "com.lihaoyi" %%% "utest" % "0.6.4" % "test",
+ testFrameworks += new TestFramework("utest.runner.Framework")
+)
+
+
lazy val yamlesque = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.crossType(CrossType.Pure)
+ .settings(testSettings)
.settings(
- libraryDependencies += "com.lihaoyi" %%% "utest" % "0.6.4" % "test",
- testFrameworks += new TestFramework("utest.runner.Framework"),
scalaVersion := crossScalaVersions.value.head
-
)
.jvmSettings(
crossScalaVersions := "2.12.4" :: "2.11.12" :: Nil
@@ -23,3 +27,15 @@ lazy val yamlesque = crossProject(JSPlatform, JVMPlatform, NativePlatform)
lazy val yamlesqueJVM = yamlesque.jvm
lazy val yamlesqueJS = yamlesque.js
lazy val yamlesqueNative = yamlesque.native
+
+lazy val yamlesqueSpray = crossProject(JSPlatform, JVMPlatform, NativePlatform)
+ .crossType(CrossType.Pure)
+ .in(file("yamlesque-spray"))
+ .dependsOn(yamlesque)
+ .settings(testSettings)
+ .settings(
+ libraryDependencies += "io.spray" %% "spray-json" % "1.3.4"
+ )
+lazy val yamlesqueSprayJVM = yamlesqueSpray.jvm
+lazy val yamlesqueSprayJS = yamlesqueSpray.js
+lazy val yamlesqueSprayNative = yamlesqueSpray.native
diff --git a/yamlesque-spray/src/main/scala/formats.scala b/yamlesque-spray/src/main/scala/formats.scala
new file mode 100644
index 0000000..4434347
--- /dev/null
+++ b/yamlesque-spray/src/main/scala/formats.scala
@@ -0,0 +1,40 @@
+package yamlesque
+
+import spray.json._
+
+trait JsonYamlFormats {
+
+ implicit def jsonToYamlReader[A](implicit jsReader: JsonReader[A]): YamlReader[A] = new YamlReader[A] {
+ override def read(yaml: YamlValue): A = jsReader.read(JsonFormats.yamlToJson(yaml))
+ }
+
+ implicit def jsonToYamlWriter[A](implicit jsWriter: JsonWriter[A]): YamlWriter[A] = new YamlWriter[A] {
+ override def write(a: A): YamlValue = JsonFormats.jsonToYaml(jsWriter.write(a))
+ }
+
+}
+
+object JsonFormats {
+
+ def jsonToYaml(js: JsValue): YamlValue = js match {
+ case JsNull => YamlScalar.Empty
+ case JsNumber(number) => YamlScalar(number.toString)
+ case JsBoolean(value) => YamlScalar(value.toString)
+ case JsString(value) => YamlScalar(value)
+ case JsArray(elements) => YamlSequence(elements.map(jsonToYaml _ ))
+ case JsObject(fields) => YamlMapping(fields.mapValues(jsonToYaml _ ))
+ }
+
+ val JsNumberPattern = """([-+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?)""".r
+
+ def yamlToJson(yaml: YamlValue): JsValue = yaml match {
+ case YamlScalar.Empty => JsNull
+ case YamlScalar("true") => JsTrue
+ case YamlScalar("false") => JsFalse
+ case YamlScalar(JsNumberPattern(x)) => JsNumber(x.toDouble)
+ case YamlScalar(x) => JsString(x)
+ case YamlSequence(elements) => JsArray(elements.map(yamlToJson))
+ case YamlMapping(fields) => JsObject(fields.mapValues(yamlToJson))
+ }
+
+}
diff --git a/yamlesque-spray/src/test/scala/FormatTests.scala b/yamlesque-spray/src/test/scala/FormatTests.scala
new file mode 100644
index 0000000..93d763a
--- /dev/null
+++ b/yamlesque-spray/src/test/scala/FormatTests.scala
@@ -0,0 +1,53 @@
+package yamlesque
+
+import spray.json._
+import utest._
+
+object FormatTests extends TestSuite {
+
+ case class A(a1: Int, a2: Seq[B])
+ case class B(a: String, b: Option[Boolean])
+
+ object Protocol extends DefaultJsonProtocol with JsonYamlFormats {
+ implicit def bFormat = jsonFormat2(B)
+ implicit def aFormat = jsonFormat2(A)
+ }
+ import Protocol._
+
+ val tests = Tests {
+ "parse" - {
+ val str =
+ s"""|a1: 42
+ |a2:
+ | - a: hello world
+ | b: true
+ | - a: yoyo
+ |""".stripMargin
+
+ "parse yaml" - {
+ str.parseYaml ==> YamlMapping(
+ "a1" -> YamlScalar("42"),
+ "a2" -> YamlSequence(
+ YamlMapping(
+ "a" -> YamlScalar("hello world"),
+ "b" -> YamlScalar("true")
+ ),
+ YamlMapping(
+ "a" -> YamlScalar("yoyo")
+ )
+ )
+ )
+ }
+ "parse with json readers" - {
+ str.parseYaml.convertTo[A] ==> A(
+ 42,
+ Seq(
+ B("hello world", Some(true)),
+ B("yoyo", None),
+ )
+ )
+ }
+ }
+ }
+
+}
diff --git a/yamlesque/src/main/scala/printers.scala b/yamlesque/src/main/scala/YamlPrinter.scala
index 0a1c008..0a1c008 100644
--- a/yamlesque/src/main/scala/printers.scala
+++ b/yamlesque/src/main/scala/YamlPrinter.scala
diff --git a/yamlesque/src/main/scala/formats.scala b/yamlesque/src/main/scala/formats.scala
new file mode 100644
index 0000000..0dbbacc
--- /dev/null
+++ b/yamlesque/src/main/scala/formats.scala
@@ -0,0 +1,8 @@
+package yamlesque
+
+trait YamlReader[A] {
+ def read(yaml: YamlValue): A
+}
+trait YamlWriter[A] {
+ def write(a: A): YamlValue
+}
diff --git a/yamlesque/src/main/scala/package.scala b/yamlesque/src/main/scala/package.scala
index fdb05d0..c40ca70 100644
--- a/yamlesque/src/main/scala/package.scala
+++ b/yamlesque/src/main/scala/package.scala
@@ -1,7 +1,26 @@
package yamlesque
object `package` {
+
+ def deserializationError(msg: String,
+ cause: Throwable = null,
+ fieldNames: List[String] = Nil) =
+ throw new DeserializationException(msg, cause, fieldNames)
+ def serializationError(msg: String) = throw new SerializationException(msg)
+
+ implicit class RichAny[A](val any: A) extends AnyVal {
+ def toYaml(implicit writer: YamlWriter[A]): YamlValue = writer.write(any)
+ }
+
implicit class RichString(val str: String) extends AnyVal {
def parseYaml: YamlValue = YamlParser(str.toIterator)
}
+
}
+
+case class DeserializationException(msg: String,
+ cause: Throwable = null,
+ fieldNames: List[String] = Nil)
+ extends RuntimeException(msg, cause)
+
+class SerializationException(msg: String) extends RuntimeException(msg)
diff --git a/yamlesque/src/main/scala/yamlValues.scala b/yamlesque/src/main/scala/yamlValues.scala
index afe8e0b..958fccc 100644
--- a/yamlesque/src/main/scala/yamlValues.scala
+++ b/yamlesque/src/main/scala/yamlValues.scala
@@ -2,6 +2,7 @@ package yamlesque
sealed trait YamlValue {
def print: String = YamlValue.DefaultPrinter(this)
+ def convertTo[A: YamlReader]: A = implicitly[YamlReader[A]].read(this)
}
object YamlValue {
val DefaultPrinter = new YamlPrinter(compact = true)