Permalink
Browse files

Adds Json section

We are adding the first of 6 sections for Circe.
  • Loading branch information...
Fran Pérez
Fran Pérez committed Jul 21, 2016
1 parent b762749 commit 88023d0d400e48f8cd78c584cbe7f6f08719bb6c
@@ -0,0 +1,36 @@
project/project
project/target
target
.idea
.tmp
*.iml
/out
.idea_modules
.classpath
.project
/RUNNING_PID
.settings
.sass-cache
scalajvm/upload/*
# temp files
.~*
*~
*.orig
# eclipse
.scala_dependencies
.buildpath
.cache
.target
bin/
.ensime
.ensime_cache
# OSX
.DS_Store
# PGP keys
pubring.gpg
secring.gpg
@@ -0,0 +1,9 @@
language: scala
scala:
- 2.11.8
jdk:
- oraclejdk8
script:
- sbt test
after_success:
- bash deploy.sh
@@ -0,0 +1,64 @@
val circeVersion = "0.4.1"
lazy val circe = (project in file("."))
.settings(publishSettings:_*)
.enablePlugins(ExerciseCompilerPlugin)
.settings(
organization := "org.scala-exercises",
name := "exercises-circe",
scalaVersion := "2.11.8",
version := "0.2.2-SNAPSHOT",
resolvers ++= Seq(
Resolver.sonatypeRepo("snapshots"),
Resolver.sonatypeRepo("releases")
),
libraryDependencies ++= Seq(
"org.typelevel" %% "cats-core" % "0.4.1",
"com.chuusai" %% "shapeless" % "2.2.5",
"org.scalatest" %% "scalatest" % "2.2.4",
"org.scala-exercises" %% "exercise-compiler" % version.value,
"org.scala-exercises" %% "definitions" % version.value,
"org.scalacheck" %% "scalacheck" % "1.12.5",
"com.github.alexarchambault" %% "scalacheck-shapeless_1.12" % "0.3.1",
"io.circe" %% "circe-core" % circeVersion,
"io.circe" %% "circe-generic" % circeVersion,
"io.circe" %% "circe-parser" % circeVersion,
compilerPlugin("org.spire-math" %% "kind-projector" % "0.7.1")
)
)
// Distribution
lazy val gpgFolder = sys.env.getOrElse("SE_GPG_FOLDER", ".")
lazy val publishSettings = Seq(
organizationName := "Scala Exercises",
organizationHomepage := Some(new URL("http://scala-exercises.org")),
startYear := Some(2016),
description := "Scala Exercises: The path to enlightenment",
homepage := Some(url("http://scala-exercises.org")),
pgpPassphrase := Some(sys.env.getOrElse("SE_GPG_PASSPHRASE", "").toCharArray),
pgpPublicRing := file(s"$gpgFolder/pubring.gpg"),
pgpSecretRing := file(s"$gpgFolder/secring.gpg"),
credentials += Credentials("Sonatype Nexus Repository Manager", "oss.sonatype.org", sys.env.getOrElse("PUBLISH_USERNAME", ""), sys.env.getOrElse("PUBLISH_PASSWORD", "")),
scmInfo := Some(ScmInfo(url("https://github.com/scala-exercises/exercises-circe"), "https://github.com/scala-exercises/exercises-circe.git")),
licenses := Seq("Apache License, Version 2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0.txt")),
publishMavenStyle := true,
publishArtifact in Test := false,
pomIncludeRepository := Function.const(false),
publishTo := {
val nexus = "https://oss.sonatype.org/"
if (isSnapshot.value)
Some("Snapshots" at nexus + "content/repositories/snapshots")
else
Some("Releases" at nexus + "service/local/staging/deploy/maven2")
},
pomExtra :=
<developers>
<developer>
<id>fperezp</id>
<name>Fran Perez</name>
<email>fran.p@47deg.com</email>
</developer>
</developers>
)
@@ -0,0 +1,23 @@
#!/bin/sh
function decipherKeys {
echo $KEYS_PASSPHRASE | gpg --passphrase-fd 0 keys.tar.gpg
tar xfv keys.tar
}
function publish {
sbt compile publishSigned
}
function release {
decipherKeys
publish
}
if [[ $TRAVIS_BRANCH == 'master' ]]; then
echo "Master branch, releasing..."
release
else
echo "Not in master branch, skipping release"
fi
BIN +2.81 KB keys.tar.gpg
Binary file not shown.
@@ -0,0 +1 @@
sbt.version=0.13.9
@@ -0,0 +1,3 @@
resolvers += Resolver.sonatypeRepo("snapshots")
addSbtPlugin("org.scala-exercises" % "sbt-exercise" % "0.2.2-SNAPSHOT", "0.13", "2.10")
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0")
@@ -0,0 +1,17 @@
package circelib
import org.scalaexercises.definitions
/** circe (pronounced SUR-see, or KEER-kee in classical Greek) is a JSON library for Scala (and Scala.js).
*
* @param name circe
*/
object CirceLibrary extends definitions.Library {
override def owner = "scala-exercises"
override def repository = "exercises-circe"
override def color = Some("#996666")
override def sections = List(JsonSection)
}
@@ -0,0 +1,145 @@
package circelib
import io.circe.Json
import org.scalaexercises.definitions
import org.scalatest._
import circelib.helpers.JsonHelpers
/** @param name Json
*/
object JsonSection extends FlatSpec with Matchers with definitions.Section {
import JsonHelpers._
/** Json is the circe data type to represent a Json object. It is a very useful data type to be familiar with since
* it's how circe is modeling the base type we want to deal with.
*
* Firstly, let's talk briefly about the shape of everyt Json object. It basically is semi structured data build on
* top of key-value pairs. These key-value pairs have a specific shape:
* - keys are strings
* - values can be of multiple types.
*
* Then, to model a real json object we need to support different data types on the value field. For this purposes
* we have different available methods so we can create a Json object from different source data types. Some examples
* of these methods are `fromString`, `fromBoolean`, `fromDouble` and so on. For further details about all possible
* methods, see https://travisbrown.github.io/circe/api/#io.circe.Json$
*
* Let's see how these methods work.
*
* {{{
* scala> // fromString example
* scala> val jsonString: Json = Json.fromString("scala exercises")
* jsonString: io.circe.Json = "scala exercises"
*
* scala> // fromDouble example
* scala> val jsonDouble: Option[Json] = Json.fromDouble(1)
* jsonDouble: Option[io.circe.Json] = Some(1.0)
*
* scala> val jsonDouble: Option[Json] = Json.fromDouble(1)
* jsonString: Option[io.circe.Json] = Some(1.0)
*
* scala> // fromFields example
* scala> val fieldList = List(
* ("key1", Json.fromString("value1")),
* ("key2", Json.fromInt(1)))
* fieldList: List[(String, io.circe.Json)] = List((key1,"value1"), (key2,1))
*
* scala> val jsonFromFields: Json = Json.fromFields(fieldList)
* jsonFromFields: io.circe.Json =
* {
* "key1" : "value1",
* "key2" : 1
* }
*
* }}}
*
*
* In addition, there are some other methods that allow you to convert from a Json object to a String.
*
* {{{
*
* scala> jsonFromFields.noSpaces
* res0: String = {"name":"sample json","version":1,"data":{"done":false,"rate":4.9}}
*
* scala> jsonFromFields.spaces2
* res1: String =
* {
* "name" : "sample json",
* "version" : 1,
* "data" : {
* "done" : false,
* "rate" : 4.9
* }
* }
*
* scala> jsonFromFields.spaces4
* res2: String =
* {
* "name" : "sample json",
* "version" : 1,
* "data" : {
* "done" : false,
* "rate" : 4.9
* }
* }
*
* }}}
*
* What would be the string output for our jsonFromFields value?
*/
def jsonToString(res0: String) = {
jsonFromFields.noSpaces should be (res0)
}
/** Let's see how we can use these methods to create custom Jsons that represents specific Json strings.
*/
def jsonObject(res0: Json, res1: (String, Json), res2: (String, Json), res3: Json) = {
"{\"key\":\"value\"}" should be(res0.noSpaces)
"{\"name\":\"sample json\",\"data\":{\"done\":false}}" should be (Json.fromFields(List(
res1,
res2)
).noSpaces)
"[{\"x\":1}]" should be (res3.noSpaces)
}
/** Furthemore, there are some other methods that allows you to deal with Json objects and apply transformation. We
* can use them to modify or apply any changes to a given Json object in a simpler way as if we have to deal with it
* manually.
*
* We are going to start from this Json array:
*
* {{{
* val jsonArray: Json = Json.fromValues(List(
* Json.fromFields(List(("field1", Json.fromInt(1)))),
* Json.fromFields(List(
* ("field1", Json.fromInt(200)),
* ("field2", Json.fromString("Having circe in Scala Exercises is awesome"))
* ))
* ))
*
* }}}
*
* Finally, we have a transformJson method:
*
* {{{
* def transformJson(jsonArray: Json): Json =
* jsonArray mapArray { oneJson: List[Json] =>
* oneJson.init
* }
* }}}
*
* So, having them, what's should be the result if we apply our transformJson function to our jsonArray value?
*
*/
def jsonClass(res0: String) = {
transformJson(jsonArray).noSpaces should be (res0)
}
}
@@ -0,0 +1,23 @@
package circelib.helpers
import io.circe.Json
object JsonHelpers {
val jsonFromFields: Json = Json.fromFields(List(
("key1", Json.fromString("value1")),
("key2", Json.fromInt(1))
))
val jsonArray: Json = Json.fromValues(List(
Json.fromFields(List(("field1", Json.fromInt(1)))),
Json.fromFields(List(
("field1", Json.fromInt(200)),
("field2", Json.fromString("Having circe in Scala Exercises is awesome"))
))
))
def transformJson(jsonArray: Json): Json =
jsonArray mapArray(_.init)
}
@@ -0,0 +1,52 @@
package circelib
import io.circe.Json
import org.scalacheck.Shapeless._
import org.scalaexercises.Test
import org.scalatest.Spec
import org.scalatest.prop.Checkers
import shapeless.HNil
import circelib.utils.JsonArbitraries
class JsonSpec extends Spec with Checkers {
import JsonArbitraries._
def `json to String` = {
val jsonString = "{\"key1\":\"value1\",\"key2\":1}"
check(
Test.testSuccess(
JsonSection.jsonToString _,
jsonString :: HNil
)
)
}
def `Json Object helpers` = {
val res0: Json = Json.obj("key" -> Json.fromString("value"))
val res1: (String, Json) = ("name", Json.fromString("sample json"))
val res2: (String, Json) = ("data", Json.obj("done" -> Json.fromBoolean(false)))
val res3: Json = Json.fromValues(List(Json.obj("x" -> Json.fromInt(1))))
check(
Test.testSuccess(
JsonSection.jsonObject _,
res0 :: res1 :: res2 :: res3 :: HNil
)
)
}
def `Json Class methods` = {
val jsonArray = "[{\"field1\":1}]"
check(
Test.testSuccess(
JsonSection.jsonClass _,
jsonArray :: HNil
)
)
}
}
@@ -0,0 +1,13 @@
package circelib.utils
import io.circe.syntax._
import io.circe.{Encoder, Json}
import org.scalacheck.{Arbitrary, Gen}
import org.scalacheck.Gen._
object JsonArbitraries {
implicit def arbJson: Arbitrary[Json] = Arbitrary(alphaStr map (_.asJson))
implicit def arbStringJsonPair: Arbitrary[(String, Json)] = Arbitrary(alphaStr map (string => (string, string.asJson)))
}

0 comments on commit 88023d0

Please sign in to comment.