Skip to content

Commit

Permalink
Merge pull request #507 from non/topic/js-jvm-projs
Browse files Browse the repository at this point in the history
Introduce cats-jvm and cats-js.
  • Loading branch information
non committed Sep 14, 2015
2 parents 7be80e5 + f04cfbc commit 5c2f182
Show file tree
Hide file tree
Showing 105 changed files with 228 additions and 250 deletions.
54 changes: 38 additions & 16 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -92,26 +92,29 @@ lazy val catsJVM = project.in(file(".catsJVM"))
.settings(moduleName := "cats")
.settings(catsSettings)
.settings(commonJvmSettings)
.aggregate(macrosJVM, coreJVM, lawsJVM, freeJVM, stateJVM, testsJVM, docs, bench)
.dependsOn(macrosJVM, coreJVM, lawsJVM, freeJVM, stateJVM, testsJVM % "test-internal -> test", bench% "compile-internal;test-internal -> test")
.aggregate(macrosJVM, coreJVM, lawsJVM, freeJVM, stateJVM, testsJVM, jvm, docs, bench)
.dependsOn(macrosJVM, coreJVM, lawsJVM, freeJVM, stateJVM, testsJVM % "test-internal -> test", jvm, bench % "compile-internal;test-internal -> test")

lazy val catsJS = project.in(file(".catsJS"))
.settings(moduleName := "cats")
.settings(catsSettings)
.settings(commonJsSettings)
.aggregate(macrosJS, coreJS, lawsJS, freeJS, stateJS, testsJS)
.dependsOn(macrosJS, coreJS, lawsJS, freeJS, stateJS, testsJS % "test-internal -> test")
.aggregate(macrosJS, coreJS, lawsJS, freeJS, stateJS, testsJS, js)
.dependsOn(macrosJS, coreJS, lawsJS, freeJS, stateJS, testsJS % "test-internal -> test", js)
.enablePlugins(ScalaJSPlugin)


lazy val macros = crossProject.crossType(CrossType.Pure)
.settings(moduleName := "cats-macros")
.settings(catsSettings:_*)
.jsSettings(commonJsSettings:_*)
.jvmSettings(commonJvmSettings:_*)
.settings(scalacOptions := scalacOptions.value.filter(_ != "-Xfatal-warnings"))

lazy val macrosJVM = macros.jvm
lazy val macrosJVM = macros.jvm
lazy val macrosJS = macros.js


lazy val core = crossProject.crossType(CrossType.Pure)
.dependsOn(macros)
.settings(moduleName := "cats-core")
Expand All @@ -125,25 +128,20 @@ lazy val core = crossProject.crossType(CrossType.Pure)
lazy val coreJVM = core.jvm
lazy val coreJS = core.js

lazy val laws = crossProject
lazy val laws = crossProject.crossType(CrossType.Pure)
.dependsOn(macros, core)
.settings(moduleName := "cats-laws")
.settings(catsSettings:_*)
.settings(disciplineDependencies:_*)
.settings(libraryDependencies += "org.spire-math" %%% "algebra-laws" % "0.3.1")
.settings(libraryDependencies ++= Seq(
"org.spire-math" %%% "algebra-laws" % "0.3.1",
"com.github.inthenow" %%% "bricks-platform" % "0.0.1"))
.jsSettings(commonJsSettings:_*)
.jvmSettings(commonJvmSettings:_*)

lazy val lawsJVM = laws.jvm
lazy val lawsJS = laws.js

lazy val bench = project.dependsOn(macrosJVM, coreJVM, freeJVM, lawsJVM)
.settings(moduleName := "cats-bench")
.settings(catsSettings)
.settings(noPublishSettings)
.settings(jmhSettings)
.settings(commonJvmSettings)

lazy val free = crossProject.crossType(CrossType.Pure)
.dependsOn(macros, core, tests % "test-internal -> test")
.settings(moduleName := "cats-free")
Expand All @@ -164,19 +162,43 @@ lazy val state = crossProject.crossType(CrossType.Pure)
lazy val stateJVM = state.jvm
lazy val stateJS = state.js

lazy val tests = crossProject
lazy val tests = crossProject.crossType(CrossType.Pure)
.dependsOn(macros, core, laws)
.settings(moduleName := "cats-tests")
.settings(catsSettings:_*)
.settings(disciplineDependencies:_*)
.settings(noPublishSettings:_*)
.settings(libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.0-M7" % "test")
.settings(libraryDependencies ++= Seq(
"org.scalatest" %%% "scalatest" % "3.0.0-M7" % "test",
"com.github.inthenow" %%% "bricks-platform" % "0.0.1" % "test"))
.jsSettings(commonJsSettings:_*)
.jvmSettings(commonJvmSettings:_*)

lazy val testsJVM = tests.jvm
lazy val testsJS = tests.js

// cats-jvm is JVM-only
lazy val jvm = project
.dependsOn(macrosJVM, coreJVM, testsJVM % "test-internal -> test")
.settings(moduleName := "cats-jvm")
.settings(catsSettings:_*)
.settings(commonJvmSettings:_*)

// bench is currently JVM-only
lazy val bench = project.dependsOn(macrosJVM, coreJVM, freeJVM, lawsJVM)
.settings(moduleName := "cats-bench")
.settings(catsSettings)
.settings(noPublishSettings)
.settings(jmhSettings)
.settings(commonJvmSettings)

// cats-js is JS-only
lazy val js = project
.dependsOn(macrosJS, coreJS, testsJS % "test-internal -> test")
.settings(moduleName := "cats-js")
.settings(catsSettings:_*)
.settings(commonJsSettings:_*)

lazy val publishSettings = Seq(
homepage := Some(url("https://github.com/non/cats")),
licenses := Seq("MIT" -> url("http://opensource.org/licenses/MIT")),
Expand Down
55 changes: 27 additions & 28 deletions core/src/main/scala/cats/std/future.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package cats
package std

import cats.syntax.eq._
import cats.syntax.all._

import scala.concurrent.{Await, ExecutionContext, Future}
import scala.concurrent.{ExecutionContext, Future}
import scala.concurrent.duration.FiniteDuration

trait FutureInstances extends FutureInstances1 {
Expand All @@ -23,39 +23,38 @@ trait FutureInstances extends FutureInstances1 {
override def map[A, B](fa: Future[A])(f: A => B): Future[B] = fa.map(f)
}

implicit def futureSemigroup[A](implicit A: Semigroup[A], ec: ExecutionContext): Semigroup[Future[A]] =
new FutureSemigroup[A]()

def futureEq[A](atMost: FiniteDuration)(implicit A: Eq[A], ec: ExecutionContext): Eq[Future[A]] =
new Eq[Future[A]] {
def eqv(fx: Future[A], fy: Future[A]): Boolean =
Await.result((fx zip fy).map { case (x, y) => x === y }, atMost)
}
implicit def futureGroup[A: Group](implicit ec: ExecutionContext): Group[Future[A]] =
new FutureGroup[A]
}

trait FutureInstances1 {

def futureComonad(atMost: FiniteDuration)(implicit ec: ExecutionContext): Comonad[Future] =
new FutureCoflatMap with Comonad[Future] {

def extract[A](x: Future[A]): A = Await.result(x, atMost)

def map[A, B](fa: Future[A])(f: A => B): Future[B] = fa.map(f)
}

implicit def futureMonoid[A](implicit A: Monoid[A], ec: ExecutionContext): Monoid[Future[A]] =
new FutureSemigroup[A] with Monoid[Future[A]] {

def empty: Future[A] = Future.successful(A.empty)
}
trait FutureInstances1 extends FutureInstances2 {
implicit def futureMonoid[A: Monoid](implicit ec: ExecutionContext): Monoid[Future[A]] =
new FutureMonoid[A]
}

private[std] abstract class FutureCoflatMap(implicit ec: ExecutionContext) extends CoflatMap[Future] {
trait FutureInstances2 {
implicit def futureSemigroup[A: Semigroup](implicit ec: ExecutionContext): Semigroup[Future[A]] =
new FutureSemigroup[A]
}

private[cats] abstract class FutureCoflatMap(implicit ec: ExecutionContext) extends CoflatMap[Future] {
def map[A, B](fa: Future[A])(f: A => B): Future[B] = fa.map(f)
def coflatMap[A, B](fa: Future[A])(f: Future[A] => B): Future[B] = Future(f(fa))
}

private[std] class FutureSemigroup[A](implicit A: Semigroup[A], ec: ExecutionContext) extends Semigroup[Future[A]] {
private[cats] class FutureSemigroup[A: Semigroup](implicit ec: ExecutionContext) extends Semigroup[Future[A]] {
def combine(fx: Future[A], fy: Future[A]): Future[A] =
(fx zip fy).map { case (x, y) => x |+| y }
}

private[cats] class FutureMonoid[A](implicit A: Monoid[A], ec: ExecutionContext) extends FutureSemigroup[A] with Monoid[Future[A]] {
def empty: Future[A] =
Future.successful(A.empty)
}

def combine(fx: Future[A], fy: Future[A]): Future[A] = (fx zip fy).map((A.combine _).tupled)
private[cats] class FutureGroup[A](implicit A: Group[A], ec: ExecutionContext) extends FutureMonoid[A] with Group[Future[A]] {
def inverse(fx: Future[A]): Future[A] =
fx.map(_.inverse)
override def remove(fx: Future[A], fy: Future[A]): Future[A] =
(fx zip fy).map { case (x, y) => x |-| y }
}
1 change: 1 addition & 0 deletions core/src/main/scala/cats/syntax/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ package object syntax {
object flatMap extends FlatMapSyntax
object foldable extends FoldableSyntax
object functor extends FunctorSyntax
object group extends GroupSyntax
object invariant extends InvariantSyntax
object monadCombine extends MonadCombineSyntax
object monadFilter extends MonadFilterSyntax
Expand Down
43 changes: 43 additions & 0 deletions jvm/src/main/scala/cats/jvm/std/future.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package cats
package jvm
package std

import scala.concurrent.{Await, Future}
import scala.concurrent.{ExecutionContext => E}
import scala.concurrent.duration.FiniteDuration

import cats.std.FutureCoflatMap
import cats.syntax.all._

object future extends FutureInstances0

trait FutureInstances0 extends FutureInstances1 {
def futureComonad(atMost: FiniteDuration)(implicit ec: E): Comonad[Future] =
new FutureCoflatMap with Comonad[Future] {
def extract[A](x: Future[A]): A =
Await.result(x, atMost)
}

def futureOrder[A: Order](atMost: FiniteDuration)(implicit ec: E): Eq[Future[A]] =
new Order[Future[A]] {
def compare(x: Future[A], y: Future[A]): Int =
Await.result((x zip y).map { case (x, y) => x compare y }, atMost)
}
}

trait FutureInstances1 extends FutureInstances2 {
def futurePartialOrder[A: PartialOrder](atMost: FiniteDuration)(implicit ec: E): PartialOrder[Future[A]] =
new PartialOrder[Future[A]] {
def partialCompare(x: Future[A], y: Future[A]): Double =
Await.result((x zip y).map { case (x, y) => x partialCompare y }, atMost)
}

}

trait FutureInstances2 {
def futureEq[A: Eq](atMost: FiniteDuration)(implicit ec: E): Eq[Future[A]] =
new Eq[Future[A]] {
def eqv(x: Future[A], y: Future[A]): Boolean =
Await.result((x zip y).map { case (x, y) => x === y }, atMost)
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package cats
package jvm
package tests

import cats.data.Xor
import cats.laws.discipline._
import cats.jvm.std.future.{futureEq, futureComonad}
import cats.tests.CatsSuite

import scala.concurrent.{Await, ExecutionContext, Future}
import scala.concurrent.duration._
Expand Down
15 changes: 0 additions & 15 deletions laws/js/src/main/scala/cats/laws/Platform.scala

This file was deleted.

35 changes: 0 additions & 35 deletions laws/jvm/src/main/scala/cats/laws/Platform.scala

This file was deleted.

11 changes: 0 additions & 11 deletions laws/shared/src/main/scala/cats/laws/SerializableLaws.scala

This file was deleted.

File renamed without changes.
52 changes: 52 additions & 0 deletions laws/src/main/scala/cats/laws/SerializableLaws.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package cats
package laws

import org.scalacheck.Prop
import org.scalacheck.Prop.{ False, Proof, Result }

import bricks.Platform

/**
* Check for Java Serializability.
*
* This laws is only applicative on the JVM, but is something we want
* to be sure to enforce. Therefore, we use bricks.Platform to do a
* runtime check rather than create a separate jvm-laws project.
*/
object SerializableLaws {

// This part is a bit tricky. Basically, we only want to test
// serializability on the JVM.
//
// The Platform.isJs macro will give us a literal true or false at
// compile time, so we rely on scalac to prune away the "other"
// branch. Thus, when scala.js look at this method it won't "see"
// the branch which was removed, and will avoid an error trying to
// suport java.io.*.
//
// This ends up being a lot nicer than having to split the entire
// laws project.

def serializable[A](a: A): Prop =
if (Platform.isJs) Prop(_ => Result(status = Proof)) else Prop { _ =>
import java.io.{ ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream }

val baos = new ByteArrayOutputStream()
val oos = new ObjectOutputStream(baos)
var ois: ObjectInputStream = null
try {
oos.writeObject(a)
oos.close()
val bais = new ByteArrayInputStream(baos.toByteArray())
ois = new ObjectInputStream(bais)
val a2 = ois.readObject()
ois.close()
Result(status = Proof)
} catch { case _: Throwable =>
Result(status = False)
} finally {
oos.close()
if (ois != null) ois.close()
}
}
}
File renamed without changes.
2 changes: 1 addition & 1 deletion project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ addSbtPlugin("pl.project13.scala"% "sbt-jmh" % "0.1.10")
addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "0.6.0")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.2.0")
addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "0.8.4")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.4")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.5")
Loading

0 comments on commit 5c2f182

Please sign in to comment.