Skip to content

Commit

Permalink
work
Browse files Browse the repository at this point in the history
  • Loading branch information
Lance Gatlin committed Dec 30, 2016
1 parent 2c9042a commit 09d282b
Show file tree
Hide file tree
Showing 7 changed files with 451 additions and 15 deletions.
63 changes: 55 additions & 8 deletions explain_json/src/main/scala/s_mach/explain_json/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,65 @@
*/
package s_mach.explain_json

import scala.language.higherKinds

object Implicits extends Implicits
trait Implicits {
implicit object JsonStringBuilderFactory extends JsonBuilderFactory[String] {
def apply() = JsonStringBuilder(1024)
}

implicit object buildJson_ListString extends BuildJson[List[String]] {
def build[R](builder: JsonBuilder[R], a: List[String]) = {
import builder._
appendArray {
a.foreach(append)
}
implicit object buildJson_Byte extends BuildJson[Byte] {
def build[JsonRepr](builder: JsonBuilder[JsonRepr], a: Byte) = {
builder.append(a.toInt)
}
}

implicit object buildJson_Short extends BuildJson[Short] {
def build[JsonRepr](builder: JsonBuilder[JsonRepr], a: Short) = {
builder.append(a.toInt)
}
}

implicit object buildJson_Int extends BuildJson[Int] {
def build[JsonRepr](builder: JsonBuilder[JsonRepr], a: Int) = {
builder.append(a)
}
}

implicit object buildJson_Long extends BuildJson[Long] {
def build[JsonRepr](builder: JsonBuilder[JsonRepr], a: Long) = {
builder.append(a)
}
}

implicit object buildJson_Float extends BuildJson[Float] {
def build[JsonRepr](builder: JsonBuilder[JsonRepr], a: Float) = {
builder.append(a.toDouble)
}
}

implicit object buildJson_Double extends BuildJson[Double] {
def build[JsonRepr](builder: JsonBuilder[JsonRepr], a: Double) = {
builder.append(a)
}
}

implicit object buildJson_BigInt extends BuildJson[BigInt] {
def build[JsonRepr](builder: JsonBuilder[JsonRepr], a: BigInt) = {
builder.append(BigDecimal(a))
}
}

implicit object buildJson_BigDecimal extends BuildJson[BigDecimal] {
def build[JsonRepr](builder: JsonBuilder[JsonRepr], a: BigDecimal) = {
builder.append(a)
}
}

implicit object buildJson_String extends BuildJson[String] {
def build[JsonRepr](builder: JsonBuilder[JsonRepr], a: String) = {
builder.append(a)
}
}

Expand All @@ -46,8 +93,8 @@ trait Implicits {
}
}

implicit def buildJson_SeqA[A](implicit buildJson: BuildJson[A]) = new BuildJson[Seq[A]] {
def build[JsonRepr](builder: JsonBuilder[JsonRepr], a: Seq[A]) = {
implicit def buildJson_SeqA[M[AA] <: Seq[AA], A](implicit buildJson: BuildJson[A]) = new BuildJson[M[A]] {
def build[JsonRepr](builder: JsonBuilder[JsonRepr], a: M[A]) = {
import builder._
appendArray {
a.foreach(_.buildJson(builder))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ class JsonStringBuilderImpl(initialBufferSize: Int = 256) extends JsonStringBuil
}

def appendField[A](fieldName: String)(build: => A) = {
val pos = sb.length
sb.append(s""""$fieldName":""")
val pos = sb.length
val retv = build
lastStartPos = pos
retv
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
package s_mach.explain_json.impl

import s_mach.explain_json._
import s_mach.metadata.Metadata
import s_mach.metadata.{Cardinality, Metadata}

class MetadataBuildJsonImpl[A](implicit
buildVal: BuildJson[A]
Expand All @@ -44,6 +44,11 @@ class MetadataBuildJsonImpl[A](implicit
case Metadata.Val(value) =>
_buildVal(value)

case a@Metadata.Arr(value,Cardinality.ZeroOrOne,_) =>
a.indexToMetadata.foreach { case (index, memberMetadata) =>
loop(memberMetadata)
}

case a@Metadata.Arr(value,cardinality,_) =>
appendObject {
pruneIfEmpty {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,11 @@ class TypeMetadataBuildJsonImpl[A](implicit

def loop : TypeMetadata[A] => Unit = {
case TypeMetadata.Val(value) =>
pruneIfEmpty {
_buildVal(value)
}
()
_buildVal(value)

case TypeMetadata.Arr(value,Cardinality.ZeroOrOne,members) =>
// Note: arrays with cardinality of zero or one are treated
// as normal fields
loop(members)

case TypeMetadata.Arr(value,cardinality,membersTypeMetadata) =>
Expand Down
130 changes: 130 additions & 0 deletions explain_json/src/test/scala/s_mach/explain_json/ImplicitsTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package s_mach.explain_json

import org.scalatest.{FlatSpec, Matchers}
import s_mach.metadata.{Cardinality, Metadata, TypeMetadata}
import Util._

class ImplicitsTest extends FlatSpec with Matchers {
"JsonStringBuilderFactory" should "create a JsonBuilderFactory for String" in {
implicitly[JsonBuilderFactory[String]].apply().isInstanceOf[JsonStringBuilder] shouldBe true
}
"buildJson_Byte" should "build a number to a JsonBuilder" in {
123.toByte.printJson[String] shouldBe "123"
}
"buildJson_Short" should "build a number to a JsonBuilder" in {
123.toShort.printJson[String] shouldBe "123"
}
"buildJson_Int" should "build a number to a JsonBuilder" in {
123.printJson[String] shouldBe "123"
}
"buildJson_Long" should "build a number to a JsonBuilder" in {
123l.printJson[String] shouldBe "123"
}
"buildJson_Float" should "build a number to a JsonBuilder" in {
123.0.toFloat.printJson[String] shouldBe "123.0"
}
"buildJson_Double" should "build a number to a JsonBuilder" in {
123.0.printJson[String] shouldBe "123.0"
}
"buildJson_Seq" should "build a JSON array to a JsonBuilder" in {
List("1","2","3").printJson[String] shouldBe """["1","2","3"]"""
}
"buildJson_MapStringA" should "build a JSON object to a JsonBuilder" in {
Map("1" -> 1,"2" -> 2,"3" -> 3).printJson[String] shouldBe """{"1":1,"2":2,"3":3}"""
}
"buildJson_Metadata" should "build a JSON representation of Metadata" in {
val m : Metadata[List[String]] = Metadata.Rec(
// ensure value is emitted as "this" field
value = List("invalid"),
fields = Seq(
"id" -> Metadata.Val(List("ok")),
"name" -> Metadata.Rec(
value = List("invalid"),
fields = Seq(
// ensure empty fields are pruned
"first" -> Metadata.Val(Nil),
"last" -> Metadata.Val(List("invalid")),
"nickname" -> Metadata.Arr(
// ensure value here is not emitted
value = List("should not be emitted"),
cardinality = Cardinality.ZeroOrOne,
members = Seq(Metadata.Val(List("ok")))
)
)
),
"friendIds" -> Metadata.Arr(
value = List("ok"),
cardinality = Cardinality.ZeroOrMore,
// ensure members are emitted with index as field to value
members = Seq(
Metadata.Val(List("ok")),
// ensure 1 is pruned
Metadata.Val(Nil),
Metadata.Val(List("invalid"))
)
)
)
)

m.printJson[String].prettyJson shouldBe
"""{
"this" : [ "invalid" ],
"id" : [ "ok" ],
"name" : {
"this" : [ "invalid" ],
"last" : [ "invalid" ],
"nickname" : [ "ok" ]
},
"friendIds" : {
"this" : [ "ok" ],
"0" : [ "ok" ],
"2" : [ "invalid" ]
}
}"""

}

"buildJson_TypeMetadata" should "build a JSON representation of TypeMetadata" in {
val tm : TypeMetadata[List[String]] = TypeMetadata.Rec(
// ensure empty "this" is pruned
value = Nil,
fields = Seq(
"id" -> TypeMetadata.Val(List("must be greater than 0")),
"name" -> TypeMetadata.Rec(
value = List("first and last name must not be longer than 64 characters"),
fields = Seq(
"first" -> TypeMetadata.Val(List("must only contain letters and spaces")),
"last" -> TypeMetadata.Val(List("must only contain letters and spaces")),
// ensure arrays with zero or one member are output as fields and not arrays
"nickname" -> TypeMetadata.Arr(
// ensure array value is ignored for cardinality zero or one
value = List("should be ignored"),
cardinality = Cardinality.ZeroOrOne,
membersTypeMetadata = TypeMetadata.Val(List("must only contain letters and spaces"))
)
)
),
"friendIds" -> TypeMetadata.Arr(
value = List("can contain no more than 10 members"),
cardinality = Cardinality.ZeroOrMore,
membersTypeMetadata = TypeMetadata.Val(List("must be greater than 0"))
)
)
)

tm.printJson.prettyJson shouldBe
"""{
"id" : [ "must be greater than 0" ],
"name" : {
"this" : [ "first and last name must not be longer than 64 characters" ],
"first" : [ "must only contain letters and spaces" ],
"last" : [ "must only contain letters and spaces" ],
"nickname" : [ "must only contain letters and spaces" ]
},
"friendIds" : {
"this" : [ "can contain no more than 10 members" ],
"*" : [ "must be greater than 0" ]
}
}"""
}
}

0 comments on commit 09d282b

Please sign in to comment.