From 8b45fe19e4dfb76ac4fb58e8fc7154adc4bf86bd Mon Sep 17 00:00:00 2001 From: Juan Pedro Moreno Date: Wed, 28 Sep 2016 18:33:43 +0200 Subject: [PATCH 1/5] Initial workarond to make evaluator client compatible with ScalaJS --- build.sbt | 37 +++++++++++++++---- .../scalaexercises/evaluator/Decoders.scala | 0 .../evaluator/EvaluatorAPI.scala | 0 .../evaluator/EvaluatorClient.scala | 0 .../evaluator/EvaluatorResponses.scala | 0 .../evaluator/api/Evaluator.scala | 0 .../evaluator/free/algebra/EvaluatorOps.scala | 0 .../free/interpreters/Interpreter.scala | 0 .../evaluator/http/HttpClient.scala | 0 .../evaluator/http/HttpRequestBuilder.scala | 0 .../scalaexercises/evaluator/implicits.scala | 0 project/EvaluatorBuild.scala | 2 +- project/plugins.sbt | 1 + .../scalaexercises/evaluator/evaluation.scala | 3 +- .../org/scalaexercises/evaluator/types.scala | 0 15 files changed, 33 insertions(+), 10 deletions(-) rename client/{ => shared}/src/main/scala/org/scalaexercises/evaluator/Decoders.scala (100%) rename client/{ => shared}/src/main/scala/org/scalaexercises/evaluator/EvaluatorAPI.scala (100%) rename client/{ => shared}/src/main/scala/org/scalaexercises/evaluator/EvaluatorClient.scala (100%) rename client/{ => shared}/src/main/scala/org/scalaexercises/evaluator/EvaluatorResponses.scala (100%) rename client/{ => shared}/src/main/scala/org/scalaexercises/evaluator/api/Evaluator.scala (100%) rename client/{ => shared}/src/main/scala/org/scalaexercises/evaluator/free/algebra/EvaluatorOps.scala (100%) rename client/{ => shared}/src/main/scala/org/scalaexercises/evaluator/free/interpreters/Interpreter.scala (100%) rename client/{ => shared}/src/main/scala/org/scalaexercises/evaluator/http/HttpClient.scala (100%) rename client/{ => shared}/src/main/scala/org/scalaexercises/evaluator/http/HttpRequestBuilder.scala (100%) rename client/{ => shared}/src/main/scala/org/scalaexercises/evaluator/implicits.scala (100%) rename shared/{ => shared}/src/main/scala/org/scalaexercises/evaluator/types.scala (100%) diff --git a/build.sbt b/build.sbt index 9cddbbb5..4c927f7c 100644 --- a/build.sbt +++ b/build.sbt @@ -1,22 +1,38 @@ +lazy val noPublishSettings = Seq( + publish := (), + publishLocal := (), + publishArtifact := false +) + lazy val root = (project in file(".")) .settings(mainClass in Universal := Some("org.scalaexercises.evaluator.EvaluatorServer")) .settings(stage <<= (stage in Universal in `evaluator-server`)) - .aggregate(`evaluator-server`, `evaluator-shared`, `evaluator-client`) + .settings(noPublishSettings: _*) + .aggregate(`evaluator-server`, `evaluator-shared-jvm`, `evaluator-shared-js`, `evaluator-client-jvm`, `evaluator-client-js`) -lazy val `evaluator-shared` = (project in file("shared")) +lazy val `evaluator-shared` = (crossProject in file("shared")) .enablePlugins(AutomateHeaderPlugin) .settings(name := "evaluator-shared") -lazy val `evaluator-client` = (project in file("client")) +lazy val `evaluator-shared-jvm` = `evaluator-shared`.jvm +lazy val `evaluator-shared-js` = `evaluator-shared`.js + +lazy val scalaJSSettings = Seq( + requiresDOM := false, + scalaJSUseRhino := false, + jsEnv := NodeJSEnv().value +) + +lazy val `evaluator-client` = (crossProject in file("client")) .dependsOn(`evaluator-shared`) .enablePlugins(AutomateHeaderPlugin) .settings( name := "evaluator-client", libraryDependencies <++= libraryVersions { v => Seq( "org.typelevel" %% "cats-free" % v('cats), - "io.circe" %% "circe-core" % v('circe), - "io.circe" %% "circe-generic" % v('circe), - "io.circe" %% "circe-parser" % v('circe), + "io.circe" %% "circe-core" % v('circe), + "io.circe" %% "circe-generic" % v('circe), + "io.circe" %% "circe-parser" % v('circe), "org.log4s" %% "log4s" % v('log4s), "org.scalaj" %% "scalaj-http" % v('scalajhttp), "org.slf4j" % "slf4j-simple" % v('slf4j), @@ -24,12 +40,17 @@ lazy val `evaluator-client` = (project in file("client")) "org.scalatest" %% "scalatest" % v('scalaTest) % "test" ) } - ) + ) + .jsSettings(scalaJSSettings: _*) + +lazy val `evaluator-client-jvm` = `evaluator-client`.jvm +lazy val `evaluator-client-js` = `evaluator-client`.js lazy val `evaluator-server` = (project in file("server")) - .dependsOn(`evaluator-shared`) + .dependsOn(`evaluator-shared-jvm`) .enablePlugins(JavaAppPackaging) .enablePlugins(AutomateHeaderPlugin) + .settings(noPublishSettings: _*) .settings( name := "evaluator-server", libraryDependencies <++= libraryVersions { v => Seq( diff --git a/client/src/main/scala/org/scalaexercises/evaluator/Decoders.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/Decoders.scala similarity index 100% rename from client/src/main/scala/org/scalaexercises/evaluator/Decoders.scala rename to client/shared/src/main/scala/org/scalaexercises/evaluator/Decoders.scala diff --git a/client/src/main/scala/org/scalaexercises/evaluator/EvaluatorAPI.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/EvaluatorAPI.scala similarity index 100% rename from client/src/main/scala/org/scalaexercises/evaluator/EvaluatorAPI.scala rename to client/shared/src/main/scala/org/scalaexercises/evaluator/EvaluatorAPI.scala diff --git a/client/src/main/scala/org/scalaexercises/evaluator/EvaluatorClient.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/EvaluatorClient.scala similarity index 100% rename from client/src/main/scala/org/scalaexercises/evaluator/EvaluatorClient.scala rename to client/shared/src/main/scala/org/scalaexercises/evaluator/EvaluatorClient.scala diff --git a/client/src/main/scala/org/scalaexercises/evaluator/EvaluatorResponses.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/EvaluatorResponses.scala similarity index 100% rename from client/src/main/scala/org/scalaexercises/evaluator/EvaluatorResponses.scala rename to client/shared/src/main/scala/org/scalaexercises/evaluator/EvaluatorResponses.scala diff --git a/client/src/main/scala/org/scalaexercises/evaluator/api/Evaluator.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/api/Evaluator.scala similarity index 100% rename from client/src/main/scala/org/scalaexercises/evaluator/api/Evaluator.scala rename to client/shared/src/main/scala/org/scalaexercises/evaluator/api/Evaluator.scala diff --git a/client/src/main/scala/org/scalaexercises/evaluator/free/algebra/EvaluatorOps.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/free/algebra/EvaluatorOps.scala similarity index 100% rename from client/src/main/scala/org/scalaexercises/evaluator/free/algebra/EvaluatorOps.scala rename to client/shared/src/main/scala/org/scalaexercises/evaluator/free/algebra/EvaluatorOps.scala diff --git a/client/src/main/scala/org/scalaexercises/evaluator/free/interpreters/Interpreter.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/free/interpreters/Interpreter.scala similarity index 100% rename from client/src/main/scala/org/scalaexercises/evaluator/free/interpreters/Interpreter.scala rename to client/shared/src/main/scala/org/scalaexercises/evaluator/free/interpreters/Interpreter.scala diff --git a/client/src/main/scala/org/scalaexercises/evaluator/http/HttpClient.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/http/HttpClient.scala similarity index 100% rename from client/src/main/scala/org/scalaexercises/evaluator/http/HttpClient.scala rename to client/shared/src/main/scala/org/scalaexercises/evaluator/http/HttpClient.scala diff --git a/client/src/main/scala/org/scalaexercises/evaluator/http/HttpRequestBuilder.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/http/HttpRequestBuilder.scala similarity index 100% rename from client/src/main/scala/org/scalaexercises/evaluator/http/HttpRequestBuilder.scala rename to client/shared/src/main/scala/org/scalaexercises/evaluator/http/HttpRequestBuilder.scala diff --git a/client/src/main/scala/org/scalaexercises/evaluator/implicits.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/implicits.scala similarity index 100% rename from client/src/main/scala/org/scalaexercises/evaluator/implicits.scala rename to client/shared/src/main/scala/org/scalaexercises/evaluator/implicits.scala diff --git a/project/EvaluatorBuild.scala b/project/EvaluatorBuild.scala index f8a6ad6b..bfea78e7 100644 --- a/project/EvaluatorBuild.scala +++ b/project/EvaluatorBuild.scala @@ -37,7 +37,7 @@ object EvaluatorBuild extends AutoPlugin { private[this] def baseSettings = Seq( - version := "0.0.3-SNAPSHOT", + version := "0.0.4-SNAPSHOT", organization := "org.scala-exercises", scalaVersion := "2.11.8", scalafmtConfig in ThisBuild := Some(file(".scalafmt")), diff --git a/project/plugins.sbt b/project/plugins.sbt index 85e4cdec..a68ff8a3 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -2,3 +2,4 @@ addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.1.1") addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "0.2.11") addSbtPlugin("de.heikoseeberger" % "sbt-header" % "1.6.0") addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.1") +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.12") \ No newline at end of file diff --git a/server/src/main/scala/org/scalaexercises/evaluator/evaluation.scala b/server/src/main/scala/org/scalaexercises/evaluator/evaluation.scala index 0b307bc7..63bbe528 100644 --- a/server/src/main/scala/org/scalaexercises/evaluator/evaluation.scala +++ b/server/src/main/scala/org/scalaexercises/evaluator/evaluation.scala @@ -57,7 +57,8 @@ class Evaluator(timeout: FiniteDuration = 20.seconds)( def resolveArtifacts(remotes: Seq[Remote], dependencies: Seq[Dependency]): Task[Resolution] = { val resolution = Resolution(dependencies.map(dependencyToModule).toSet) - val repositories: Seq[Repository] = Cache.ivy2Local +: remotes.map(remoteToRepository) + val repositories: Seq[Repository] = Cache.ivy2Local +: remotes.map( + remoteToRepository) val fetch = Fetch.from(repositories, Cache.fetch()) resolution.process.run(fetch) } diff --git a/shared/src/main/scala/org/scalaexercises/evaluator/types.scala b/shared/shared/src/main/scala/org/scalaexercises/evaluator/types.scala similarity index 100% rename from shared/src/main/scala/org/scalaexercises/evaluator/types.scala rename to shared/shared/src/main/scala/org/scalaexercises/evaluator/types.scala From 6c8b062c3044df3c05419c87ea3a8a2df537cebe Mon Sep 17 00:00:00 2001 From: Juan Pedro Moreno Date: Thu, 6 Oct 2016 23:01:28 +0200 Subject: [PATCH 2/5] First workaround to use RosHTTP Client --- build.sbt | 8 ++-- .../evaluator/EvaluatorAPI.scala | 19 ++------ .../evaluator/EvaluatorClient.scala | 26 ++++------ .../evaluator/EvaluatorResponses.scala | 47 +++++++++++-------- .../evaluator/api/Evaluator.scala | 8 +--- .../evaluator/free/algebra/EvaluatorOps.scala | 16 +------ .../free/interpreters/Interpreter.scala | 35 +++----------- .../evaluator/http/HttpClient.scala | 14 ++---- .../evaluator/http/HttpRequestBuilder.scala | 31 ++++++------ .../scalaexercises/evaluator/implicits.scala | 32 +------------ project/EvaluatorBuild.scala | 6 +-- 11 files changed, 77 insertions(+), 165 deletions(-) diff --git a/build.sbt b/build.sbt index 4c927f7c..5d493e4e 100644 --- a/build.sbt +++ b/build.sbt @@ -34,13 +34,13 @@ lazy val `evaluator-client` = (crossProject in file("client")) "io.circe" %% "circe-generic" % v('circe), "io.circe" %% "circe-parser" % v('circe), "org.log4s" %% "log4s" % v('log4s), - "org.scalaj" %% "scalaj-http" % v('scalajhttp), "org.slf4j" % "slf4j-simple" % v('slf4j), // Testing libraries "org.scalatest" %% "scalatest" % v('scalaTest) % "test" ) - } - ) + }, + libraryDependencies += "fr.hmil" %%% "roshttp" % "1.1.0" +) .jsSettings(scalaJSSettings: _*) lazy val `evaluator-client-jvm` = `evaluator-client`.jvm @@ -75,4 +75,4 @@ lazy val `evaluator-server` = (project in file("server")) .settings(compilerDependencySettings: _*) onLoad in Global := (Command.process("project evaluator-server", _: State)) compose (onLoad in Global).value -addCommandAlias("publishSignedAll", ";evaluator-shared/publishSigned;evaluator-client/publishSigned") \ No newline at end of file +addCommandAlias("publishSignedAll", ";evaluator-sharedJS/publishSigned;evaluator-sharedJVM/publishSigned;evaluator-clientJS/publishSigned;evaluator-clientJVM/publishSigned") diff --git a/client/shared/src/main/scala/org/scalaexercises/evaluator/EvaluatorAPI.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/EvaluatorAPI.scala index c5e7dec1..7f9b92e2 100644 --- a/client/shared/src/main/scala/org/scalaexercises/evaluator/EvaluatorAPI.scala +++ b/client/shared/src/main/scala/org/scalaexercises/evaluator/EvaluatorAPI.scala @@ -7,24 +7,13 @@ package org.scalaexercises.evaluator import cats.free.Free import org.scalaexercises.evaluator.EvaluatorResponses.EvaluationResponse -import org.scalaexercises.evaluator.free.algebra.{EvaluatorOp, EvaluatorOps} +import org.scalaexercises.evaluator.free.algebra.EvaluatorOps -import scala.concurrent.duration.Duration - -class EvaluatorAPI[F[_]](url: String, - authKey: String, - connTimeout: Duration, - readTimeout: Duration)(implicit O: EvaluatorOps[F]) { +class EvaluatorAPI[F[_]](url: String, authKey: String)( + implicit O: EvaluatorOps[F]) { def evaluates(resolvers: List[String] = Nil, dependencies: List[Dependency] = Nil, code: String): Free[F, EvaluationResponse[EvalResponse]] = - O.evaluates( - url, - authKey, - connTimeout, - readTimeout, - resolvers, - dependencies, - code) + O.evaluates(url, authKey, resolvers, dependencies, code) } diff --git a/client/shared/src/main/scala/org/scalaexercises/evaluator/EvaluatorClient.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/EvaluatorClient.scala index 1b60b50c..6df3bef5 100644 --- a/client/shared/src/main/scala/org/scalaexercises/evaluator/EvaluatorClient.scala +++ b/client/shared/src/main/scala/org/scalaexercises/evaluator/EvaluatorClient.scala @@ -6,36 +6,30 @@ package org.scalaexercises.evaluator import cats.data.XorT -import cats.{MonadError, ~>} +import cats.~> +import cats._, cats.std.all._ import org.scalaexercises.evaluator.EvaluatorResponses.{EvalIO, EvaluationException, EvaluationResponse, EvaluationResult} import org.scalaexercises.evaluator.free.algebra.EvaluatorOp -import scala.concurrent.duration._ -import scala.concurrent.duration.Duration +import scala.concurrent.Future +import scala.concurrent.ExecutionContext.Implicits.global -class EvaluatorClient(url: String, - authKey: String, - connTimeout: Duration = 1.second, - readTimeout: Duration = 10.seconds) { +class EvaluatorClient(url: String, authKey: String) { - lazy val api: EvaluatorAPI[EvaluatorOp] = - new EvaluatorAPI(url, authKey, connTimeout, readTimeout) + lazy val api: EvaluatorAPI[EvaluatorOp] = new EvaluatorAPI(url, authKey) } object EvaluatorClient { - def apply(url: String, - authKey: String, - connTimeout: Duration = 1.second, - readTimeout: Duration = 10.seconds) = - new EvaluatorClient(url, authKey, connTimeout, readTimeout) + def apply(url: String, authKey: String) = + new EvaluatorClient(url, authKey) implicit class EvaluationIOSyntaxXOR[A]( evalIO: EvalIO[EvaluationResponse[A]]) { - def exec[M[_]](implicit I: (EvaluatorOp ~> M), - A: MonadError[M, Throwable]): M[EvaluationResponse[A]] = + def exec( + implicit I: (EvaluatorOp ~> Future)): Future[EvaluationResponse[A]] = evalIO foldMap I def liftEvaluator: XorT[EvalIO, EvaluationException, EvaluationResult[A]] = diff --git a/client/shared/src/main/scala/org/scalaexercises/evaluator/EvaluatorResponses.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/EvaluatorResponses.scala index b305a942..8a4ebfd3 100644 --- a/client/shared/src/main/scala/org/scalaexercises/evaluator/EvaluatorResponses.scala +++ b/client/shared/src/main/scala/org/scalaexercises/evaluator/EvaluatorResponses.scala @@ -13,8 +13,11 @@ import io.circe.parser._ import io.circe.generic.auto._ import org.scalaexercises.evaluator.free.algebra.EvaluatorOp -import scala.language.higherKinds -import scalaj.http.HttpResponse +import scala.concurrent.Future +import scala.concurrent.ExecutionContext.Implicits.global + +import fr.hmil.roshttp.HttpResponse +import fr.hmil.roshttp.HeaderMap object EvaluatorResponses { @@ -24,7 +27,7 @@ object EvaluatorResponses { case class EvaluationResult[A](result: A, statusCode: Int, - headers: Map[String, IndexedSeq[String]]) + headers: Map[String, String]) sealed abstract class EvaluationException(msg: String, cause: Option[Throwable] = None) @@ -37,24 +40,30 @@ object EvaluatorResponses { case class UnexpectedException(msg: String) extends EvaluationException(msg) - def toEntity[A](response: HttpResponse[String])( - implicit D: Decoder[A]): EvaluationResponse[A] = response match { - case r if r.isSuccess ⇒ - decode[A](r.body).fold( - e ⇒ - JsonParsingException(e.getMessage, r.body).left[EvaluationResult[A]], - result ⇒ - Xor.Right(EvaluationResult(result, r.code, r.headers.toLowerCase)) - ) - case r ⇒ - UnexpectedException( - s"Failed invoking get with status : ${r.code}, body : \n ${r.body}") - .left[EvaluationResult[A]] - } + def toEntity[A](futureResponse: Future[HttpResponse])( + implicit D: Decoder[A]): Future[EvaluationResponse[A]] = + futureResponse map { + case r if isSuccess(r.statusCode) ⇒ + decode[A](r.body).fold( + e ⇒ + JsonParsingException(e.getMessage, r.body) + .left[EvaluationResult[A]], + result ⇒ + Xor.Right( + EvaluationResult(result, r.statusCode, r.headers.toLowerCase)) + ) + case r ⇒ + UnexpectedException( + s"Failed invoking get with status : ${r.statusCode}, body : \n ${r.body}") + .left[EvaluationResult[A]] + } - implicit class HeadersLowerCase[A](headers: Map[String, A]) { + private[this] def isSuccess(statusCode: Int) = + statusCode >= 200 && statusCode <= 299 - def toLowerCase: Map[String, A] = headers.map(e ⇒ (e._1.toLowerCase, e._2)) + implicit class HeadersLowerCase[A >: String](headers: HeaderMap[A]) { + def toLowerCase: Map[String, A] = + headers.iterator.map(t => (t._1.toLowerCase, t._2)).toList.toMap } } diff --git a/client/shared/src/main/scala/org/scalaexercises/evaluator/api/Evaluator.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/api/Evaluator.scala index 332fb92e..05db870a 100644 --- a/client/shared/src/main/scala/org/scalaexercises/evaluator/api/Evaluator.scala +++ b/client/shared/src/main/scala/org/scalaexercises/evaluator/api/Evaluator.scala @@ -11,7 +11,7 @@ import org.scalaexercises.evaluator.http.HttpClient import io.circe.generic.auto._ import io.circe.syntax._ -import scala.concurrent.duration.Duration +import scala.concurrent.Future class Evaluator { @@ -21,16 +21,12 @@ class Evaluator { def eval(url: String, authKey: String, - connTimeout: Duration, - readTimeout: Duration, resolvers: List[String] = Nil, dependencies: List[Dependency] = Nil, - code: String): EvaluationResponse[EvalResponse] = + code: String): Future[EvaluationResponse[EvalResponse]] = httpClient.post[EvalResponse]( url = url, secretKey = authKey, - connTimeout = connTimeout, - readTimeout = readTimeout, data = EvalRequest(resolvers, dependencies, code).asJson.noSpaces) } diff --git a/client/shared/src/main/scala/org/scalaexercises/evaluator/free/algebra/EvaluatorOps.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/free/algebra/EvaluatorOps.scala index a78ee978..11b3e555 100644 --- a/client/shared/src/main/scala/org/scalaexercises/evaluator/free/algebra/EvaluatorOps.scala +++ b/client/shared/src/main/scala/org/scalaexercises/evaluator/free/algebra/EvaluatorOps.scala @@ -9,14 +9,9 @@ import cats.free.{Free, Inject} import org.scalaexercises.evaluator.{Dependency, EvalResponse} import org.scalaexercises.evaluator.EvaluatorResponses.EvaluationResponse -import scala.concurrent.duration._ -import scala.concurrent.duration.Duration - sealed trait EvaluatorOp[A] final case class Evaluates(url: String, authKey: String, - connTimeout: Duration, - readTimeout: Duration, resolvers: List[String] = Nil, dependencies: List[Dependency] = Nil, code: String) @@ -27,21 +22,12 @@ class EvaluatorOps[F[_]](implicit I: Inject[EvaluatorOp, F]) { def evaluates( url: String, authKey: String, - connTimeout: Duration, - readTimeout: Duration, resolvers: List[String] = Nil, dependencies: List[Dependency] = Nil, code: String ): Free[F, EvaluationResponse[EvalResponse]] = Free.inject[EvaluatorOp, F]( - Evaluates( - url, - authKey, - connTimeout, - readTimeout, - resolvers, - dependencies, - code)) + Evaluates(url, authKey, resolvers, dependencies, code)) } diff --git a/client/shared/src/main/scala/org/scalaexercises/evaluator/free/interpreters/Interpreter.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/free/interpreters/Interpreter.scala index dd1d2130..687bbceb 100644 --- a/client/shared/src/main/scala/org/scalaexercises/evaluator/free/interpreters/Interpreter.scala +++ b/client/shared/src/main/scala/org/scalaexercises/evaluator/free/interpreters/Interpreter.scala @@ -5,46 +5,25 @@ package org.scalaexercises.evaluator.free.interpreters -import cats.{ApplicativeError, Eval, MonadError, ~>} +import cats.~> import org.scalaexercises.evaluator.api.Evaluator import org.scalaexercises.evaluator.free.algebra.{Evaluates, EvaluatorOp} -import scala.language.higherKinds +import scala.concurrent.Future trait Interpreter { - implicit def interpreter[M[_]]( - implicit A: MonadError[M, Throwable] - ): EvaluatorOp ~> M = evaluatorOpsInterpreter[M] - /** * Lifts Evaluator Ops to an effect capturing Monad such as Task via natural transformations */ - def evaluatorOpsInterpreter[M[_]]( - implicit A: ApplicativeError[M, Throwable]): EvaluatorOp ~> M = - new (EvaluatorOp ~> M) { + implicit def evaluatorOpsInterpreter: EvaluatorOp ~> Future = + new (EvaluatorOp ~> Future) { val evaluator = new Evaluator() - def apply[A](fa: EvaluatorOp[A]): M[A] = fa match { - case Evaluates( - url, - authKey, - connTimeout, - readTimeout, - resolvers, - dependencies, - code) ⇒ - A.pureEval( - Eval.later( - evaluator.eval( - url, - authKey, - connTimeout, - readTimeout, - resolvers, - dependencies, - code))) + def apply[A](fa: EvaluatorOp[A]): Future[A] = fa match { + case Evaluates(url, authKey, resolvers, dependencies, code) ⇒ + evaluator.eval(url, authKey, resolvers, dependencies, code) } } diff --git a/client/shared/src/main/scala/org/scalaexercises/evaluator/http/HttpClient.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/http/HttpClient.scala index da58573e..8401b5ba 100644 --- a/client/shared/src/main/scala/org/scalaexercises/evaluator/http/HttpClient.scala +++ b/client/shared/src/main/scala/org/scalaexercises/evaluator/http/HttpClient.scala @@ -8,9 +8,7 @@ package org.scalaexercises.evaluator.http import io.circe.Decoder import org.scalaexercises.evaluator.EvaluatorResponses import org.scalaexercises.evaluator.EvaluatorResponses.EvaluationResponse - -import scala.concurrent.duration._ -import scala.concurrent.duration.Duration +import scala.concurrent.Future object HttpClient { @@ -26,17 +24,11 @@ class HttpClient { url: String, secretKey: String, method: String = "post", - connTimeout: Duration, - readTimeout: Duration, headers: Headers = Map.empty, data: String - )(implicit D: Decoder[A]): EvaluationResponse[A] = + )(implicit D: Decoder[A]): Future[EvaluationResponse[A]] = EvaluatorResponses.toEntity( - HttpRequestBuilder( - url = url, - httpVerb = method, - connTimeout = connTimeout, - readTimeout = readTimeout) + HttpRequestBuilder(url = url, httpVerb = method) .withHeaders(headers + (authHeaderName -> secretKey)) .withBody(data) .run) diff --git a/client/shared/src/main/scala/org/scalaexercises/evaluator/http/HttpRequestBuilder.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/http/HttpRequestBuilder.scala index 5485cbec..bb18355c 100644 --- a/client/shared/src/main/scala/org/scalaexercises/evaluator/http/HttpRequestBuilder.scala +++ b/client/shared/src/main/scala/org/scalaexercises/evaluator/http/HttpRequestBuilder.scala @@ -7,33 +7,30 @@ package org.scalaexercises.evaluator.http import org.scalaexercises.evaluator.http.HttpClient._ -import scala.concurrent.duration.Duration -import scalaj.http.{Http, HttpOptions} +import scala.concurrent.Future + +import fr.hmil.roshttp.body.Implicits._ +import fr.hmil.roshttp.{HttpRequest, Method, HttpResponse} +import fr.hmil.roshttp.body.JSONBody case class HttpRequestBuilder( url: String, httpVerb: String, - connTimeout: Duration, - readTimeout: Duration, - followRedirects: Boolean = true, headers: Headers = Map.empty[String, String], - body: Option[String] = None + body: String = "" ) { def withHeaders(headers: Headers) = copy(headers = headers) - def withBody(body: String) = copy(body = Option(body)) + def withBody(body: String) = copy(body = body) + + def run: Future[HttpResponse] = { - def run = { - val request = Http(url).method(httpVerb).headers(headers) + val request = HttpRequest(url) + .withMethod(Method(httpVerb)) + .withHeaders(headers.toList: _*) + .withHeader("content.type", "application/json") - body - .fold(request)( - request - .option(HttpOptions.connTimeout(connTimeout.toMillis.toInt)) - .option(HttpOptions.readTimeout(readTimeout.toMillis.toInt)) - .postData(_) - .header("content-type", "application/json")) - .asString + request.post(JSONBody(body)) } } diff --git a/client/shared/src/main/scala/org/scalaexercises/evaluator/implicits.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/implicits.scala index 84043653..ba158078 100644 --- a/client/shared/src/main/scala/org/scalaexercises/evaluator/implicits.scala +++ b/client/shared/src/main/scala/org/scalaexercises/evaluator/implicits.scala @@ -6,36 +6,6 @@ package org.scalaexercises.evaluator import cats.std.FutureInstances -import cats.std.future._ -import cats.{Eval, MonadError} import org.scalaexercises.evaluator.free.interpreters.Interpreter -object implicits extends Interpreter with EvalInstances with FutureInstances - -trait EvalInstances { - - implicit val evalMonadError: MonadError[Eval, Throwable] = - new MonadError[Eval, Throwable] { - - override def pure[A](x: A): Eval[A] = Eval.now(x) - - override def map[A, B](fa: Eval[A])(f: A ⇒ B): Eval[B] = fa.map(f) - - override def flatMap[A, B](fa: Eval[A])(ff: A ⇒ Eval[B]): Eval[B] = - fa.flatMap(ff) - - override def raiseError[A](e: Throwable): Eval[A] = - Eval.later({ throw e }) - - override def handleErrorWith[A](fa: Eval[A])( - f: Throwable ⇒ Eval[A]): Eval[A] = - Eval.later({ - try { - fa.value - } catch { - case e: Throwable ⇒ f(e).value - } - }) - } - -} +object implicits extends Interpreter with FutureInstances diff --git a/project/EvaluatorBuild.scala b/project/EvaluatorBuild.scala index bfea78e7..544df61d 100644 --- a/project/EvaluatorBuild.scala +++ b/project/EvaluatorBuild.scala @@ -37,7 +37,7 @@ object EvaluatorBuild extends AutoPlugin { private[this] def baseSettings = Seq( - version := "0.0.4-SNAPSHOT", + version := "0.1.0-SNAPSHOT", organization := "org.scala-exercises", scalaVersion := "2.11.8", scalafmtConfig in ThisBuild := Some(file(".scalafmt")), @@ -65,7 +65,7 @@ object EvaluatorBuild extends AutoPlugin { 'jwtcore -> "0.8.0", 'log4s -> "1.3.0", 'monix -> "2.0-RC8", - 'scalajhttp -> "2.3.0", + 'roshttp -> "1.1.0", 'scalacheck -> "1.12.5", 'scalaTest -> "2.2.6", 'slf4j -> "1.7.21" @@ -128,4 +128,4 @@ object EvaluatorBuild extends AutoPlugin { Some("Releases" at nexus + "service/local/staging/deploy/maven2") } ) -} \ No newline at end of file +} From 33ff10d005bd64c2b438a54bf9db84e772da12ce Mon Sep 17 00:00:00 2001 From: Juan Pedro Moreno Date: Thu, 6 Oct 2016 23:20:31 +0200 Subject: [PATCH 3/5] Provides a custom JSON BodyPart for Circe --- .../evaluator/http/HttpClient.scala | 1 + .../evaluator/http/HttpRequestBuilder.scala | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/client/shared/src/main/scala/org/scalaexercises/evaluator/http/HttpClient.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/http/HttpClient.scala index 8401b5ba..aa9e0da5 100644 --- a/client/shared/src/main/scala/org/scalaexercises/evaluator/http/HttpClient.scala +++ b/client/shared/src/main/scala/org/scalaexercises/evaluator/http/HttpClient.scala @@ -8,6 +8,7 @@ package org.scalaexercises.evaluator.http import io.circe.Decoder import org.scalaexercises.evaluator.EvaluatorResponses import org.scalaexercises.evaluator.EvaluatorResponses.EvaluationResponse + import scala.concurrent.Future object HttpClient { diff --git a/client/shared/src/main/scala/org/scalaexercises/evaluator/http/HttpRequestBuilder.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/http/HttpRequestBuilder.scala index bb18355c..bbbd4689 100644 --- a/client/shared/src/main/scala/org/scalaexercises/evaluator/http/HttpRequestBuilder.scala +++ b/client/shared/src/main/scala/org/scalaexercises/evaluator/http/HttpRequestBuilder.scala @@ -9,9 +9,10 @@ import org.scalaexercises.evaluator.http.HttpClient._ import scala.concurrent.Future -import fr.hmil.roshttp.body.Implicits._ import fr.hmil.roshttp.{HttpRequest, Method, HttpResponse} -import fr.hmil.roshttp.body.JSONBody +import fr.hmil.roshttp.body.BodyPart + +import java.nio.ByteBuffer case class HttpRequestBuilder( url: String, @@ -20,6 +21,12 @@ case class HttpRequestBuilder( body: String = "" ) { + case class CirceJSONBody(value: String) extends BodyPart { + override def contentType: String = s"application/json; charset=utf-8" + + override def content: ByteBuffer = ByteBuffer.wrap(value.getBytes("utf-8")) + } + def withHeaders(headers: Headers) = copy(headers = headers) def withBody(body: String) = copy(body = body) @@ -28,9 +35,9 @@ case class HttpRequestBuilder( val request = HttpRequest(url) .withMethod(Method(httpVerb)) + .withHeader("content-type", "application/json") .withHeaders(headers.toList: _*) - .withHeader("content.type", "application/json") - request.post(JSONBody(body)) + request.send(CirceJSONBody(body)) } } From 4e658a9d2203bb5ea443adb0beb6a0b3df52eea5 Mon Sep 17 00:00:00 2001 From: Juan Pedro Moreno Date: Fri, 7 Oct 2016 11:46:01 +0200 Subject: [PATCH 4/5] Removes unnecessary future instances --- .../main/scala/org/scalaexercises/evaluator/implicits.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/shared/src/main/scala/org/scalaexercises/evaluator/implicits.scala b/client/shared/src/main/scala/org/scalaexercises/evaluator/implicits.scala index ba158078..c1fdd0f6 100644 --- a/client/shared/src/main/scala/org/scalaexercises/evaluator/implicits.scala +++ b/client/shared/src/main/scala/org/scalaexercises/evaluator/implicits.scala @@ -5,7 +5,6 @@ package org.scalaexercises.evaluator -import cats.std.FutureInstances import org.scalaexercises.evaluator.free.interpreters.Interpreter -object implicits extends Interpreter with FutureInstances +object implicits extends Interpreter From 758b7b364d134fcba28cb1d42998991686053801 Mon Sep 17 00:00:00 2001 From: Juan Pedro Moreno Date: Fri, 7 Oct 2016 12:08:21 +0200 Subject: [PATCH 5/5] It also adds dependencies in the jsSettings --- build.sbt | 17 +++++++++++------ project/EvaluatorBuild.scala | 34 +++++++++++++++------------------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/build.sbt b/build.sbt index 5d493e4e..1c4680ee 100644 --- a/build.sbt +++ b/build.sbt @@ -20,7 +20,14 @@ lazy val `evaluator-shared-js` = `evaluator-shared`.js lazy val scalaJSSettings = Seq( requiresDOM := false, scalaJSUseRhino := false, - jsEnv := NodeJSEnv().value + jsEnv := NodeJSEnv().value, + libraryDependencies ++= Seq( + "fr.hmil" %%% "roshttp" % v('roshttp), + "org.typelevel" %%% "cats-free" % v('cats), + "io.circe" %%% "circe-core" % v('circe), + "io.circe" %%% "circe-generic" % v('circe), + "io.circe" %%% "circe-parser" % v('circe) + ) ) lazy val `evaluator-client` = (crossProject in file("client")) @@ -28,7 +35,8 @@ lazy val `evaluator-client` = (crossProject in file("client")) .enablePlugins(AutomateHeaderPlugin) .settings( name := "evaluator-client", - libraryDependencies <++= libraryVersions { v => Seq( + libraryDependencies ++= Seq( + "fr.hmil" %% "roshttp" % v('roshttp), "org.typelevel" %% "cats-free" % v('cats), "io.circe" %% "circe-core" % v('circe), "io.circe" %% "circe-generic" % v('circe), @@ -38,8 +46,6 @@ lazy val `evaluator-client` = (crossProject in file("client")) // Testing libraries "org.scalatest" %% "scalatest" % v('scalaTest) % "test" ) - }, - libraryDependencies += "fr.hmil" %%% "roshttp" % "1.1.0" ) .jsSettings(scalaJSSettings: _*) @@ -53,7 +59,7 @@ lazy val `evaluator-server` = (project in file("server")) .settings(noPublishSettings: _*) .settings( name := "evaluator-server", - libraryDependencies <++= libraryVersions { v => Seq( + libraryDependencies ++= Seq( "io.monix" %% "monix" % v('monix), "org.http4s" %% "http4s-dsl" % v('http4s), "org.http4s" %% "http4s-blaze-server" % v('http4s), @@ -70,7 +76,6 @@ lazy val `evaluator-server` = (project in file("server")) "io.get-coursier" %% "coursier-cache" % v('coursier), "org.scalatest" %% "scalatest" % v('scalaTest) % "test" ) - } ) .settings(compilerDependencySettings: _*) diff --git a/project/EvaluatorBuild.scala b/project/EvaluatorBuild.scala index 544df61d..bcd65353 100644 --- a/project/EvaluatorBuild.scala +++ b/project/EvaluatorBuild.scala @@ -14,7 +14,21 @@ object EvaluatorBuild extends AutoPlugin { object autoImport { - val libraryVersions = settingKey[Map[Symbol, String]]("Common versions to be used for dependencies") + val v = Map( + 'cats -> "0.6.1", + 'circe -> "0.5.0-M2", + 'config -> "1.3.0", + 'coursier -> "1.0.0-M12", + 'http4s -> "0.14.1", + 'jwtcore -> "0.8.0", + 'log4s -> "1.3.0", + 'monix -> "2.0-RC8", + 'roshttp -> "1.1.0", + 'scalacheck -> "1.12.5", + 'scalaTest -> "2.2.6", + 'slf4j -> "1.7.21" + ) + def compilerDependencySettings = Seq( libraryDependencies ++= Seq( @@ -31,7 +45,6 @@ object EvaluatorBuild extends AutoPlugin { override def projectSettings = baseSettings ++ reformatOnCompileSettings ++ - dependencySettings ++ publishSettings ++ miscSettings @@ -55,23 +68,6 @@ object EvaluatorBuild extends AutoPlugin { javacOptions ++= Seq("-encoding", "UTF-8", "-Xlint:-options") ) - private[this] def dependencySettings = Seq( - libraryVersions := Map( - 'cats -> "0.6.1", - 'circe -> "0.5.0-M2", - 'config -> "1.3.0", - 'coursier -> "1.0.0-M12", - 'http4s -> "0.14.1", - 'jwtcore -> "0.8.0", - 'log4s -> "1.3.0", - 'monix -> "2.0-RC8", - 'roshttp -> "1.1.0", - 'scalacheck -> "1.12.5", - 'scalaTest -> "2.2.6", - 'slf4j -> "1.7.21" - ) - ) - private[this] def miscSettings = Seq( headers <<= (name, version) { (name, version) => Map( "scala" -> (