diff --git a/shared/src/main/scala/mouse/anyf.scala b/shared/src/main/scala/mouse/anyf.scala index e9056bf..2303e6c 100644 --- a/shared/src/main/scala/mouse/anyf.scala +++ b/shared/src/main/scala/mouse/anyf.scala @@ -23,8 +23,7 @@ package mouse import cats.data.EitherT import cats.data.OptionT -import cats.~> -import cats.Functor +import cats.{ApplicativeError, Functor, MonadError, ~>} trait AnyFSyntax { implicit final def anyfSyntaxMouse[F[_], A](fa: F[A]): AnyFOps[F, A] = new AnyFOps(fa) @@ -49,4 +48,13 @@ final class AnyFOps[F[_], A](private val fa: F[A]) extends AnyVal { def liftOptionT(implicit F: Functor[F]): OptionT[F, A] = OptionT.liftF(fa) -} + // applicativeError + def recoverAsLeft[E, L](pf: PartialFunction[E, L])(implicit F: ApplicativeError[F, E]): F[Either[L, A]] = + recoverEither(pf.andThen(Left(_))) + + def recoverAsRight[E](pf: PartialFunction[E, A])(implicit F: ApplicativeError[F, E]): F[Either[Nothing, A]] = + recoverEither(pf.andThen(Right(_))) + + def recoverEither[E, L](pf: PartialFunction[E, Either[L, A]])(implicit F: ApplicativeError[F, E]): F[Either[L, A]] = + F.recover(mapAsRight[L])(pf) +} \ No newline at end of file diff --git a/shared/src/test/scala/mouse/AnyFSyntaxTest.scala b/shared/src/test/scala/mouse/AnyFSyntaxTest.scala index 5e87147..d8a3d25 100644 --- a/shared/src/test/scala/mouse/AnyFSyntaxTest.scala +++ b/shared/src/test/scala/mouse/AnyFSyntaxTest.scala @@ -23,9 +23,11 @@ package mouse import cats.data.EitherT import cats.data.OptionT -import cats.syntax.option._ -import cats.syntax.either._ -import cats.{~>, Id} +import cats.syntax.option.* +import cats.syntax.either.* +import cats.{Id, ~>} + +import scala.util.{Success, Try} class AnyFSyntaxTest extends MouseSuite { private val emptyK = new (List ~> List) { @@ -75,6 +77,55 @@ class AnyFSyntaxTest extends MouseSuite { assertEquals(List(1).mapAsSome, List(1.some)) } + test("AnyFSyntax.recoverEither") { + assertEquals( + Try[Int](1).recoverEither { + case _: Throwable => Right(2) + }, + Success(1.asRight) + ) + + assertEquals( + Try[Int](throw new RuntimeException("boom")).recoverEither { + case _: Throwable => Right(2) + }, + Success(2.asRight) + ) + } + + + test("AnyFSyntax.recoverAsRight") { + assertEquals( + Try[Int](1).recoverAsRight { + case _: Throwable => 2 + }, + Success(1.asRight) + ) + + assertEquals( + Try[Int](throw new RuntimeException("boom")).recoverAsRight { + case _: Throwable => 2 + }, + Success(2.asRight) + ) + } + + test("AnyFSyntax.recoverAsLeft") { + assertEquals( + Try(1).recoverAsLeft { + case _: Throwable => "foo" + }, + Success(1.asRight) + ) + + assertEquals( + Try(throw new RuntimeException("boom")).recoverAsLeft { + case _: Throwable => "error" + }, + Success("error".asLeft) + ) + } + test("AnyFSyntax.liftEitherT") { assertEquals(List(1).liftEitherT[String], EitherT(List(1.asRight[String]))) }