Skip to content

Commit

Permalink
Add catchOnly to ApplicativeError.
Browse files Browse the repository at this point in the history
  • Loading branch information
takayahilton committed Nov 20, 2019
1 parent 55c48a8 commit 8153a8c
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 3 deletions.
25 changes: 22 additions & 3 deletions core/src/main/scala/cats/ApplicativeError.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package cats

import cats.data.{EitherT, Validated}
import cats.data.Validated.{Invalid, Valid}
import cats.ApplicativeError.CatchOnlyPartiallyApplied
import cats.data.EitherT

import scala.reflect.ClassTag
import scala.util.{Failure, Success, Try}
Expand Down Expand Up @@ -91,7 +93,7 @@ trait ApplicativeError[F[_], E] extends Applicative[F] {
* `F[A]` values.
*/
def recover[A](fa: F[A])(pf: PartialFunction[E, A]): F[A] =
handleErrorWith(fa)(e => (pf.andThen(pure _)).applyOrElse(e, raiseError _))
handleErrorWith(fa)(e => pf.andThen(pure).applyOrElse(e, raiseError))

/**
* Recover from certain errors by mapping them to an `F[A]` value.
Expand Down Expand Up @@ -129,7 +131,7 @@ trait ApplicativeError[F[_], E] extends Applicative[F] {
* having originally been included in the `MonadError` API and syntax.
*/
def adaptError[A](fa: F[A])(pf: PartialFunction[E, E]): F[A] =
recoverWith(fa)(pf.andThen(raiseError[A] _))
recoverWith(fa)(pf.andThen(raiseError[A]))

/**
* Returns a new value that transforms the result of the source,
Expand Down Expand Up @@ -194,7 +196,7 @@ trait ApplicativeError[F[_], E] extends Applicative[F] {
* }}}
*/
def onError[A](fa: F[A])(pf: PartialFunction[E, F[Unit]]): F[A] =
handleErrorWith(fa)(e => (pf.andThen(map2(_, raiseError[A](e))((_, b) => b))).applyOrElse(e, raiseError))
handleErrorWith(fa)(e => pf.andThen(map2(_, raiseError[A](e))((_, b) => b)).applyOrElse(e, raiseError))

/**
* Often E is Throwable. Here we try to call pure or catch
Expand All @@ -216,6 +218,12 @@ trait ApplicativeError[F[_], E] extends Applicative[F] {
case NonFatal(e) => raiseError(e)
}

/**
* Evaluates the specified block, catching exceptions of the specified type. Uncaught exceptions are propagated.
*/
def catchOnly[T >: Null <: Throwable]: CatchOnlyPartiallyApplied[T, F, E] =
new CatchOnlyPartiallyApplied[T, F, E](this)

/**
* If the error type is Throwable, we can convert from a scala.util.Try
*/
Expand Down Expand Up @@ -301,6 +309,17 @@ object ApplicativeError {
}
}

final private[cats] class CatchOnlyPartiallyApplied[T, F[_], E](private val F: ApplicativeError[F, E])
extends AnyVal {
def apply[A](f: => A)(implicit CT: ClassTag[T], NT: NotNull[T], ev: Throwable <:< E): F[A] =
try {
F.pure(f)
} catch {
case t if CT.runtimeClass.isInstance(t) =>
F.raiseError(t)
}
}

/**
* lift from scala.Option[A] to a F[A]
*
Expand Down
4 changes: 4 additions & 0 deletions core/src/main/scala/cats/instances/try.scala
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ trait TryInstances extends TryInstances1 {
}

override def isEmpty[A](fa: Try[A]): Boolean = fa.isFailure

override def catchNonFatal[A](a: => A)(implicit ev: Throwable <:< Throwable): Try[A] = Try(a)

override def catchNonFatalEval[A](a: Eval[A])(implicit ev: Throwable <:< Throwable): Try[A] = Try(a.value)
}
// scalastyle:on method.length

Expand Down
11 changes: 11 additions & 0 deletions tests/src/test/scala/cats/tests/TrySuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ class TrySuite extends CatsSuite {
res should not be (null)
}
}

test("catchOnly works") {
forAll { e: Either[String, Int] =>
val str = e.fold(identity, _.toString)
val res = MonadError[Try, Throwable].catchOnly[NumberFormatException](str.toInt)
// the above should just never cause an uncaught exception
// this is a somewhat bogus test:
res should not be (null)
}
}

test("fromTry works") {
forAll { t: Try[Int] =>
(MonadError[Try, Throwable].fromTry(t)) should ===(t)
Expand Down

0 comments on commit 8153a8c

Please sign in to comment.