summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Rudolph <johannes.rudolph@gmail.com>2013-08-20 11:46:46 +0200
committerJohannes Rudolph <johannes.rudolph@gmail.com>2013-08-20 11:46:46 +0200
commit5b2bfa93c7a13d7c55e49ecbaa87bd76a30147d7 (patch)
treefa08de475a9686ff31f935263ab0130d8175c95b
parent636bba4ef16f26967bd14092da2625316981eabd (diff)
downloadspray-json-5b2bfa93c7a13d7c55e49ecbaa87bd76a30147d7.tar.gz
spray-json-5b2bfa93c7a13d7c55e49ecbaa87bd76a30147d7.tar.bz2
spray-json-5b2bfa93c7a13d7c55e49ecbaa87bd76a30147d7.zip
add new lens `arrayOrSingletonAsArray` which reinterprets non json array values as singleton arrays, fixes #8
-rw-r--r--README.md2
-rw-r--r--notes/0.5.4.markdown7
-rw-r--r--src/main/scala/spray/json/lenses/ScalarLenses.scala16
-rw-r--r--src/test/scala/spray/json/lenses/JsonLensesSpec.scala29
-rw-r--r--src/test/scala/spray/json/lenses/JsonPathExamplesSpec.scala21
5 files changed, 74 insertions, 1 deletions
diff --git a/README.md b/README.md
index 26f0cf5..b053a7f 100644
--- a/README.md
+++ b/README.md
@@ -184,6 +184,8 @@ from the following list.
and its field `fullName` is a string starting with `"Joe"`.
* `allMatching(next: Lens)`: A combination of `combine` and `elements`. Selects elements matching the `next` lens
and then applies the `next` lens.
+ * `arrayOrSingletonAsArray`: Makes sure that the result is always a json array by interpreting a value that is no array
+ as an singleton array containing just that value.
##### Combination
diff --git a/notes/0.5.4.markdown b/notes/0.5.4.markdown
new file mode 100644
index 0000000..861208a
--- /dev/null
+++ b/notes/0.5.4.markdown
@@ -0,0 +1,7 @@
+New features in this version:
+
+ - [#8][] added `arrayOrSingletonAsArray` which allows to reinterpret values as singleton arrays
+ - [#11][] fixed a parser bug in JsonPathParser
+
+[#8]: https://github.com/jrudolph/json-lenses/issues/8
+[#11]: https://github.com/jrudolph/json-lenses/issues/11
diff --git a/src/main/scala/spray/json/lenses/ScalarLenses.scala b/src/main/scala/spray/json/lenses/ScalarLenses.scala
index 3a85147..4beee27 100644
--- a/src/main/scala/spray/json/lenses/ScalarLenses.scala
+++ b/src/main/scala/spray/json/lenses/ScalarLenses.scala
@@ -55,6 +55,20 @@ trait ScalarLenses {
def retr: JsValue => SafeJsValue = x => Right(x)
}
+
+ /**
+ * A lens which leaves JsArray as is but transforms any other kind of JsValue into
+ * a singleton JsArray with that value as single element.
+ */
+ val arrayOrSingletonAsArray: ScalarLens = new LensImpl[Id] {
+ def updated(f: SafeJsValue => SafeJsValue)(parent: JsValue): SafeJsValue =
+ retr(parent).flatMap(x => f(Right(x)))
+
+ def retr: JsValue => Validated[JsValue] = {
+ case ar: JsArray => Right(ar)
+ case x => Right(JsArray(x))
+ }
+ }
}
-object ScalarLenses extends ScalarLenses \ No newline at end of file
+object ScalarLenses extends ScalarLenses
diff --git a/src/test/scala/spray/json/lenses/JsonLensesSpec.scala b/src/test/scala/spray/json/lenses/JsonLensesSpec.scala
index 780083c..9418fb1 100644
--- a/src/test/scala/spray/json/lenses/JsonLensesSpec.scala
+++ b/src/test/scala/spray/json/lenses/JsonLensesSpec.scala
@@ -66,6 +66,20 @@ class JsonLensesSpec extends Specification with SpecHelpers {
}
}
}
+ "orSingletonArray" in {
+ "empty JsArray" in {
+ "[]".extract[Seq[Int]](arrayOrSingletonAsArray) === Nil
+ }
+ "filled JsArray" in {
+ "[1,2,3,4,5]".extract[Seq[Int]](arrayOrSingletonAsArray) === Seq(1, 2, 3, 4, 5)
+ }
+ "single int value" in {
+ "5".extract[Seq[Int]](arrayOrSingletonAsArray) === Seq(5)
+ }
+ "single object value" in {
+ """{ "a": 5 }""".extract[Seq[Map[String, Int]]](arrayOrSingletonAsArray) === Seq(Map("a" -> 5))
+ }
+ }
"all elements of an array" in {
"simple" in {
"""[18, 23, 2, 5, 8, 3]""".extract[Int](*) must be_==(Seq(18, 23, 2, 5, 8, 3))
@@ -88,6 +102,7 @@ class JsonLensesSpec extends Specification with SpecHelpers {
"""{"a": 5}""".extract[Int](("a" / *)) must throwAn[Exception]( """Not a json array: 5""")
}
}
+
/*"filtered elements of an array" in {
}*/
@@ -161,6 +176,20 @@ class JsonLensesSpec extends Specification with SpecHelpers {
"set element of array" in {
"""["a", "b", 2, 5, 8, 3]""" update (element(3) ! set(35)) must be_json( """["a", "b", 2, 35, 8, 3]""")
}
+ "orSingletonArray" in {
+ "empty JsArray" in {
+ "[]".update(arrayOrSingletonAsArray ! set(Seq(1, 2, 3, 4, 5))) must be_json("""[1, 2, 3, 4, 5]""")
+ }
+ "filled JsArray" in {
+ "[1,2,3,4,5]".update(arrayOrSingletonAsArray / * ! modify[Int](_ + 1)) must be_json("""[2, 3, 4, 5, 6]""")
+ }
+ "single int value" in {
+ "5".update(arrayOrSingletonAsArray / * ! modify[Int](_ + 1)) must be_json("""[6]""")
+ }
+ "single object value" in {
+ """{ "a": 5 }""".update(arrayOrSingletonAsArray / * / 'a ! modify[Int](_ + 1)) must be_json("""[{ "a" : 6 }]""")
+ }
+ }
"change a found element" in {
"in a homogenuous array" in {
"if found" in {
diff --git a/src/test/scala/spray/json/lenses/JsonPathExamplesSpec.scala b/src/test/scala/spray/json/lenses/JsonPathExamplesSpec.scala
index 707671b..0b43039 100644
--- a/src/test/scala/spray/json/lenses/JsonPathExamplesSpec.scala
+++ b/src/test/scala/spray/json/lenses/JsonPathExamplesSpec.scala
@@ -38,6 +38,24 @@ class JsonPathExamplesSpec extends Specification with SpecHelpers {
|}
""".stripMargin)
+ val singleElemArray = JsonParser(
+ """
+ |{ "store": {
+ | "book":
+ | { "category": "reference",
+ | "author": "Nigel Rees",
+ | "title": "Sayings of the Century",
+ | "price": 8.95
+ | }
+ | ,
+ | "bicycle": {
+ | "color": "red",
+ | "price": 19.95
+ | }
+ | }
+ |}
+ """.stripMargin)
+
"Examples" should {
"with Scala syntax" in {
"All authors" in {
@@ -46,6 +64,9 @@ class JsonPathExamplesSpec extends Specification with SpecHelpers {
"Author of first book" in {
json.extract[String](("store" / "book" / element(0) / "author")) must be_==("Nigel Rees")
}
+ "Author of first book no array" in {
+ singleElemArray.extract[String](("store" / "book" / arrayOrSingletonAsArray / element(0) / "author")) must be_==("Nigel Rees")
+ }
"Books with category 'reference'" in {
json.extract[String](("store" / "book" / filter("category".is[String](_ == "reference")) / "title")) must be_==(Seq("Sayings of the Century"))
}