Skip to content

Instantly share code, notes, and snippets.

@xuwei-k
Created November 9, 2014 09:47
Show Gist options
  • Save xuwei-k/36ca7a1668ef2778bab9 to your computer and use it in GitHub Desktop.
Save xuwei-k/36ca7a1668ef2778bab9 to your computer and use it in GitHub Desktop.
Json Pointer Scala
name := "jsonpointer"
libraryDependencies ++= (
("io.argonaut" %% "argonaut" % "6.1-M4") ::
Nil
)
scalaVersion := "2.11.4"
licenses := Seq("MIT License" -> url("http://www.opensource.org/licenses/mit-license.php")),
package jsonpointer
import argonaut.Json
import scalaz.{IList, Order}
import scalaz.std.anyVal._
import scalaz.std.string._
import scalaz.std.vector._
sealed abstract class PointerNode{
def asString: String
}
object PointerNode{
final case class Node(private val raw: String) extends PointerNode{
override def asString = raw.replace("~", "~0").replace("/", "~1")
}
final case class Index(i: Long) extends PointerNode{
assert(i >= 0, "index must be positive")
override def asString = i.toString
}
implicit val instance: Order[PointerNode] =
Order.order{
case (Index(_), Node(_)) => scalaz.Ordering.LT
case (Node(_), Index(_)) => scalaz.Ordering.GT
case (Node(a), Node(b)) => Order[String].order(a, b)
case (Index(a), Index(b)) => Order[Long].order(a, b)
}
}
final case class JsonPointer(values: Vector[PointerNode]){
def |+|(that: JsonPointer): JsonPointer = JsonPointer(values ++ that.values)
def :+(node: PointerNode): JsonPointer = JsonPointer(values :+ node)
def +:(node: PointerNode): JsonPointer = JsonPointer(node +: values)
override def toString: String = values.map(_.asString).mkString("/", "/", "")
}
object JsonPointer {
val root: JsonPointer = JsonPointer(Vector.empty)
implicit val instance: Order[JsonPointer] =
Order.orderBy(_.values)
private def loop(json: Json, acc: JsonPointer): Map[JsonPointer, Json] = {
json.arrayOrObject[Map[JsonPointer, Json]](
or = Map.empty,
jsonArray = array => {
array.zipWithIndex.map{ case (j, i) =>
loop(j, acc :+ PointerNode.Index(i))
}.reduceOption(_ ++ _).getOrElse(Map.empty)
},
jsonObject = obj => {
obj.toMap.map{ case (k, v) =>
loop(v, acc :+ PointerNode.Node(k))
}.reduceOption(_ ++ _).getOrElse(Map.empty)
}
) ++ Map(acc -> json)
}
def toMap(json: Json): Map[JsonPointer, Json] =
loop(json, root)
def sortedList(json: Json): IList[(JsonPointer, Json)] =
IList.fromFoldable(loop(json, root).toVector).sortBy(_._1)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment