diff --git a/changelogs/2.0.0.md b/changelogs/2.0.0.md new file mode 100644 index 00000000..2a478e30 --- /dev/null +++ b/changelogs/2.0.0.md @@ -0,0 +1,569 @@ +## [2.0.0](https://github.com/kevin-lee/effectie/issues?q=is%3Aissue+is%3Aclosed+milestone%3Av2-m1) - 2024-12-01 + +* Temporarily disable `Scala.js` support (#636) +* Improve design (Effectie v2) (#300) + +It also includes all the changes in the following releases. + +## [2.0.0-beta1](https://github.com/Kevin-Lee/effectie/issues?q=is%3Aissue+is%3Aclosed+milestone%3Av2-m1+created%3A%3C%3D2022-03-28) - 2022-05-02 + +## Done +* Make `Fx` `CanCatch` (#301) +* Make `Fx` `CanHandleError` (#302) +* Make `Fx` `CanRecover` (#303) +* `core` project should be effect library free (#304) +* Sub-projects for `Cats Effect` and `Monix` (#305) +* Remove `EffectConstructor` (#306) +* Withdraw `Scalaz Effect` support (#308) +* Remove `Xor` (#310) +* Remove `OptionTSupport` (#314) +* Remove `EitherTSupport` (#315) +* Remove `Fx`, `FxCtor` and `CanCatch` `trait`s from `effectie-cats-effect`, `effectie-cats-effect3` and `effectie-monix` (#320) +* Remove `CanHandleError` and `CanRecover` `trait`s from `effectie-cats-effect`, `effectie-cats-effect3` and `effectie-monix` (#322) +* Add missing type class instances and fix tests (#326) +* Remove unused libraries for testing code using `cats-effect3` (#328) +* Set up Codecov in GitHub Actions (#339) +* Publish to `s01.oss.sonatype.org` (the new Maven central) (#342) +* Use `extras-concurrent` and `extras-concurrent-testing` for testing (#348) +* Test typeclasses for `Future` in the `core` project (#350) +* Change `Effectful` to `fx` and move to `core` / also move possible `error` `syntax` to `core` (#352) +* Rename the package of the `core` from `effectie` to `effectie.core` (#358) +* Redesign `ConsoleEffect` and `ConsoleEffectful` (#364) +* Move `FromFuture` and `ToFuture` to `core` and leave only typeclass instances in the sub-projects (#367) +* Uncapitalize typeclass instance names for Scala 2 (#371) +* Move all sub-projects to `modules` (#373) +* Upgrade `cats` to `2.7.0` (#377) +* Add `effectie-cats` for `cats` specific code (#384) +* Add `Scalafix` and `Scalafmt` checks (#386) +* Support `Scala.js` (#388) +* Add `fromEither`, `fromOption` and `fromTry` to `FxCtor` and `Fx` (#393) +--- + +## [2.0.0-beta2](https://github.com/Kevin-Lee/effectie/issues?q=is%3Aissue+is%3Aclosed+milestone%3Av2-m1+created%3A%3E2022-03-28+closed%3A%3C2022-09-20) - 2022-09-20 + +## Renaming +Rename modules and packages (#430) + +### Modules +* `effectie-cats` => `effectie-syntax` +* `effectie-cats-effect` => `effectie-cats-effect2` +* `effectie-cats-effect3` remains the same +* `effectie-monix` => `effectie-monix3` + +### Packages +* Cats Effect 2: `effectie.cats` => `effectie.ce2` +* Cats Effect 3: `effectie.cats` => `effectie.ce3` +* Monix 3: `effectie.monix` => `effectie.monix3` +*** + +## Project Structure Change +* Use `effectie-cats-effect` common code for `effectie-monix` (#425) +*** + +## Added +* Add `FxCtor.pureOrError(a)` and `Fx.pureOrError(a)` (#424) + ```scala + FxCtor[IO].pureOrError(1) + // IO[Int] = Pure(1) + + FxCtor[IO].pureOrError[Int]((throw new RuntimeException("ERROR")): Int) + // IO[Int] = RaiseError(java.lang.RuntimeException("ERROR")) + ``` + +*** + +## Clean up +* Clean up syntax (#421) +* syntax should have cats (#432) + * (`effectie.cats.syntax` and `effectie.syntax`) => `effectie.syntax` + +*** + +## Documentation +* Upgrade docs site to Docusaurus `2.0.0-rc.1` (#415) + +--- + +## [2.0.0-beta3](https://github.com/Kevin-Lee/effectie/issues?q=is%3Aissue+is%3Aclosed+milestone%3Av2-m1+closed%3A2022-09-20..2022-11-13) - 2022-11-13 + +### Packages +* Reorganize instances - move to `effectie.instances` (#429) + * `effectie.instances.future` + * `effectie.instances.ce2` + * `effectie.instances.ce3` + * `effectie.instances.monix3` + * `effectie.instances.id` + +### Details +* move to `effectie.instances`: Move instances for `Future` to `effectie.instances.future` +* Also add `@implicitNotFound` to show what to import +* move to `effectie.instances`: Move instances for `Id` to `effectie.instances.id` +* Remove instances for `Id` for Cats Effect 2 and 3 since they are now in the `effectie-cats` +* Move `ConsoleEffect` instance to `effectie.instances` +* Also `effectie.instances.future.fromFuture.FromFutureToIdTimeout` => `effectie.core.FromFuture.FromFutureToIdTimeout` +* Remove instances for `Id` for Monix since they are now in the `effectie-cats` +* Remove instances for `IO` for Monix since they are now in the `effectie-cats-effect2` +* Move instances for `IO` and `Task` to `effectie.instances` + +*** + +## Added +* Add `ReleasableResource` to automatically release resource after use (#443) + * For `cats-effect` it should use `cats.effect.Resource` as its implementation + * For non-`cats-effect`, use Scala's `scala.util.Using` and `Future` with proper resource release + +### `ReleasableResource` with `Using` and `Try` + +```scala +import effectie.resource.ReleasableResource + +ReleasableResource.usingResource(SomeAutoCloseable()) + .use { resource => + Try(resource.doSoemthing()) // Try[A] + } // Try[A] + +// OR + +val trySomeResource: Try[SomeResource] = ... +ReleasableResource.usingResourceFromTry(trySomeResource) + .use { resource => + Try(resource.doSoemthing()) // Try[A] + } // Try[A] + +``` + +### `ReleasableResource` with `Future` + +```scala +import effectie.resource.ReleasableResource +val futureResource: Future[SomeResource] = ... + +ReleasableResource.futureResource(futureResource) + .use { resource => + Future(doSomething(resource)) // Future[A] + } // Future[A] + +``` + +### `ReleasableResource` with Cats Effect `IO` +* Cats Effect 2 + ```scala + import effectie.resource.Ce2Resource + + val fa: F[SomeResource] = ... + + Ce2Resource.fromAutoCloseable(fa) + .use { resource => + Sycn[F].delay(doSomething(resource)) // F[A] + } // F[A] + ``` + +* Cats Effect 3 + ```scala + import effectie.resource.Ce3Resource + + val fa: F[SomeResource] = ... + + Ce3Resource.fromAutoCloseable(fa) + .use { resource => + Sycn[F].delay(doSomething(resource)) // F[A] + } // F[A] + ``` + +--- + +## [2.0.0-beta4](https://github.com/Kevin-Lee/effectie/issues?q=is%3Aissue+is%3Aclosed+milestone%3Av2-m1+closed%3A2022-11-14..2022-12-25) - 2022-12-25 🎄 + +### Changes +* Update missing implicit instance messages for Scala 3 (#454) + e.g.) + ```scala + import effectie.instances.ce2.fx.* + ``` + to + ```scala + import effectie.instances.ce2.fx.given + ``` +* Change `f` in `def catchNonFatal[A, B](fb: => F[B])(f: Throwable => A): F[Either[A, B]]` to `f: PartialFunction[Throwable, AA]` (#457) + ```scala + CanCatch[F].catchNonFatal(fa) { + case FooException(err) => + FooError(err) + } + // If fa throws FooException, the result is F[Either[FooError, A]] + // If fa throws some other exception, the result is F[Either[FooError, A]] but it's actually the same as errorOf[Either[FooError, A]](theException) so the exception is not caught in Either. + ``` + +--- + +## [2.0.0-beta5](https://github.com/Kevin-Lee/effectie/issues?q=is%3Aissue+is%3Aclosed+milestone%3Av2-m1+closed%3A2022-12-26..2023-01-14) - 2023-01-14 + +### New Features +* Add `ResourceMaker` (#468) + ```scala + ResourceMaker[F].forAutoCloseable[A <: AutoCloseable](fa: F[A]): ReleasableResource[F, A] + ``` + ```scala + import effectie.resource.ResourceMaker + + ResourceMaker.usingResourceMaker // ResourceMaker[Try] + ResourceMaker.futureResourceMaker(implicit ec: ExecutionContext) // ResourceMaker[Future] + ``` + + ```scala + import effectie.resource.Ce2ResourceMaker + + Ce2ResourceMaker.forAutoCloseable // ResourceMaker[F] where F[*]: Sync: BracketThrow + ``` + + ```scala + import effectie.resource.Ce3Resource + + Ce3Resource.forAutoCloseable // ResourceMaker[F] where F[*]: Sync: MonadCancelThrow + ``` + +### Internal Housekeeping +* `cats-effect` `3.3.5` => `3.3.14` + +--- + +## [2.0.0-beta6](https://github.com/Kevin-Lee/effectie/issues?q=is%3Aissue+is%3Aclosed+milestone%3Av2-m1+closed%3A2023-01-15..2023-02-11) - 2023-02-11 + +### Change +* Remove `implicit fxCtor: FxCtor[F]` param from the catch methods in `CanCatch` (#480) + + The following methods in `CanCatch` + ```scala + def catchNonFatal[A, B]( + fb: => F[B] + )( + f: PartialFunction[Throwable, A] + )( + implicit fxCtor: FxCtor[F] + ): F[Either[A, B]] + + def catchNonFatalEither[A, AA >: A, B]( + fab: => F[Either[A, B]] + )( + f: PartialFunction[Throwable, AA] + )( + implicit fxCtor: FxCtor[F] + ): F[Either[AA, B]] + ``` + have been changed to + ```scala + def catchNonFatal[A, B]( + fb: => F[B] + )( + f: PartialFunction[Throwable, A] + ): F[Either[A, B]] + + def catchNonFatalEither[A, AA >: A, B]( + fab: => F[Either[A, B]] + )( + f: PartialFunction[Throwable, AA] + ): F[Either[AA, B]] + ``` + +--- + +## [2.0.0-beta7](https://github.com/Kevin-Lee/effectie/issues?q=is%3Aissue+is%3Aclosed+milestone%3Av2-m1+closed%3A2023-02-12..2023-02-25) - 2023-02-25 + +### New Features +* Add `pureOfOption`, `pureOfSome`, `pureOfNone`, `pureOfRight` and `pureOfLeft` to `FxCtor` and `Fx` (#488) + * `Fx[F].pureOfOption[A](a: A): F[Option[A]]` + * `Fx[F].pureOfSome[A](a: A): F[Option[A]]` + * `Fx[F].pureOfNone[A]: F[Option[A]]` + * `Fx[F].pureOfRight[A][B](b: B): F[Either[A, B]]` + * `Fx[F].pureOfLeft[B][A](a: A): F[Either[A, B]]` + +### Fix +* Fix typo in the missing `implicit` instance messages (#489) + +--- + +## [2.0.0-beta8](https://github.com/Kevin-Lee/effectie/issues?q=is%3Aissue+is%3Aclosed+milestone%3Av2-m1+closed%3A2023-02-26..2023-03-07) - 2023-03-07 + +### Changes + +* Remove unused implicit params (#497) + ```scala + def catchNonFatal[A]( + f: PartialFunction[Throwable, A] + )( + implicit canCatch: CanCatch[F], + fxCtor: FxCtor[F], // <= This is unused + ): F[Either[A, B]] = + canCatch.catchNonFatal[A, B](fb())(f) + ``` + The `implicit` param `fxCtor: FxCtor[F]` has been removed. +* Rename `ConsoleEffect` to `ConsoleFx` (#499) +* Move `flatMapFa` from `CanCatch` to `FxCtor` (#501) + ```scala + def flatMapFa[A, B](fa: F[A])(f: A => F[B]): F[B] + ``` +* Move `FxCtor` from instance creation of `ConsoleFx` to each `ConsoleFx` method param (#504) + ```scala + implicit def consoleFxF[F[*]: FxCtor: FlatMap]: ConsoleFx[F] = ... + ``` + to + ```scala + trait ConsoleFx[F[*]] { + def readLn(implicit fxCtor: FxCtor[F]): F[String] + + def readPassword(implicit fxCtor: FxCtor[F]): F[Array[Char]] + + def putStr(value: String)(implicit fxCtor: FxCtor[F]): F[Unit] + + def putStrLn(value: String)(implicit fxCtor: FxCtor[F]): F[Unit] + + def putErrStr(value: String)(implicit fxCtor: FxCtor[F]): F[Unit] + + def putErrStrLn(value: String)(implicit fxCtor: FxCtor[F]): F[Unit] + + def readYesNo(prompt: String)(implicit fxCtor: FxCtor[F]): F[YesNo] + } + ``` +* `ConsoleFx` instance should not depend on cats (`Monad`) (#505) + + Instead, it depends on `FxCtor` now. + +--- + +## [2.0.0-beta9](https://github.com/Kevin-Lee/effectie/issues?q=is%3Aissue+is%3Aclosed+milestone%3Av2-m1+closed%3A2023-03-08..2023-03-18) - 2023-03-18 + +### New Feature + +* Add `Fx` instance for `Try` - `Fx[Try]` (#512) + + +### Internal Housekeeping + +* Remove `cats` from the `core` module (#513) +* Reorganize tests (#515) + +--- + + +## [2.0.0-beta10](https://github.com/Kevin-Lee/effectie/issues?q=is%3Aissue+is%3Aclosed+milestone%3Av2-m1+closed%3A2023-03-19..2023-07-15) - 2023-07-15 + +### New Feature + +* Add `fromEffect(fa: => F[A]): F[A]` to `FxCtor` and `Fx` (#524) + ```scala + Fx[IO].fromEffect(IO(1)) // IO[Int] + FxCtor[IO].fromEffect(IO(1)) // IO[Int] + ``` + + +* Add `make[A](fa: => F[A])(release: A => F[Unit]): ReleasableResource[F, A]` to `ResourceMaker[F[*]]` (#527) + ```scala + def make[A](fa: => F[A])(release: A => F[Unit]): ReleasableResource[F, A] + ``` + + * `Try` + ```scala + val resourceMaker = ResourceMaker.usingResourceMaker + resourceMaker + .make(Try(new SomeResource()))(a => Try(a.release())) // ReleasableResource[Try, SomeResource] + .use { someResource => + // do something with someResource + Try(result) // Try[ResultType] + } // Try[ResultType] + ``` + + * Future + ```scala + val resourceMaker = ResourceMaker.futureResourceMaker + resourceMaker + .make(Future(new SomeResource()))(a => Future(a.release())) // ReleasableResource[Future, SomeResource] + .use { someResource => + // do something with someResource + Future.successful(result) // Future[ResultType] + } // Future[ResultType] + ``` + + * Cats Effect 2 + ```scala + val resourceMaker = Ce2ResourceMaker.withResource + resourceMaker + .make(IO(new SomeResource()))(a => IO(a.release())) // ReleasableResource[IO, SomeResource] + .use { someResource => + // do something with someResource + IO.pure(result) // IO[ResultType] + } // IO[ResultType] + ``` + + * Cats Effect 3 + ```scala + val resourceMaker = Ce3ResourceMaker.withResource + resourceMaker + .make(IO(new SomeResource()))(a => IO(a.release())) // ReleasableResource[IO, SomeResource] + .use { someResource => + // do something with someResource + IO.pure(result) // IO[ResultType] + } // IO[ResultType] + ``` + + +* Add `pure[A](a: A)` and `eval[A](fa: F[A])` to `ResourceMaker` (#534) + ```scala + trait ResourceMaker[F[*]] { + ... + + def pure[A](a: A): ReleasableResource[F, A] + + def eval[A](fa: F[A]): ReleasableResource[F, A] + } + ``` + + +* Add `ReleasableResource.pure` (#542) + ```scala + ReleasableResource.pure(resource: A): ReleasableResource[F, A] + ``` + So `A` doesn't have to be `AutoCloseable` as it's just a pure value. + + +* Add `ReleasableResource.map` and `ReleasableResource.flatMap` (#544) + ```scala + ReleasableResource.map(f: A => B) + ReleasableResource.flatMap(f: A => ReleasableResource[F, B]) + ``` + + +* Add `Functor` type-class for `ReleasableResource` (#548) + + +* Add `Applicative` type-class for `ReleasableResource` (#550) + + + +### Changes + +* Remove unnecessary re-evaluation of `ResourceMaker` (#529) + + The following `ResourceMaker` constructor method is just `val` now. + ```scala + effectie.resource.ResourceMaker.usingResourceMaker + ``` + + +* Rename `withResource` in `Ce2ResourceMaker` and `Ce3ResourceMaker` to `maker` (#530) + + +* Move `ResourceMaker` and `ReleasableResource` to `effectie-cats` (#546) + + Having `ReleasableResource` in `effectie-cats` is required to have `Functor` and `Monad` type-classes. + + +--- + +## [2.0.0-beta11](https://github.com/kevin-lee/effectie/issues?q=is%3Aissue+is%3Aclosed+milestone%3Av2-m1+closed%3A2023-07-16..2023-07-22) - 2023-07-22 + +### Fixed +* Fix the comments of the `deprecated` methods in `Ce2ResourceMaker` and `Ce3ResourceMaker` (#559) + * `Ce2ResourceMaker`: `Please use withResource instead` => `Please use Ce2ResourceMaker.maker instead` + * `Ce3ResourceMaker`: `Please use withResource instead` => `Please use Ce3ResourceMaker.maker instead` + +--- + +## [2.0.0-beta12](https://github.com/kevin-lee/effectie/issues?q=is%3Aissue+is%3Aclosed+milestone%3Av2-m1+closed%3A2023-07-23..2023-09-09) - 2023-09-09 + +### New Features +* Add `CanRestart` for retrying `F[A]` (#566) + ```scala + trait CanRestart[F[*]] { + def restartWhile[A](fa: F[A])(p: A => Boolean): F[A] + + def restartUntil[A](fa: F[A])(p: A => Boolean): F[A] + + def restartOnError[A](fa: F[A])(maxRetries: Long): F[A] + + def restartOnErrorIfTrue[A](fa: F[A])(p: Throwable => Boolean): F[A] + } + ``` + +* Add instances of `CanCatch`, `CanHandleError`, `CanRecover`, `FromFuture`, `Fx` and `FxCtor` with `Sync` and `Async` (#568) + + So it can be done like this with the `effectie.instances.ce2.f` and `effectie.instances.ce3.f` packages. + ```scala + def foo[F[*]: Fx](n: Int): F[Int] = Fx[F].effectOf(n * 2) + + // Fx[F] can be satisfied with just Sync[F] like this. + import effectie.instances.ce2.f.fx._ + def bar[F[*]: Sync](n: Int): F[Int] = foo(n) + ``` + +--- + +## [2.0.0-beta13](https://github.com/kevin-lee/effectie/issues?q=is%3Aissue+is%3Aclosed+milestone%3Av2-m1+closed%3A2023-09-10..2023-09-30) - 2023-10-01 + +### Changes +* `CanHandleError[Future]` and `CanRecover[Future]` should use `Future`'s `recover` and `recoverWith`. (#584) +* `CanHandleError[Try].handleNonFatal` and `CanRecover[Try].recoverFromNonFatal` should use `Try`'s `recover` (#586) + +### New Feature +* `rethrowIfLeft` and `rethrowTIfLeft` `syntax` for `F[Either[A, B]]` and `EitherT[F, A, B]` (#588) + ```scala + val fa: IO[Either[Throwable, Int]] = pureOf[IO](Right(1)) + fa.rethrowIfLeft + // IO[Int] = IO(1) + ``` + ```scala + val fa: IO[Either[Throwable, Int]] = pureOf[IO](Left(new RuntimeException("Error"))) + fa.rethrowIfLeft + // IO[Int] = RaiseError(RuntimeException("ERROR")) + ``` + + ```scala + val fa: EitherT[IO, Throwable, Int] = pureOf[IO](Right(1)).eitherT + fa.rethrowTIfLeft + // IO[Int] = IO(1) + ``` + ```scala + val fa: EitherT[IO, Throwable, Int] = pureOf[IO](Left(new RuntimeException("Error"))).eitherT + fa.rethrowTIfLeft + // IO[Int] = RaiseError(RuntimeException("ERROR")) + ``` + +--- + +## [2.0.0-beta14](https://github.com/kevin-lee/effectie/issues?q=is%3Aissue+is%3Aclosed+milestone%3Av2-m1+closed%3A2023-10-01..2024-01-12) - 2024-01-12 + +### New Feature +* Add `effectie-time` module (#601) +* [`effectie-time`] Add `TimeSource` (#602) + ```scala + TimeSource[F].currentTime() + TimeSource[F].realTime + TimeSource[F].realTimeTo + TimeSource[F].monotonic + TimeSource[F].monotonicTo + TimeSource[F].timeSpent(F[A]) + ``` +* [`effectie-time`] Add `ApproxFiniteDuration` and `syntax` (#603) + ```scala + import scala.concurrent.duration._ + import effectie.time.syntax._ + + 5.seconds +- 2.seconds + // ApproxFiniteDuration(5.seconds, 2.seconds) + + 3.seconds.isWithIn(5.seconds +- 2.seconds) + // Boolean = true + + 7.seconds.isWithIn(5.seconds +- 2.seconds) + // Boolean = true + + 2.seconds.isWithIn(5.seconds +- 2.seconds) + // Boolean = false + + 8.seconds.isWithIn(5.seconds +- 2.seconds) + // Boolean = false + ``` +* Add ~~`effectie-cats-effect2-time`~~ `effectie-time-cats-effect2` (#607) +* [`effectie-cats-effect2-time`] Add `TimeSource` with `Clock` from `cats-effect` 2 (#608) +* Add ~~`effectie-cats-effect3-time`~~ `effectie-time-cats-effect3` (#610) +* [`effectie-cats-effect3-time`] Add `TimeSource` with `Clock` from `cats-effect` 3 (#611) +* Rename `effectie-cats-effect2-time` to `effectie-time-cats-effect2` and `effectie-cats-effect3-time` to `effectie-time-cats-effect3` (#615)