diff options
author | Jakob Odersky <jakob@odersky.com> | 2018-04-08 16:24:00 -0700 |
---|---|---|
committer | Jakob Odersky <jakob@odersky.com> | 2018-04-08 16:24:00 -0700 |
commit | 3fe7b06c5f357f34a5c227bc040effcbb259aef2 (patch) | |
tree | 1f83c575a6f59340403c7cfdd77969d61467f817 | |
parent | f1fe50cba0c07d27f109a727c480b02639d140e0 (diff) | |
download | yamlesque-3fe7b06c5f357f34a5c227bc040effcbb259aef2.tar.gz yamlesque-3fe7b06c5f357f34a5c227bc040effcbb259aef2.tar.bz2 yamlesque-3fe7b06c5f357f34a5c227bc040effcbb259aef2.zip |
Add spray compatibility layer
-rw-r--r-- | build.sbt | 22 | ||||
-rw-r--r-- | yamlesque-spray/src/main/scala/formats.scala | 40 | ||||
-rw-r--r-- | yamlesque-spray/src/test/scala/FormatTests.scala | 53 | ||||
-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.scala | 8 | ||||
-rw-r--r-- | yamlesque/src/main/scala/package.scala | 19 | ||||
-rw-r--r-- | yamlesque/src/main/scala/yamlValues.scala | 1 |
7 files changed, 140 insertions, 3 deletions
@@ -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) |