diff --git a/changelogs/0.36.0.md b/changelogs/0.36.0.md new file mode 100644 index 00000000..9284697b --- /dev/null +++ b/changelogs/0.36.0.md @@ -0,0 +1,540 @@ +## [0.36.0](https://github.com/Kevin-Lee/extras/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aclosed+-label%3Ainvalid+milestone%3Amilestone37) - 2023-03-12 + +## New Feature + +### `extras-cats` +* Add `innerMap` extension method to `F[Option[A]]` (#348) + ```scala + val foa: F[Option[A]] = ... + foa.innerMap(A => B) // F[Option[B]] + ``` + ```scala + val foa: IO[Option[Int]] = IO.pure(1) + // IO[Option[Int]] = IO(Some(1)) + foa.innerMap(_ + 999) + // IO[Option[Int]] = IO(Some(1000)) + ``` + +*** + +* Add `innerFlatMap` extension method to `F[Option[A]]` (#349) + ```scala + val foa: F[Option[A]] = ... + foa.innerFlatMap(A => Option[B]) // F[Option[B]] + ``` + ```scala + val foa: IO[Option[Int]] = IO.pure(1) + // IO[Option[Int]] = IO(Some(1)) + foa.innerFlatMap((_ + 999).some) + // IO[Option[Int]] = IO(Some(1000)) + ``` + +*** + +* Add `innerFlatMapF` extension method to `F[Option[A]]` (#352) + ```scala + val foa: F[Option[A]] = ... + foa.innerFlatMapF(A => F[Option[B]]) // F[Option[B]] + ``` + ```scala + val foa: IO[Option[Int]] = IO.pure(1) + // IO[Option[Int]] = IO(Some(1)) + foa.innerFlatMapF(a => IO.pure((a + 999).some)) + // IO[Option[Int]] = IO(Some(1000)) + ``` + +*** + +* `innerGetOrElse`, `innerGetOrElseF`, `innerFold` and `innerFoldF` to extension methods to `F[Option[A]]` (#354) + * `innerGetOrElse` + ```scala + val foa: F[Option[A]] = ... + foa.innerGetOrElse[B >: A](=> B) // F[Option[B]] + ``` + ```scala + val foa: IO[Option[Int]] = IO.pure(999) + // IO[Option[Int]] = IO(Some(999)) + foa.innerGetOrElse(0) + // IO[Option[Int]] = IO(Some(1000)) + + val foa2: IO[Option[Int]] = IO.pure(Option.empty[Int]) + // IO[Option[Int]] = None + foa2.innerGetOrElse(0) + // IO[Option[Int]] = IO(Some(0)) + ``` + + * `innerGetOrElseF` + ```scala + val foa: F[Option[A]] = ... + foa.innerGetOrElseF[B >: A](=> F[B]) // F[Option[B]] + ``` + ```scala + val foa: IO[Option[Int]] = IO.pure(999) + // IO[Option[Int]] = IO(Some(999)) + foa.innerGetOrElseF(IO.pure(0)) + // IO[Option[Int]] = IO(Some(1000)) + + val foa2: IO[Option[Int]] = IO.pure(Option.empty[Int]) + // IO[Option[Int]] = None + foa2.innerGetOrElseF(IO.pure(0)) + // IO[Option[Int]] = IO(Some(0)) + ``` + + * `innerFold` + ```scala + val foa: F[Option[A]] = ... + foa.innerFold[B](=> B)(A => B) // F[Option[B]] + ``` + ```scala + val foa: IO[Option[Int]] = IO.pure(1) + // IO[Option[Int]] = IO(Some(1)) + foa.innerFold(0)(_ + 999) + // IO[Option[Int]] = IO(Some(1000)) + + val foa2: IO[Option[Int]] = IO.pure(Option.empty[Int]) + // IO[Option[Int]] = None + foa2.innerFold(0)(_ + 999) + // IO[Option[Int]] = IO(Some(0)) + ``` + + * `innerFoldF` + ```scala + val foa: F[Option[A]] = ... + foa.innerFoldF[B >: A](=> F[B]) // F[Option[B]] + ``` + ```scala + val foa: IO[Option[Int]] = IO.pure(1) + // IO[Option[Int]] = IO(Some(1)) + foa.innerFoldF(IO.pure(0))(a => IO.pure(a + 999)) + // IO[Option[Int]] = IO(Some(1000)) + + val foa2: IO[Option[Int]] = IO.pure(Option.empty[Int]) + // IO[Option[Int]] = None + foa2.innerFoldF(IO.pure(0))(a => IO.pure(a + 999)) + // IO[Option[Int]] = IO(Some(0)) + ``` + +*** + +* Add `innerMap`, `innerFlatMap`, `innerFlatMapF`, `innerGetOrElse`, `innerGetOrElseF`, `innerFold` and `innerFoldF` extension methods to `F[Either[A, B]]` (#356) + * `innerMap` + ```scala + val feab: F[Either[A, B]] = ... + feab.innerMap(B => D) // F[Either[A, D]] + ``` + ```scala + val feab: F[Either[String, Int]] = IO.pure(Right(1)) + // IO[Either[String, Int]] = IO(Right(1)) + feab.innerMap(_ + 999) + // IO[Either[String, Int]] = IO(Right(1000)) + ``` + + * `innerFlatMap` + ```scala + val feab: F[Either[A, B]] = ... + feab.innerFlatMap(B => Either[A, D]) // F[Either[A, D]] + ``` + ```scala + val feab: F[Either[String, Int]] = IO.pure(Right(1)) + // IO[Either[String, Int]] = IO(Right(1)) + feab.innerFlatMap(b => (b + 999).asRight[String]) + // IO[Either[String, Int]] = IO(Right(1000)) + ``` + + * `innerFlatMapF` + ```scala + val feab: F[Either[A, B]] = ... + feab.innerFlatMapF(B => F[Either[A, D]]) // F[Either[A, D]] + ``` + ```scala + val feab: F[Either[String, Int]] = IO.pure(Right(1)) + // IO[Either[String, Int]] = IO(Right(1)) + feab.innerFlatMapF(b => IO.pure((b + 999).asRight[String])) + // IO[Either[String, Int]] = IO(Right(1000)) + ``` + + * `innerGetOrElse` + ```scala + val feab: F[Either[A, B]] = ... + feab.innerGetOrElse[D >: B](=> D) // F[D] + ``` + ```scala + val feab: F[Either[String, Int]] = IO.pure(Right(999)) + // IO[Either[String, Int]] = IO(Right(999)) + feab.innerGetOrElse(0) + // IO[Int] = IO(999) + + val feab2: F[Either[String, Int]] = IO.pure("Error".asLeft[Int]) + // IO[Either[String, Int]] = IO(Left("Error")) + feab2.innerGetOrElse(0) + // IO[Int] = IO(0) + ``` + + * `innerGetOrElseF` + ```scala + val feab: F[Either[A, B]] = ... + feab.innerGetOrElseF[D >: B](=> F[D]) // F[D] + ``` + ```scala + val feab: F[Either[String, Int]] = IO.pure(Right(999)) + // IO[Either[String, Int]] = IO(Right(999)) + feab.innerGetOrElseF(IO.pure(0)) + // IO[Either[String, Int]] = IO(Right(999)) + + val feab2: F[Either[String, Int]] = IO.pure("Error".asLeft[Int]) + // IO[Either[String, Int]] = IO(Left("Error")) + feab2.innerGetOrElseF(IO.pure(0)) + // IO[Int] = IO(0) + ``` + + * `innerFold` + ```scala + val feab: F[Either[A, B]] = ... + feab.innerFold[D](=> D)(B => D) // F[D] + ``` + ```scala + val feab: F[Either[String, Int]] = IO.pure(Right(1)) + // IO[Either[String, Int]] = IO(Right(1)) + feab.innerFold(0)(_ + 999) + // IO[Int] = IO(1000) + + val feab: F[Either[String, Int]] = IO.pure("Error".asLeft) + // IO[Either[String, Int]] = IO(Left("Error")) + feab.innerFold(0)(_ + 999) + // IO[Int] = IO(0) + ``` + + * `innerFoldF` + ```scala + val feab: F[Either[A, B]] = ... + feab.innerFoldF[D](=> F[D])(B => F[D]) // F[D] + ``` + ```scala + val feab: F[Either[String, Int]] = IO.pure(Right(1)) + // IO[Either[String, Int]] = IO(Right(1)) + feab.innerFoldF(IO.pure(0))(b => IO.pure(b + 999)) + // IO[Int] = IO(1000) + + val feab: F[Either[String, Int]] = IO.pure("Error".asLeft) + // IO[Either[String, Int]] = IO(Left("Error")) + feab.innerFoldF(IO.pure(0))(b => IO.pure(b + 999)) + // IO[Int] = IO(0) + ``` + +*** + +* Add `innerLeftMap`, `innerLeftFlatMap` and `innerLeftFlatMapF` extension methods to `F[Either[A, B]]` (#358) + * `innerLeftMap` + ```scala + val feab: F[Either[A, B]] = ... + feab.innerLeftMap(A => C) // F[Either[C, B]] + ``` + ```scala + val feab: F[Either[String, Int]] = IO.pure(Left("Error")) + // IO[Either[String, Int]] = IO(Left("Error")) + feab.innerLeftMap("Failed: " + _) + // IO[Either[String, Int]] = IO(Left("Failed: Error")) + ``` + + * `innerLeftFlatMap` + ```scala + val feab: F[Either[A, B]] = ... + feab.innerFlatMap(A => Either[C, B]) // F[Either[C, B]] + ``` + ```scala + val feab: F[Either[String, Int]] = IO.pure(Left("Error")) + // IO[Either[String, Int]] = IO(Left("Error")) + feab.innerFlatMap(a => ("Failed: " + a).asLeft[Int]) + // IO[Either[String, Int]] = IO(Left("Failed: Error")) + ``` + + * `innerLeftFlatMapF` + ```scala + val feab: F[Either[A, B]] = ... + feab.innerFlatMapF(A => F[Either[C, B]]) // F[Either[C, B]] + ``` + ```scala + val feab: F[Either[String, Int]] = IO.pure(Left("Error")) + // IO[Either[String, Int]] = IO(Left("Error")) + feab.innerFlatMapF(a => IO.pure(("Failed: " + a).asLeft[Int])) + // IO[Either[String, Int]] = IO(Left("Failed: Error")) + ``` + +* Add `innerFilter`, `innerExists`, `innerContains`, `innerForall`, `innerCollect`, `innerOrElse` and `innerOrElseF` extension methods to `F[Option[A]]` (#360) + * `innerFilter` + ```scala + val foa: F[Option[A]] = ... + foa.innerFilter(A => Boolean) // F[Option[A]] + ``` + ```scala + val foa: IO[Option[Int]] = IO.pure(Some(1)) + // IO[Option[Int]] = IO(Some(1)) + foa.innerFilter(_ > 0) + // IO[Option[Int]] = IO(Some(1)) + foa.innerFilter(_ > 1) + // IO[Option[Int]] = IO(None) + ``` + + * `innerExists` + ```scala + val foa: F[Option[A]] = ... + foa.innerExists(A => Boolean) // F[Boolean] + ``` + ```scala + val foa: IO[Option[Int]] = IO.pure(Some(1)) + // IO[Option[Int]] = IO(Some(1)) + foa.innerExists(_ > 0) + // IO[Boolean] = IO(true) + foa.innerExists(_ > 1) + // IO[Boolean] = IO(false) + ``` + + * `innerContains` + ```scala + val foa: F[Option[A]] = ... + foa.innerContains(A) // F[Boolean] + ``` + ```scala + val foa: IO[Option[Int]] = IO.pure(Some(1)) + // IO[Option[Int]] = IO(Some(1)) + foa.innerContains(1) + // IO[Boolean] = IO(true) + foa.innerContains(0) + // IO[Boolean] = IO(false) + ``` + + * `innerForall` + ```scala + val foa: F[Option[A]] = ... + foa.innerForall(A) // F[Boolean] + ``` + ```scala + val foa: IO[Option[Int]] = IO.pure(Some(1)) + // IO[Option[Int]] = IO(Some(1)) + foa.innerForall(_ > 0) + // IO[Boolean] = IO(true) + foa.innerForall(_ > 1) + // IO[Boolean] = IO(false) + + val foa2: IO[Option[Int]] = IO.pure(None) + // IO[Option[Int]] = IO(None) + foa2.innerForall(_ > 1) + // IO[Boolean] = IO(true) + ``` + + * `innerCollect` + ```scala + val foa: F[Option[A]] = ... + foa.innerCollect(PartialFunction[A, B]) // F[Option[B]] + ``` + ```scala + val foa: IO[Option[Int]] = IO.pure(Some(1)) + // IO[Option[Int]] = IO(Some(1)) + foa.innerCollect { + case 1 => 0 + case 2 => 999 + } + // IO[Option[Int]] = IO(0) + + val foa2: IO[Option[Int]] = IO.pure(Some(2)) + // IO[Option[Int]] = IO(2) + foa.innerCollect { + case 1 => 0 + case 2 => 999 + } + // IO[Option[Int]] = IO(999) + + val foa3: IO[Option[Int]] = IO.pure(Some(3)) + // IO[Option[Int]] = IO(3) + foa.innerCollect { + case 1 => 0 + case 2 => 999 + } + // IO[Option[Int]] = IO(None) + ``` + + * `innerOrElse` + ```scala + val foa: F[Option[A]] = ... + foa.innerOrElse[B >: A](Option[B]) // F[Option[B]] + ``` + ```scala + val foa: IO[Option[Int]] = IO.pure(Some(1)) + // IO[Option[Int]] = IO(Some(1)) + foa.innerOrElse(Some(0)) + // IO[Option[Int]] = IO(Some(1)) + + val foa2: IO[Option[Int]] = IO.pure(None) + // IO[Option[Int]] = IO(None) + foa2.innerOrElse(Some(0)) + // IO[Option[Int]] = IO(Some(0)) + ``` + + * `innerOrElseF` + ```scala + val foa: F[Option[A]] = ... + foa.innerOrElse[B >: A](F[Option[B]]) // F[Option[B]] + ``` + ```scala + val foa: IO[Option[Int]] = IO.pure(Some(1)) + // IO[Option[Int]] = IO(Some(1)) + foa.innerOrElse(IO.pure(Some(0))) + // IO[Option[Int]] = IO(Some(1)) + + val foa2: IO[Option[Int]] = IO.pure(None) + // IO[Option[Int]] = IO(None) + foa2.innerOrElse(IO.pure(Some(0))) + // IO[Option[Int]] = IO(Some(0)) + ``` + +* Add `innerFind`, `innerFilterOrElse`, `innerExists`, `innerForall`, `innerContains`, `innerCollectFirst`, `innerOrElse` and `innerOrElseF` extension methods to `F[Either[A, B]]` (#362) + * `innerFind` + ```scala + val feab: F[Either[A, B]] = ... + feab.innerFind(B => Boolean): F[Option[B]] + ``` + ```scala + val feab: IO[Either[String, Int]] = IO(Right(1)) + // IO[Either[String, Int]] = IO(Right(1)) + feab.innerFind(_ > 0) + // IO[Option[Int]] = IO(Some(1)) + feab.innerFind(_ > 1) + // IO[Option[Int]] = IO(None) + ``` + * `innerFilterOrElse` + ```scala + val feab: F[Either[A, B]] = ... + feab.innerFilterOrElse[C >: A](B => Boolean, C): F[Either[C, B]] + ``` + ```scala + val feab: IO[Either[String, Int]] = IO(Right(1)) + // IO[Either[String, Int]] = IO(Right(1)) + feab.innerFilterOrElse(_ > 0, "Error") + // IO[Either[String, Int]] = IO(Right(1)) + feab.innerFilterOrElse(_ > 1, "Error") + // IO[Either[String, Int]] = IO(Left("Error")) + ``` + * `innerExists` + ```scala + val feab: F[Either[A, B]] = ... + feab.innerExists(B => Boolean): F[Boolean] + ``` + ```scala + val feab: IO[Either[String, Int]] = IO(Right(1)) + // IO[Either[String, Int]] = IO(Right(1)) + feab.innerExists(_ > 0) + // IO[Boolean] = IO(true) + feab.innerExists(_ > 1) + // IO[Boolean] = IO(false) + ``` + * `innerForall` + ```scala + val feab: F[Either[A, B]] = ... + feab.innerForall(B => Boolean): F[Boolean] + ``` + ```scala + val feab: IO[Either[String, Int]] = IO(Right(1)) + // IO[Either[String, Int]] = IO(Right(1)) + feab.innerForall(_ > 0) + // IO[Boolean] = IO(true) + feab.innerForall(_ > 1) + // IO[Boolean] = IO(false) + + val feab2: IO[Either[String, Int]] = IO(Left("Error")) + // IO[Either[String, Int]] = IO(Left("Error")) + feab2.innerForall(_ > 1) + // IO[Boolean] = IO(true) + ``` + + * `innerContains` + ```scala + val feab: F[Either[A, B]] = ... + feab.innerContains(B): F[Boolean] + ``` + ```scala + val feab: IO[Either[String, Int]] = IO(Right(1)) + // IO[Either[String, Int]] = IO(Right(1)) + feab.innerContains(1) + // IO[Boolean] = IO(true) + feab.innerContains(0) + // IO[Boolean] = IO(false) + + val feab2: IO[Either[String, Int]] = IO(Left("Error")) + // IO[Either[String, Int]] = IO(Left("Error")) + feab2.innerContains(1) + // IO[Boolean] = IO(false) + ``` + + * `innerCollectFirst` + ```scala + val feab: F[Either[A, B]] = ... + feab.innerCollectFirst[D](PartialFunction[B, D]): F[Option[D]] + ``` + ```scala + val feab: IO[Either[String, Int]] = IO(Right(1)) + // IO[Either[String, Int]] = IO(Right(1)) + feab.innerCollectFirst { + case 1 => 0 + case 2 => 999 + } + // IO[Option[Int]] = IO(Some(0)) + + val feab2: IO[Either[String, Int]] = IO(Right(2)) + // IO[Either[String, Int]] = IO(Right(2)) + feab2.innerCollectFirst { + case 1 => 0 + case 2 => 999 + } + // IO[Option[Int]] = IO(Some(999)) + + val feab3: IO[Either[String, Int]] = IO(Right(3)) + // IO[Either[String, Int]] = IO(Right(3)) + feab3.innerCollectFirst { + case 1 => 0 + case 2 => 999 + } + // IO[Option[Int]] = IO(None) + + val feab4: IO[Either[String, Int]] = IO(Left("Error")) + // IO[Either[String, Int]] = IO(Left("Error")) + feab4.innerCollectFirst { + case 1 => 0 + case 2 => 999 + } + // IO[Option[Int]] = IO(None) + ``` + + * `innerOrElse` + ```scala + val feab: F[Either[A, B]] = ... + feab.innerOrElse[C >: A, D >: B](=> Either[C, D]): F[Either[C, D]] + ``` + ```scala + val feab: IO[Either[String, Int]] = IO(Right(1)) + // IO[Either[String, Int]] = IO(Right(1)) + feab.innerOrElse(0.asRight[String]) + // IO[Option[Int]] = IO(Some(1)) + + val feab2: IO[Either[String, Int]] = IO(Left("Error")) + // IO[Either[String, Int]] = IO(Left("Error")) + feab2.innerOrElse(0.asRight[String]) + // IO[Option[Int]] = IO(Some(0)) + ``` + * `innerOrElseF` + ```scala + val feab: F[Either[A, B]] = ... + feab.innerOrElseF[C >: A, D >: B](=> F[Either[C, D]]): F[Either[C, D]] + ``` + ```scala + val feab: IO[Either[String, Int]] = IO(Right(1)) + // IO[Either[String, Int]] = IO(Right(1)) + feab.innerOrElseF(IO.pure(0.asRight[String])) + // IO[Option[Int]] = IO(Some(1)) + + val feab2: IO[Either[String, Int]] = IO(Left("Error")) + // IO[Either[String, Int]] = IO(Left("Error")) + feab2.innerOrElseF(IO.pure(0.asRight[String])) + // IO[Option[Int]] = IO(Some(0)) + ``` + +* [`extras-cats`] Add tests for all new extension methods in `AllSyntax` inherited from `OptionSyntax` and `EitherSyntax` (#366)