Skip to content
This repository

Adds lift-json-scalaz7 (Scalaz 7 support). #1424

Merged
merged 5 commits into from about 1 year ago

2 participants

Taylor Leese David Pollak
Taylor Leese

Adds lift-json-scalaz7 (Scalaz 7 support).

  • Adds a new submodule for lift-json-scalaz7.
  • Maintains lift-json-scalaz for Scalaz 6 support.
  • Updated json-scalaz directory structure from lifweb to liftweb.
  • Updated README to correspond to Scalaz 7.

Discussion on Lift mailing list.

Taylor Leese Move lift-json-scalaz to Scalaz 7
* All tests pass, but only compiling for Scala 2.10.0 at the moment.
* May need a lift-json-scalaz7 subproject to provide both Scalaz 6 and Scalaz 7 support.
765ae74
Taylor Leese

Punting on cross compiling for now. I think it's a larger discussion.

Reverted this and fixed via 15461ae.

Taylor Leese

Punting on cross compiling for now. Perhaps there needs to be a lift-json-scalaz7 subproject as well that is only compiled/published for Scala 2.10.x. I believe that's a larger discussion as well.

Reverted this and fixed via 15461ae.

added some commits March 21, 2013
Taylor Leese Adds lift-json-scalaz7 (Scalaz 7 support).
* Adds a new submodule for lift-json-scalaz7.
* Maintains lift-json-scalaz for Scalaz 6 support.
* Updated README to correspond to Scalaz 7.
15461ae
Taylor Leese Revert "Move lift-json-scalaz to Scalaz 7"
This reverts commit 765ae74.
afd3b5f
Taylor Leese Merge branch 'scalaz-seven' dfa59f6
Taylor Leese Update contributors afc8ba6
Taylor Leese taylorleese commented on the diff March 21, 2013
core/json-scalaz7/README.md
((45 lines not shown))
  45
+    (JValue => Result[String], JValue => Result[String]) => (JValue => Result[Address])
  46
+
  47
+Example which adds a new type class instance
  48
+--------------------------------------------
  49
+
  50
+    scala> implicit def addrJSONR: JSONR[Address] = Address.applyJSON(field[String]("street"), field[String]("zip"))
  51
+
  52
+    scala> val p = JsonParser.parse(""" {"name":"joe","age":34,"address":{"street": "Manhattan 2", "zip": "00223" }} """)
  53
+    scala> Person.applyJSON(field[String]("name"), field[Int]("age"), field[Address]("address"))(p)
  54
+    res0: Success(Person(joe,34,Address(Manhattan 2,00223)))
  55
+
  56
+Validation
  57
+----------
  58
+
  59
+Applicative style parsing works nicely with validation and data conversion. It is easy to compose 
  60
+validations using a for comprehension.
1

Note, I removed the Kleisli composition example because Validation is not a monad in Scalaz 7 (see the Scalaz 7 thread). Using a for comprehension provides the same functionality albeit with a little more typing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Taylor Leese taylorleese commented on the diff March 21, 2013
@@ -6,7 +6,7 @@ if test -f ~/.liftsh.config; then
6 6
 fi
7 7
 
8 8
 # Internal options, always specified
9  
-INTERNAL_OPTS="-Dfile.encoding=UTF-8 -Xmx768m -noverify -XX:ReservedCodeCacheSize=96m -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:MaxPermSize=512m"
  9
+INTERNAL_OPTS="-Dfile.encoding=UTF-8 -Xmx2048m -noverify -XX:ReservedCodeCacheSize=96m -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:MaxPermSize=2048m"
1

This may be overly cautious, but it's the only way it could get it to compile and actually run tests across all versions on my machine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
David Pollak dpp merged commit b1812ab into from March 22, 2013
David Pollak dpp closed this March 22, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 5 unique commits by 1 author.

Mar 20, 2013
Taylor Leese Move lift-json-scalaz to Scalaz 7
* All tests pass, but only compiling for Scala 2.10.0 at the moment.
* May need a lift-json-scalaz7 subproject to provide both Scalaz 6 and Scalaz 7 support.
765ae74
Mar 21, 2013
Taylor Leese Adds lift-json-scalaz7 (Scalaz 7 support).
* Adds a new submodule for lift-json-scalaz7.
* Maintains lift-json-scalaz for Scalaz 6 support.
* Updated README to correspond to Scalaz 7.
15461ae
Taylor Leese Revert "Move lift-json-scalaz to Scalaz 7"
This reverts commit 765ae74.
afd3b5f
Taylor Leese Merge branch 'scalaz-seven' dfa59f6
Taylor Leese Update contributors afc8ba6
This page is out of date. Refresh to see the latest.
7  contributors.md
Source Rendered
@@ -67,7 +67,6 @@ Francis Rhys-Jones
67 67
 francis.rhys-jones at guardian dot co dot uk
68 68
 
69 69
 ### Name: ###
70  
-<<<<<<< HEAD
71 70
 Gregory Flanagan
72 71
 
73 72
 ### Email: ###
@@ -132,3 +131,9 @@ Olivier Bruchez
132 131
 
133 132
 ### Email: ###
134 133
 olivier at bruchez dot org
  134
+
  135
+### Name: ###
  136
+Taylor Leese
  137
+
  138
+### Email: ###
  139
+tleese22 at gmail dot com
2  core/json-scalaz/README.md
Source Rendered
@@ -79,6 +79,6 @@ Add dependency to your SBT project description:
79 79
 Links
80 80
 -----
81 81
 
82  
-* [More examples](https://github.com/lift/framework/tree/master/core/json-scalaz/src/test/scala/net/lifweb/json/scalaz)
  82
+* [More examples](https://github.com/lift/framework/tree/master/core/json-scalaz/src/test/scala/net/liftweb/json/scalaz)
83 83
 * [Scalaz](http://code.google.com/p/scalaz/)
84 84
 * [Kleisli composition](http://www.haskell.org/hoogle/?hoogle=%28a+-%3E+m+b%29+-%3E+%28b+-%3E+m+c%29+-%3E+%28a+-%3E+m+c%29)
0  .../src/main/scala/net/lifweb/json/scalaz/Base.scala → ...src/main/scala/net/liftweb/json/scalaz/Base.scala
File renamed without changes
0  ...ain/scala/net/lifweb/json/scalaz/JsonScalaz.scala → ...in/scala/net/liftweb/json/scalaz/JsonScalaz.scala
File renamed without changes
0  ...c/main/scala/net/lifweb/json/scalaz/Lifting.scala → .../main/scala/net/liftweb/json/scalaz/Lifting.scala
File renamed without changes
0  ...rc/main/scala/net/lifweb/json/scalaz/Tuples.scala → ...c/main/scala/net/liftweb/json/scalaz/Tuples.scala
File renamed without changes
88  core/json-scalaz7/README.md
Source Rendered
... ...
@@ -0,0 +1,88 @@
  1
+Scalaz support for Lift JSON
  2
+============================
  3
+
  4
+This project adds a type class to parse JSON:
  5
+
  6
+    trait JSON[A] {
  7
+      def read(json: JValue): Result[A]
  8
+      def write(value: A): JValue
  9
+    }
  10
+
  11
+    type Result[+A] = ValidationNel[Error, A]
  12
+
  13
+Function 'read' returns an Applicative Functor, enabling parsing in an applicative style.
  14
+
  15
+Simple example
  16
+--------------
  17
+
  18
+    scala> import scalaz._
  19
+    scala> import Scalaz._
  20
+    scala> import net.liftweb.json.scalaz.JsonScalaz._
  21
+    scala> import net.liftweb.json._
  22
+
  23
+    scala> case class Address(street: String, zipCode: String)
  24
+    scala> case class Person(name: String, age: Int, address: Address)
  25
+  
  26
+    scala> val json = parse(""" {"street": "Manhattan 2", "zip": "00223" } """)
  27
+    scala> (field[String]("street")(json) |@| field[String]("zip")(json)) { Address }
  28
+    res0: Success(Address(Manhattan 2,00223))
  29
+
  30
+    scala> (field[String]("streets")(json) |@| field[String]("zip")(json)) { Address }
  31
+    res1: Failure("no such field 'streets'")
  32
+
  33
+Notice the required explicit types when reading fields from JSON. The library comes with helpers which
  34
+can lift functions with pure values into "parsing context". This works well with Scala's type inferencer:
  35
+
  36
+    scala> Address.applyJSON(field[String]("street"), field[String]("zip"))(json)
  37
+    res2: Success(Address(Manhattan 2,00223))
  38
+
  39
+Function 'applyJSON' above lifts function 
  40
+
  41
+    (String, String) => Address 
  42
+
  43
+to
  44
+
  45
+    (JValue => Result[String], JValue => Result[String]) => (JValue => Result[Address])
  46
+
  47
+Example which adds a new type class instance
  48
+--------------------------------------------
  49
+
  50
+    scala> implicit def addrJSONR: JSONR[Address] = Address.applyJSON(field[String]("street"), field[String]("zip"))
  51
+
  52
+    scala> val p = JsonParser.parse(""" {"name":"joe","age":34,"address":{"street": "Manhattan 2", "zip": "00223" }} """)
  53
+    scala> Person.applyJSON(field[String]("name"), field[Int]("age"), field[Address]("address"))(p)
  54
+    res0: Success(Person(joe,34,Address(Manhattan 2,00223)))
  55
+
  56
+Validation
  57
+----------
  58
+
  59
+Applicative style parsing works nicely with validation and data conversion. It is easy to compose 
  60
+validations using a for comprehension.
  61
+
  62
+    def min(x: Int): Int => Result[Int] = (y: Int) => 
  63
+      if (y < x) Fail("min", y + " < " + x) else y.success
  64
+
  65
+    def max(x: Int): Int => Result[Int] = (y: Int) => 
  66
+      if (y > x) Fail("max", y + " > " + x) else y.success
  67
+
  68
+    val ageResult = (jValue: JValue) => for {
  69
+      age <- field[Int]("age")(jValue)
  70
+      _ <- min(16)(age)
  71
+      _ <- max(60)(age)
  72
+    } yield age
  73
+
  74
+    // Creates a function JValue => Result[Person]
  75
+    Person.applyJSON(field[String]("name"), ageResult, field[Address]("address"))
  76
+
  77
+Installation
  78
+------------
  79
+
  80
+Add dependency to your SBT project description:
  81
+
  82
+    val lift_json_scalaz = "net.liftweb" %% "lift-json-scalaz" % "XXX"
  83
+
  84
+Links
  85
+-----
  86
+
  87
+* [More examples](https://github.com/lift/framework/tree/master/core/json-scalaz7/src/test/scala/net/liftweb/json/scalaz)
  88
+* [Scalaz](http://code.google.com/p/scalaz/)
120  core/json-scalaz7/src/main/scala/net/liftweb/json/scalaz/Base.scala
... ...
@@ -0,0 +1,120 @@
  1
+/*
  2
+ * Copyright 2009-2010 WorldWide Conferencing, LLC
  3
+ *
  4
+ * Licensed under the Apache License, Version 2.0 (the "License");
  5
+ * you may not use this file except in compliance with the License.
  6
+ * You may obtain a copy of the License at
  7
+ *
  8
+ *     http://www.apache.org/licenses/LICENSE-2.0
  9
+ *
  10
+ * Unless required by applicable law or agreed to in writing, software
  11
+ * distributed under the License is distributed on an "AS IS" BASIS,
  12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13
+ * See the License for the specific language governing permissions and
  14
+ * limitations under the License.
  15
+ */
  16
+
  17
+package net.liftweb.json.scalaz
  18
+
  19
+import scalaz.ValidationNel
  20
+import scalaz.Validation._
  21
+import scalaz.std.option._
  22
+import scalaz.std.list._
  23
+import scalaz.syntax.traverse._
  24
+import net.liftweb.json._
  25
+import scala.collection.breakOut
  26
+
  27
+trait Base { this: Types =>
  28
+  implicit def boolJSON: JSON[Boolean] = new JSON[Boolean] {
  29
+    def read(json: JValue) = json match {
  30
+      case JBool(b) => success(b)
  31
+      case x => failure(UnexpectedJSONError(x, classOf[JBool])).toValidationNel
  32
+    }
  33
+
  34
+    def write(value: Boolean) = JBool(value)
  35
+  }
  36
+
  37
+  implicit def intJSON: JSON[Int] = new JSON[Int] {
  38
+    def read(json: JValue) = json match {
  39
+      case JInt(x) => success(x.intValue)
  40
+      case x => failure(UnexpectedJSONError(x, classOf[JInt])).toValidationNel
  41
+    }
  42
+
  43
+    def write(value: Int) = JInt(BigInt(value))
  44
+  }
  45
+
  46
+  implicit def longJSON: JSON[Long] = new JSON[Long] {
  47
+    def read(json: JValue) = json match {
  48
+      case JInt(x) => success(x.longValue)
  49
+      case x => failure(UnexpectedJSONError(x, classOf[JInt])).toValidationNel
  50
+    }
  51
+
  52
+    def write(value: Long) = JInt(BigInt(value))
  53
+  }
  54
+
  55
+  implicit def doubleJSON: JSON[Double] = new JSON[Double] {
  56
+    def read(json: JValue) = json match {
  57
+      case JDouble(x) => success(x)
  58
+      case x => failure(UnexpectedJSONError(x, classOf[JDouble])).toValidationNel
  59
+    }
  60
+
  61
+    def write(value: Double) = JDouble(value)
  62
+  }
  63
+
  64
+  implicit def stringJSON: JSON[String] = new JSON[String] {
  65
+    def read(json: JValue) = json match {
  66
+      case JString(x) => success(x)
  67
+      case x => failure(UnexpectedJSONError(x, classOf[JString])).toValidationNel
  68
+    }
  69
+
  70
+    def write(value: String) = JString(value)
  71
+  }
  72
+
  73
+  implicit def bigintJSON: JSON[BigInt] = new JSON[BigInt] {
  74
+    def read(json: JValue) = json match {
  75
+      case JInt(x) => success(x)
  76
+      case x => failure(UnexpectedJSONError(x, classOf[JInt])).toValidationNel
  77
+    }
  78
+
  79
+    def write(value: BigInt) = JInt(value)
  80
+  }
  81
+
  82
+  implicit def jvalueJSON: JSON[JValue] = new JSON[JValue] {
  83
+    def read(json: JValue) = success(json)
  84
+    def write(value: JValue) = value
  85
+  }
  86
+
  87
+  implicit def listJSONR[A: JSONR]: JSONR[List[A]] = new JSONR[List[A]] {
  88
+    def read(json: JValue) = json match {
  89
+      case JArray(xs) => {
  90
+        xs.map(fromJSON[A]).sequence[({type λ[α]=ValidationNel[Error, α]})#λ, A]
  91
+      }
  92
+      case x => failure(UnexpectedJSONError(x, classOf[JArray])).toValidationNel
  93
+    }
  94
+  }
  95
+  implicit def listJSONW[A: JSONW]: JSONW[List[A]] = new JSONW[List[A]] {
  96
+    def write(values: List[A]) = JArray(values.map(x => toJSON(x)))
  97
+  }
  98
+
  99
+  implicit def optionJSONR[A: JSONR]: JSONR[Option[A]] = new JSONR[Option[A]] {
  100
+    def read(json: JValue) = json match {
  101
+      case JNothing | JNull => success(None)
  102
+      case x => fromJSON[A](x).map(some)
  103
+    }
  104
+  }
  105
+  implicit def optionJSONW[A: JSONW]: JSONW[Option[A]] = new JSONW[Option[A]] {
  106
+    def write(value: Option[A]) = value.map(x => toJSON(x)).getOrElse(JNull)
  107
+  }
  108
+
  109
+  implicit def mapJSONR[A: JSONR]: JSONR[Map[String, A]] = new JSONR[Map[String, A]] {
  110
+    def read(json: JValue) = json match {
  111
+      case JObject(fs) => 
  112
+        val r = fs.map(f => fromJSON[A](f.value).map(v => (f.name, v))).sequence[({type λ[α]=ValidationNel[Error, α]})#λ, (String, A)]
  113
+        r.map(_.toMap)
  114
+      case x => failure(UnexpectedJSONError(x, classOf[JObject])).toValidationNel
  115
+    }
  116
+  }
  117
+  implicit def mapJSONW[A: JSONW]: JSONW[Map[String, A]] = new JSONW[Map[String, A]] {
  118
+    def write(values: Map[String, A]) = JObject(values.map { case (k, v) => JField(k, toJSON(v)) }(breakOut))
  119
+  }
  120
+}
80  core/json-scalaz7/src/main/scala/net/liftweb/json/scalaz/JsonScalaz.scala
... ...
@@ -0,0 +1,80 @@
  1
+/*
  2
+ * Copyright 2009-2010 WorldWide Conferencing, LLC
  3
+ *
  4
+ * Licensed under the Apache License, Version 2.0 (the "License");
  5
+ * you may not use this file except in compliance with the License.
  6
+ * You may obtain a copy of the License at
  7
+ *
  8
+ *     http://www.apache.org/licenses/LICENSE-2.0
  9
+ *
  10
+ * Unless required by applicable law or agreed to in writing, software
  11
+ * distributed under the License is distributed on an "AS IS" BASIS,
  12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13
+ * See the License for the specific language governing permissions and
  14
+ * limitations under the License.
  15
+ */
  16
+
  17
+package net.liftweb.json.scalaz
  18
+
  19
+import scalaz.{Equal, Kleisli, Monoid, Semigroup, Show, ValidationNel}
  20
+import scalaz.Validation._
  21
+import scalaz.std.option._
  22
+import net.liftweb.json._
  23
+
  24
+trait Types {
  25
+  type Result[+A] = ValidationNel[Error, A]
  26
+
  27
+  sealed trait Error
  28
+  case class UnexpectedJSONError(was: JValue, expected: Class[_ <: JValue]) extends Error
  29
+  case class NoSuchFieldError(name: String, json: JValue) extends Error
  30
+  case class UncategorizedError(key: String, desc: String, args: List[Any]) extends Error
  31
+
  32
+  case object Fail {
  33
+    def apply[A](key: String, desc: String, args: List[Any]): Result[A] = 
  34
+      failure(UncategorizedError(key, desc, args)).toValidationNel
  35
+
  36
+    def apply[A](key: String, desc: String): Result[A] = 
  37
+      failure(UncategorizedError(key, desc, Nil)).toValidationNel
  38
+  }
  39
+
  40
+  implicit def JValueShow[A <: JValue]: Show[A] = new Show[A] {
  41
+    override def shows(json: A): String = compact(render(json))
  42
+  }
  43
+
  44
+  implicit def JValueMonoid: Monoid[JValue] = Monoid.instance(_ ++ _, JNothing)
  45
+  implicit def JValueSemigroup: Semigroup[JValue] = Semigroup.instance(_ ++ _)
  46
+  implicit def JValueEqual: Equal[JValue] = Equal.equalA
  47
+
  48
+  trait JSONR[A] {
  49
+    def read(json: JValue): Result[A]
  50
+  }
  51
+
  52
+  trait JSONW[A] {
  53
+    def write(value: A): JValue
  54
+  }
  55
+
  56
+  trait JSON[A] extends JSONR[A] with JSONW[A]
  57
+
  58
+  implicit def Result2JSONR[A](f: JValue => Result[A]): JSONR[A] = new JSONR[A] {
  59
+    def read(json: JValue) = f(json)
  60
+  }
  61
+
  62
+  def fromJSON[A: JSONR](json: JValue): Result[A] = implicitly[JSONR[A]].read(json)
  63
+  def toJSON[A: JSONW](value: A): JValue = implicitly[JSONW[A]].write(value)
  64
+
  65
+  def field[A: JSONR](name: String)(json: JValue): Result[A] = json match {
  66
+    case JObject(fs) => 
  67
+      fs.find(_.name == name)
  68
+        .map(f => implicitly[JSONR[A]].read(f.value))
  69
+        .orElse(implicitly[JSONR[A]].read(JNothing).fold(_ => none, x => some(success(x))))
  70
+        .getOrElse(failure(NoSuchFieldError(name, json)).toValidationNel)
  71
+    case x => failure(UnexpectedJSONError(x, classOf[JObject])).toValidationNel
  72
+  }
  73
+
  74
+  def validate[A: JSONR](name: String): Kleisli[Result, JValue, A] = Kleisli(field[A](name))
  75
+
  76
+  def makeObj(fields: Traversable[(String, JValue)]): JObject = 
  77
+    JObject(fields.toList.map { case (n, v) => JField(n, v) })
  78
+}
  79
+
  80
+object JsonScalaz extends Types with Lifting with Base with Tuples
57  core/json-scalaz7/src/main/scala/net/liftweb/json/scalaz/Lifting.scala
... ...
@@ -0,0 +1,57 @@
  1
+/*
  2
+ * Copyright 2009-2010 WorldWide Conferencing, LLC
  3
+ *
  4
+ * Licensed under the Apache License, Version 2.0 (the "License");
  5
+ * you may not use this file except in compliance with the License.
  6
+ * You may obtain a copy of the License at
  7
+ *
  8
+ *     http://www.apache.org/licenses/LICENSE-2.0
  9
+ *
  10
+ * Unless required by applicable law or agreed to in writing, software
  11
+ * distributed under the License is distributed on an "AS IS" BASIS,
  12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13
+ * See the License for the specific language governing permissions and
  14
+ * limitations under the License.
  15
+ */
  16
+
  17
+package net.liftweb.json.scalaz
  18
+
  19
+import scalaz.syntax.apply._
  20
+import net.liftweb.json._
  21
+
  22
+trait Lifting { this: Types =>
  23
+  implicit def Func2ToJSON[A: JSONR, B: JSONR, R](z: (A, B) => R) = new {
  24
+    def applyJSON(a: JValue => Result[A], b: JValue => Result[B]): JValue => Result[R] = 
  25
+        (json: JValue) => (a(json) |@| b(json))(z)
  26
+  }
  27
+
  28
+  implicit def Func3ToJSON[A: JSONR, B: JSONR, C: JSONR, R](z: (A, B, C) => R) = new {
  29
+    def applyJSON(a: JValue => Result[A], b: JValue => Result[B], c: JValue => Result[C]): JValue => Result[R] = 
  30
+      (json: JValue) => (a(json) |@| b(json) |@| c(json))(z)
  31
+  }
  32
+
  33
+  implicit def Func4ToJSON[A: JSONR, B: JSONR, C: JSONR, D: JSONR, R](z: (A, B, C, D) => R) = new {
  34
+    def applyJSON(a: JValue => Result[A], b: JValue => Result[B], c: JValue => Result[C], d: JValue => Result[D]): JValue => Result[R] = 
  35
+      (json: JValue) => (a(json) |@| b(json) |@| c(json) |@| d(json))(z)
  36
+  }
  37
+
  38
+  implicit def Func5ToJSON[A: JSONR, B: JSONR, C: JSONR, D: JSONR, E: JSONR, R](z: (A, B, C, D, E) => R) = new {
  39
+    def applyJSON(a: JValue => Result[A], b: JValue => Result[B], c: JValue => Result[C], d: JValue => Result[D], e: JValue => Result[E]): JValue => Result[R] = 
  40
+      (json: JValue) => (a(json) |@| b(json) |@| c(json) |@| d(json) |@| e(json))(z)
  41
+  }
  42
+
  43
+  implicit def Func6ToJSON[A: JSONR, B: JSONR, C: JSONR, D: JSONR, E: JSONR, F: JSONR, R](z: (A, B, C, D, E, F) => R) = new {
  44
+    def applyJSON(a: JValue => Result[A], b: JValue => Result[B], c: JValue => Result[C], d: JValue => Result[D], e: JValue => Result[E], f: JValue => Result[F]): JValue => Result[R] = 
  45
+      (json: JValue) => (a(json) |@| b(json) |@| c(json) |@| d(json) |@| e(json) |@| f(json))(z)
  46
+  }
  47
+
  48
+  implicit def Func7ToJSON[A: JSONR, B: JSONR, C: JSONR, D: JSONR, E: JSONR, F: JSONR, G: JSONR, R](z: (A, B, C, D, E, F, G) => R) = new {
  49
+    def applyJSON(a: JValue => Result[A], b: JValue => Result[B], c: JValue => Result[C], d: JValue => Result[D], e: JValue => Result[E], f: JValue => Result[F], g: JValue => Result[G]): JValue => Result[R] = 
  50
+      (json: JValue) => (a(json) |@| b(json) |@| c(json) |@| d(json) |@| e(json) |@| f(json) |@| g(json))(z)
  51
+  }
  52
+
  53
+  implicit def Func8ToJSON[A: JSONR, B: JSONR, C: JSONR, D: JSONR, E: JSONR, F: JSONR, G: JSONR, H: JSONR, R](z: (A, B, C, D, E, F, G, H) => R) = new {
  54
+    def applyJSON(a: JValue => Result[A], b: JValue => Result[B], c: JValue => Result[C], d: JValue => Result[D], e: JValue => Result[E], f: JValue => Result[F], g: JValue => Result[G], h: JValue => Result[H]): JValue => Result[R] = 
  55
+      (json: JValue) => (a(json) |@| b(json) |@| c(json) |@| d(json) |@| e(json) |@| f(json) |@| g(json) |@| h(json))(z)
  56
+  }
  57
+}
73  core/json-scalaz7/src/main/scala/net/liftweb/json/scalaz/Tuples.scala
... ...
@@ -0,0 +1,73 @@
  1
+/*
  2
+ * Copyright 2009-2010 WorldWide Conferencing, LLC
  3
+ *
  4
+ * Licensed under the Apache License, Version 2.0 (the "License");
  5
+ * you may not use this file except in compliance with the License.
  6
+ * You may obtain a copy of the License at
  7
+ *
  8
+ *     http://www.apache.org/licenses/LICENSE-2.0
  9
+ *
  10
+ * Unless required by applicable law or agreed to in writing, software
  11
+ * distributed under the License is distributed on an "AS IS" BASIS,
  12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13
+ * See the License for the specific language governing permissions and
  14
+ * limitations under the License.
  15
+ */
  16
+
  17
+package net.liftweb.json.scalaz
  18
+
  19
+import scalaz.Validation._
  20
+import scalaz.syntax.apply._
  21
+import net.liftweb.json._
  22
+
  23
+trait Tuples { this: Types =>
  24
+  implicit def Tuple2JSON[A: JSON, B: JSON]: JSON[(A, B)] = new JSON[(A, B)] {
  25
+    def read(json: JValue) = json match {
  26
+      case JArray(a :: b :: _) => 
  27
+        (fromJSON[A](a) |@| fromJSON[B](b)) { (a, b) => (a, b)  }
  28
+      case x => failure(UnexpectedJSONError(x, classOf[JArray])).toValidationNel
  29
+    }
  30
+
  31
+    def write(value: (A, B)) = JArray(toJSON(value._1) :: toJSON(value._2) :: Nil)
  32
+  }
  33
+
  34
+  implicit def Tuple3JSON[A: JSON, B: JSON, C: JSON]: JSON[(A, B, C)] = new JSON[(A, B, C)] {
  35
+    def read(json: JValue) = json match {
  36
+      case JArray(a :: b :: c :: _) => 
  37
+        (fromJSON[A](a) |@| fromJSON[B](b) |@| fromJSON[C](c)) { (a, b, c) => (a, b, c)  }
  38
+      case x => failure(UnexpectedJSONError(x, classOf[JArray])).toValidationNel
  39
+    }
  40
+
  41
+    def write(value: (A, B, C)) = JArray(toJSON(value._1) :: toJSON(value._2) :: toJSON(value._3) :: Nil)
  42
+  }
  43
+
  44
+  implicit def Tuple4JSON[A: JSON, B: JSON, C: JSON, D: JSON]: JSON[(A, B, C, D)] = new JSON[(A, B, C, D)] {
  45
+    def read(json: JValue) = json match {
  46
+      case JArray(a :: b :: c :: d :: _) => 
  47
+        (fromJSON[A](a) |@| fromJSON[B](b) |@| fromJSON[C](c) |@| fromJSON[D](d)) { (a, b, c, d) => (a, b, c, d)  }
  48
+      case x => failure(UnexpectedJSONError(x, classOf[JArray])).toValidationNel
  49
+    }
  50
+
  51
+    def write(value: (A, B, C, D)) = JArray(toJSON(value._1) :: toJSON(value._2) :: toJSON(value._3) :: toJSON(value._4) :: Nil)
  52
+  }
  53
+
  54
+  implicit def Tuple5JSON[A: JSON, B: JSON, C: JSON, D: JSON, E: JSON]: JSON[(A, B, C, D, E)] = new JSON[(A, B, C, D, E)] {
  55
+    def read(json: JValue) = json match {
  56
+      case JArray(a :: b :: c :: d :: e :: _) => 
  57
+        (fromJSON[A](a) |@| fromJSON[B](b) |@| fromJSON[C](c) |@| fromJSON[D](d) |@| fromJSON[E](e)) { (a, b, c, d, e) => (a, b, c, d, e)  }
  58
+      case x => failure(UnexpectedJSONError(x, classOf[JArray])).toValidationNel
  59
+    }
  60
+
  61
+    def write(value: (A, B, C, D, E)) = JArray(toJSON(value._1) :: toJSON(value._2) :: toJSON(value._3) :: toJSON(value._4) :: toJSON(value._5) :: Nil)
  62
+  }
  63
+
  64
+  implicit def Tuple6JSON[A: JSON, B: JSON, C: JSON, D: JSON, E: JSON, F: JSON]: JSON[(A, B, C, D, E, F)] = new JSON[(A, B, C, D, E, F)] {
  65
+    def read(json: JValue) = json match {
  66
+      case JArray(a :: b :: c :: d :: e :: f :: _) => 
  67
+        (fromJSON[A](a) |@| fromJSON[B](b) |@| fromJSON[C](c) |@| fromJSON[D](d) |@| fromJSON[E](e) |@| fromJSON[F](f)) { (a, b, c, d, e, f) => (a, b, c, d, e, f)  }
  68
+      case x => failure(UnexpectedJSONError(x, classOf[JArray])).toValidationNel
  69
+    }
  70
+
  71
+    def write(value: (A, B, C, D, E, F)) = JArray(toJSON(value._1) :: toJSON(value._2) :: toJSON(value._3) :: toJSON(value._4) :: toJSON(value._5) :: toJSON(value._6) :: Nil)
  72
+  }
  73
+}
66  core/json-scalaz7/src/test/scala/net/liftweb/json/scalaz/Example.scala
... ...
@@ -0,0 +1,66 @@
  1
+package net.liftweb.json.scalaz
  2
+
  3
+import scalaz._
  4
+import scalaz.syntax.applicative._
  5
+import scalaz.syntax.show._
  6
+import JsonScalaz._
  7
+import net.liftweb.json._
  8
+
  9
+import org.specs2.mutable.Specification
  10
+
  11
+object Example extends Specification {
  12
+
  13
+  case class Address(street: String, zipCode: String)
  14
+  case class Person(name: String, age: Int, address: Address)
  15
+  
  16
+  "Parse address in an Applicative style" in {
  17
+    val json = parse(""" {"street": "Manhattan 2", "zip": "00223" } """)
  18
+    val a1 = field[String]("zip")(json) <*> (field[String]("street")(json) map Address.curried)
  19
+    val a2 = (field[String]("street")(json) |@| field[String]("zip")(json)) { Address }
  20
+    val a3 = Address.applyJSON(field[String]("street"), field[String]("zip"))(json)
  21
+    a1 mustEqual Success(Address("Manhattan 2", "00223"))
  22
+    a2 mustEqual a1
  23
+    a3 mustEqual a1
  24
+  }
  25
+
  26
+  "Failed address parsing" in {
  27
+    val json = parse(""" {"street": "Manhattan 2", "zip": "00223" } """)
  28
+    val a = (field[String]("streets")(json) |@| field[String]("zip")(json)) { Address }
  29
+    a mustEqual Failure(NonEmptyList(NoSuchFieldError("streets", json)))
  30
+  }
  31
+
  32
+  "Parse Person with Address" in {
  33
+    implicit def addrJSON: JSONR[Address] = new JSONR[Address] {
  34
+      def read(json: JValue) = Address.applyJSON(field[String]("street"), field[String]("zip"))(json)
  35
+    }
  36
+
  37
+    val p = parse(""" {"name":"joe","age":34,"address":{"street": "Manhattan 2", "zip": "00223" }} """)
  38
+    val person = Person.applyJSON(field[String]("name"), field[Int]("age"), field[Address]("address"))(p)
  39
+    person mustEqual Success(Person("joe", 34, Address("Manhattan 2", "00223")))
  40
+  }
  41
+
  42
+  "Format Person with Address" in {
  43
+    implicit def addrJSON: JSONW[Address] = new JSONW[Address] {
  44
+      def write(a: Address) = 
  45
+        makeObj(("street" -> toJSON(a.street)) :: ("zip" -> toJSON(a.zipCode)) :: Nil)
  46
+    }
  47
+
  48
+    val p = Person("joe", 34, Address("Manhattan 2", "00223"))
  49
+    val json = makeObj(("name" -> toJSON(p.name)) :: 
  50
+                       ("age" -> toJSON(p.age)) :: 
  51
+                       ("address" -> toJSON(p.address)) :: Nil)
  52
+    json.shows mustEqual 
  53
+      """{"name":"joe","age":34,"address":{"street":"Manhattan 2","zip":"00223"}}"""
  54
+  }
  55
+
  56
+  "Parse Map" in {
  57
+    val json = parse(""" {"street": "Manhattan 2", "zip": "00223" } """)
  58
+    fromJSON[Map[String, String]](json) mustEqual Success(Map("street" -> "Manhattan 2", "zip" -> "00223"))
  59
+  }
  60
+
  61
+  "Format Map" in {
  62
+    toJSON(Map("street" -> "Manhattan 2", "zip" -> "00223")).shows mustEqual
  63
+      """{"street":"Manhattan 2","zip":"00223"}"""
  64
+  }
  65
+
  66
+}
47  core/json-scalaz7/src/test/scala/net/liftweb/json/scalaz/LottoExample.scala
... ...
@@ -0,0 +1,47 @@
  1
+package net.liftweb.json.scalaz
  2
+
  3
+import scalaz._
  4
+import scalaz.syntax.validation._
  5
+import JsonScalaz._
  6
+import net.liftweb.json._
  7
+
  8
+import org.specs2.mutable.Specification
  9
+
  10
+object LottoExample extends Specification {
  11
+
  12
+  case class Winner(winnerId: Long, numbers: List[Int])
  13
+  case class Lotto(id: Long, winningNumbers: List[Int], winners: List[Winner], drawDate: Option[String])
  14
+
  15
+  val json = parse("""{"id":5,"winning-numbers":[2,45,34,23,7,5],"winners":[{"winner-id":23,"numbers":[2,45,34,23,3,5]},{"winner-id":54,"numbers":[52,3,12,11,18,22]}]}""")
  16
+
  17
+  // Lotto line must have exactly 6 numbers
  18
+  def len(x: Int) = (xs: List[Int]) => 
  19
+    if (xs.length != x) Fail("len", xs.length + " != " + x) else xs.success
  20
+
  21
+  implicit def winnerJSON: JSONR[Winner] = {
  22
+    val numbersResult = (jValue: JValue) => for {
  23
+      numbers <- field[List[Int]]("numbers")(jValue)
  24
+      _ <- len(6)(numbers)
  25
+    } yield numbers
  26
+    Winner.applyJSON(field[Long]("winner-id"), numbersResult)
  27
+  }
  28
+
  29
+  implicit def lottoJSON: JSONR[Lotto] = {
  30
+    val winningNumbersResult = (jValue: JValue) => for {
  31
+      winningNumbers <- field[List[Int]]("winning-numbers")(jValue)
  32
+      _ <- len(6)(winningNumbers)
  33
+    } yield winningNumbers
  34
+    Lotto.applyJSON(field[Long]("id")
  35
+                  , winningNumbersResult
  36
+                  , field[List[Winner]]("winners")
  37
+                  , field[Option[String]]("draw-date"))
  38
+  }
  39
+  
  40
+  val winners = List(Winner(23, List(2, 45, 34, 23, 3, 5)), Winner(54, List(52, 3, 12, 11, 18, 22)))
  41
+  val lotto = Lotto(5, List(2, 45, 34, 23, 7, 5), winners, None)
  42
+
  43
+  "Parse Lotto" in {
  44
+    fromJSON[Lotto](json) mustEqual Success(lotto)
  45
+  }
  46
+
  47
+}
14  core/json-scalaz7/src/test/scala/net/liftweb/json/scalaz/TupleExample.scala
... ...
@@ -0,0 +1,14 @@
  1
+package net.liftweb.json.scalaz
  2
+
  3
+import scalaz._
  4
+import JsonScalaz._
  5
+import net.liftweb.json._
  6
+
  7
+import org.specs2.mutable.Specification
  8
+
  9
+object TupleExample extends Specification {
  10
+  "Parse tuple from List" in {
  11
+    val json = JsonParser.parse(""" [1,2,3] """)
  12
+    fromJSON[Tuple3[Int, Int, Int]](json) mustEqual Success(1, 2, 3)
  13
+  }
  14
+}
82  core/json-scalaz7/src/test/scala/net/liftweb/json/scalaz/ValidationExample.scala
... ...
@@ -0,0 +1,82 @@
  1
+package net.liftweb.json.scalaz
  2
+
  3
+import scalaz._
  4
+import scalaz.std.list._
  5
+import scalaz.syntax.traverse._
  6
+import scalaz.syntax.validation._
  7
+import JsonScalaz._
  8
+import net.liftweb.json._
  9
+
  10
+import org.specs2.mutable.Specification
  11
+
  12
+object ValidationExample extends Specification {
  13
+
  14
+  case class Person(name: String, age: Int)
  15
+
  16
+  "Validation" should {
  17
+    def min(x: Int): Int => Result[Int] = (y: Int) => 
  18
+      if (y < x) Fail("min", y + " < " + x) else y.success
  19
+
  20
+    def max(x: Int): Int => Result[Int] = (y: Int) => 
  21
+      if (y > x) Fail("max", y + " > " + x) else y.success
  22
+
  23
+    val json = JsonParser.parse(""" {"name":"joe","age":17} """)
  24
+
  25
+    "fail when age is less than min age" in {
  26
+      // Age must be between 18 an 60
  27
+      val ageResult = (jValue: JValue) => for {
  28
+        age <- field[Int]("age")(jValue)
  29
+        _ <- min(18)(age)
  30
+        _ <- max(60)(age)
  31
+      } yield age
  32
+      val person = Person.applyJSON(field[String]("name"), ageResult)
  33
+      person(json) mustEqual Failure(NonEmptyList(UncategorizedError("min", "17 < 18", Nil)))
  34
+    }
  35
+
  36
+    "pass when age within limits" in {
  37
+      // Age must be between 16 an 60
  38
+      val ageResult = (jValue: JValue) => for {
  39
+        age <- field[Int]("age")(jValue)
  40
+        _ <- min(16)(age)
  41
+        _ <- max(60)(age)
  42
+      } yield age
  43
+      val person = Person.applyJSON(field[String]("name"), ageResult)
  44
+      person(json) mustEqual Success(Person("joe", 17))
  45
+    }
  46
+  }
  47
+
  48
+  case class Range(start: Int, end: Int)
  49
+
  50
+  // This example shows:
  51
+  // * a validation where result depends on more than one value
  52
+  // * parse a List with invalid values
  53
+
  54
+  "Range filtering" should {
  55
+    val json = JsonParser.parse(""" [{"s":10,"e":17},{"s":12,"e":13},{"s":11,"e":8}] """)
  56
+
  57
+    def ascending: (Int, Int) => Result[(Int, Int)] = (x1: Int, x2: Int) => 
  58
+      if (x1 > x2) Fail("asc", x1 + " > " + x2) else (x1, x2).success
  59
+
  60
+    // Valid range is a range having start <= end
  61
+    implicit def rangeJSON: JSONR[Range] = new JSONR[Range] {
  62
+      def read(json: JValue) = {
  63
+        for {
  64
+          s <- field[Int]("s")(json)
  65
+          e <- field[Int]("e")(json)
  66
+          r <- ascending(s, e)
  67
+        } yield Range.tupled(r)
  68
+      }
  69
+    }
  70
+
  71
+    "fail if lists contains invalid ranges" in {
  72
+      val r = fromJSON[List[Range]](json)
  73
+      r mustEqual Failure(NonEmptyList(UncategorizedError("asc", "11 > 8", Nil)))
  74
+    }
  75
+ 
  76
+    "optionally return only valid ranges" in {
  77
+      val ranges = json.children.map(fromJSON[Range]).filter(_.isSuccess).sequence[({type λ[α]=ValidationNel[Error, α]})#λ, Range]
  78
+      ranges mustEqual Success(List(Range(10, 17), Range(12, 13)))
  79
+    }
  80
+  }
  81
+
  82
+}
2  liftsh
@@ -6,7 +6,7 @@ if test -f ~/.liftsh.config; then
6 6
 fi
7 7
 
8 8
 # Internal options, always specified
9  
-INTERNAL_OPTS="-Dfile.encoding=UTF-8 -Xmx768m -noverify -XX:ReservedCodeCacheSize=96m -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:MaxPermSize=512m"
  9
+INTERNAL_OPTS="-Dfile.encoding=UTF-8 -Xmx2048m -noverify -XX:ReservedCodeCacheSize=96m -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:MaxPermSize=2048m"
10 10
 
11 11
 # Add 64bit specific option
12 12
 exec java -version 2>&1 | grep -q "64-Bit" && INTERNAL_OPTS="${INTERNAL_OPTS} -XX:+UseCompressedOops -XX:ReservedCodeCacheSize=128m"
10  project/Build.scala
@@ -34,7 +34,7 @@ object BuildDef extends Build {
34 34
   // Core Projects
35 35
   // -------------
36 36
   lazy val core: Seq[ProjectReference] =
37  
-    Seq(common, actor, json, json_scalaz, json_ext, util)
  37
+    Seq(common, actor, json, json_scalaz, json_scalaz7, json_ext, util)
38 38
 
39 39
   lazy val common =
40 40
     coreProject("common")
@@ -56,9 +56,15 @@ object BuildDef extends Build {
56 56
   lazy val json_scalaz =
57 57
     coreProject("json-scalaz")
58 58
         .dependsOn(json)
59  
-        .settings(description := "JSON Library based on Scalaz",
  59
+        .settings(description := "JSON Library based on Scalaz 6",
60 60
                   libraryDependencies <+= scalaVersion(scalaz))
61 61
 
  62
+  lazy val json_scalaz7 =
  63
+    coreProject("json-scalaz7")
  64
+        .dependsOn(json)
  65
+        .settings(description := "JSON Library based on Scalaz 7",
  66
+                  libraryDependencies <+= scalaVersion(scalaz7))
  67
+
62 68
   lazy val json_ext =
63 69
     coreProject("json-ext")
64 70
         .dependsOn(common, json)
7  project/Dependencies.scala
@@ -31,6 +31,7 @@ object Dependencies {
31 31
 
32 32
   lazy val scalazGroup       = defaultOrMapped("org.scalaz")
33 33
   lazy val scalazVersion     = defaultOrMapped("6.0.4", "2.9.0" -> "6.0.RC2")
  34
+  lazy val scalaz7Version    = defaultOrMapped("7.0.0-M9")
34 35
 
35 36
   // Compile scope:
36 37
   // Scope available in all classpath, transitive by default.
@@ -45,15 +46,17 @@ object Dependencies {
45 46
   lazy val paranamer              = "com.thoughtworks.paranamer" % "paranamer"          % "2.4.1"
46 47
   lazy val scalajpa               = "org.scala-libs"             % "scalajpa"           % "1.4"     cross CVMapping29
47 48
   lazy val scalap: ModuleMap      = "org.scala-lang"             % "scalap"             % _
48  
-  lazy val scala_compiler: ModuleMap  = "org.scala-lang"                % "scala-compiler"     % _
  49
+  lazy val scala_compiler: ModuleMap = "org.scala-lang"          % "scala-compiler"     % _
49 50
   lazy val scalaz_core: ModuleMap = sv => scalazGroup(sv)        % "scalaz-core"        % scalazVersion(sv) cross crossMapped("2.10.0" -> "2.10.0-RC5", "2.9.2" -> "2.9.1", "2.9.1-1" -> "2.9.1")
  51
+  lazy val scalaz7_core: ModuleMap = sv => scalazGroup(sv)       % "scalaz-core"        % scalaz7Version(sv) cross CVMapping29
50 52
   lazy val slf4j_api              = "org.slf4j"                  % "slf4j-api"          % slf4jVersion
51  
-  lazy val squeryl                = "org.squeryl"                % "squeryl"           % "0.9.5-6" cross CVMapping29
  53
+  lazy val squeryl                = "org.squeryl"                % "squeryl"            % "0.9.5-6" cross CVMapping29
52 54
   @deprecated lazy val scalaactors= "org.scala-lang"             % "scala-actors"       % "2.10.0"
53 55
 
54 56
   // Aliases
55 57
   lazy val mongo_driver = mongo_java_driver
56 58
   lazy val scalaz = scalaz_core
  59
+  lazy val scalaz7 = scalaz7_core
57 60
 
58 61
 
59 62
   // Provided scope:
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.