Skip to content

Commit

Permalink
Add cats.io and IO monad
Browse files Browse the repository at this point in the history
  • Loading branch information
adelbertc committed Mar 2, 2016
1 parent c292e7f commit 2548b55
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 9 deletions.
27 changes: 19 additions & 8 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -95,22 +95,22 @@ lazy val cats = project.in(file("."))
.settings(moduleName := "root")
.settings(catsSettings)
.settings(noPublishSettings)
.aggregate(catsJVM, catsJS)
.dependsOn(catsJVM, catsJS, testsJVM % "test-internal -> test", bench % "compile-internal;test-internal -> test")
.aggregate(catsJVM, catsJS, ioJVM, ioJS)
.dependsOn(catsJVM, catsJS, ioJVM, ioJS, testsJVM % "test-internal -> test", bench % "compile-internal;test-internal -> test")

lazy val catsJVM = project.in(file(".catsJVM"))
.settings(moduleName := "cats")
.settings(catsSettings)
.settings(commonJvmSettings)
.aggregate(macrosJVM, coreJVM, lawsJVM, testsJVM, jvm, docs, bench)
.dependsOn(macrosJVM, coreJVM, lawsJVM, testsJVM % "test-internal -> test", jvm, bench % "compile-internal;test-internal -> test")
.aggregate(macrosJVM, coreJVM, ioJVM, lawsJVM, testsJVM, jvm, docs, bench)
.dependsOn(macrosJVM, coreJVM, ioJVM, lawsJVM, 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, testsJS, js)
.dependsOn(macrosJS, coreJS, lawsJS, testsJS % "test-internal -> test", js)
.aggregate(macrosJS, coreJS, ioJS, lawsJS, testsJS, js)
.dependsOn(macrosJS, coreJS, ioJS, lawsJS, testsJS % "test-internal -> test", js)
.enablePlugins(ScalaJSPlugin)


Expand Down Expand Up @@ -139,6 +139,17 @@ lazy val core = crossProject.crossType(CrossType.Pure)
lazy val coreJVM = core.jvm
lazy val coreJS = core.js

lazy val io = crossProject.crossType(CrossType.Pure)
.dependsOn(core, tests % "test-internal -> test")
.settings(moduleName := "cats-io")
.settings(catsSettings: _*)
.jsSettings(commonJsSettings: _*)
.jsSettings()
.jvmSettings(commonJvmSettings: _*)

lazy val ioJVM = io.jvm
lazy val ioJS = io.js

lazy val laws = crossProject.crossType(CrossType.Pure)
.dependsOn(macros, core)
.settings(moduleName := "cats-laws")
Expand Down Expand Up @@ -259,11 +270,11 @@ lazy val publishSettings = Seq(
) ++ credentialSettings ++ sharedPublishSettings ++ sharedReleaseProcess

// These aliases serialise the build for the benefit of Travis-CI.
addCommandAlias("buildJVM", ";macrosJVM/compile;coreJVM/compile;coreJVM/test;lawsJVM/compile;testsJVM/test;jvm/test;bench/test")
addCommandAlias("buildJVM", ";macrosJVM/compile;coreJVM/compile;coreJVM/test;ioJVM/compile;lawsJVM/compile;testsJVM/test;ioJVM/test;jvm/test;bench/test")

addCommandAlias("validateJVM", ";scalastyle;buildJVM;makeSite")

addCommandAlias("validateJS", ";macrosJS/compile;coreJS/compile;lawsJS/compile;testsJS/test;js/test")
addCommandAlias("validateJS", ";macrosJS/compile;coreJS/compile;ioJS/compile;ioJS/test;lawsJS/compile;testsJS/test;js/test")

addCommandAlias("validate", ";validateJS;validateJVM")

Expand Down
43 changes: 43 additions & 0 deletions io/src/main/scala/cats/io/IO.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package cats
package io

import cats.data.Xor

import java.lang.Throwable

import scala.reflect.ClassTag

final class IO[A] private[io] (private val eval: Eval[A]) extends Serializable {
def unsafePerformIO(): A = eval.value

def catchOnly[T >: Null <: Throwable: ClassTag]: IO[T Xor A] =
new IO(Eval.always(Xor.catchOnly[T](eval.value)))

def catchNonFatal: IO[Throwable Xor A] =
new IO(Eval.always(Xor.catchNonFatal(eval.value)))

def map[B](f: A => B): IO[B] =
new IO(eval.map(f))

def flatMap[B](f: A => IO[B]): IO[B] =
new IO(eval.flatMap(a => f(a).eval))
}

object IO extends IOInstances {
/** Capture a side-effecting expression as a new IO primitive. */
def always[A](a: => A): IO[A] =
new IO[A](Eval.always(a))

def pure[A](a: A): IO[A] =
new IO[A](Eval.now(a))
}

trait IOInstances {
implicit val ioInstances: Monad[IO] =
new Monad[IO] {
def pure[A](a: A): IO[A] = IO.pure(a)
override def pureEval[A](a: Eval[A]): IO[A] = new IO(a)
def flatMap[A, B](ma: IO[A])(f: A => IO[B]): IO[B] = ma.flatMap(f)
override def map[A, B](ma: IO[A])(f: A => B): IO[B] = ma.map(f)
}
}
15 changes: 15 additions & 0 deletions io/src/test/scala/cats/io/IOSuite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package cats
package io

import cats.laws.discipline.arbitrary._

import org.scalacheck.Arbitrary
import org.scalacheck.Arbitrary.arbitrary

trait IOSuite {
implicit def ioArbitrary[A: Arbitrary]: Arbitrary[IO[A]] =
Arbitrary(arbitrary[Eval[A]].map(ea => new IO(ea)))

implicit def ioEq[A: Eq]: Eq[IO[A]] =
Eq.by(_.unsafePerformIO())
}
11 changes: 11 additions & 0 deletions io/src/test/scala/cats/io/IOTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package cats
package io

import cats.laws.discipline.{MonadTests, SerializableTests}
import cats.tests.CatsSuite
import cats.laws.discipline.eq.tuple3Eq

class IOTests extends CatsSuite with IOSuite {
checkAll("IO", MonadTests[IO].monad[Int, String, Double])
checkAll("Monad[IO]", SerializableTests.serializable(Monad[IO]))
}
2 changes: 1 addition & 1 deletion scripts/travis-publish.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fi
sbt_cmd="sbt ++$TRAVIS_SCALA_VERSION"

coverage="$sbt_cmd coverage validateJVM coverageReport && bash <(curl -s https://codecov.io/bash)"
scala_js="$sbt_cmd macrosJS/compile coreJS/compile lawsJS/compile && $sbt_cmd testsJS/test && $sbt_cmd js/test"
scala_js="$sbt_cmd macrosJS/compile coreJS/compile ioJS/compile lawsJS/compile && $sbt_cmd testsJS/test && $sbt_cmd js/test && $sbt_cmd ioJS/test"
scala_jvm="$sbt_cmd validateJVM"

run_cmd="$coverage && $scala_js && $scala_jvm $publish_cmd"
Expand Down

0 comments on commit 2548b55

Please sign in to comment.