Helpers for cats & co.
Bones is a great cat as well as a pure tagless final wrapper for slf4j. You should use Bones because:
- It allows you to separate out the orthogonal concern of carrying a logging context without relying on mutable global state
- It supports strongly typed logging contexts that are transformed into independent values in the
MDC
- e.g.
case class A(b: String)
,case class C(d: A)
withC(A("hi!"))
would be set in theMDC
asd.b -> "hi!"
- e.g.
- It uses Li Haoyi's
sourcecode
to add the full name of the nearest enclosing definition where the logger was invoked to the MDC as the keyCodeLocation
import cats.implicits._
import cats.mtl.implicits._
import cats.effect.IO
import cats.data.ReaderT
import ltd.k1nd.pets.bones.log.MdcLogger
case class Context(name: String, age: Int)
type MyReader[T] = ReaderT[IO, Context, T]
val logger = MdcLogger[IO, MyReader, Context](getClass).unsafeRunSync()
logger.info("This is a log - wow!").run(Context("Elias", 27)).unsafeRunSync()
Takes a by name value and lifts it into a Sync context.
scala> import ltd.k1nd.pets.dog.syntax.SyncOps._
import ltd.k1nd.pets.dog.syntax.SyncOps._
scala> import cats.effect.IO
import cats.effect.IO
scala> val suspended = println("hey friend").delay[IO]
suspended: cats.effect.IO[Unit] = IO$305606396
scala> suspended.unsafeRunSync()
hey friend
Converts a boolean into an applicative error, with true corresponding to success and false corresponding to error.
scala> import ltd.k1nd.pets.dog.syntax.BooleanOps._
import ltd.k1nd.pets.dog.syntax.BooleanOps._
scala> import scala.util.Try
import scala.util.Try
scala> import cats.implicits.catsStdInstancesForTry
import cats.implicits.catsStdInstancesForTry
scala> val exception: Throwable = new Exception("hey you")
exception: Throwable = java.lang.Exception: hey you
scala> val notUnit: Try[Unit] = false.toApplicativeError(exception)
notUnit: scala.util.Try[Unit] = Failure(java.lang.Exception: hey you)
scala> val definitelyMyString: Try[String] = true.toApplicativeError(exception, "onSuccess")
definitelyMyString: scala.util.Try[String] = Success(onSuccess)
An extension method on boolean that evaluates to it's first argument if false and the second if true.
scala> import ltd.k1nd.pets.dog.syntax.BooleanOps._
import ltd.k1nd.pets.dog.syntax.BooleanOps._
scala> val left = false.ifElseThen("left", "right")
left: String = left
scala> val right = true.ifElseThen("left", "right")
right: String = right
An extension method on boolean that evaluates to left if false and right if true.
scala> import ltd.k1nd.pets.dog.syntax.BooleanOps._
import ltd.k1nd.pets.dog.syntax.BooleanOps._
scala> val left = false.toEither("left", "right")
left: Either[String,String] = Left(left)
scala> val right = true.toEither("left", "right")
right: Either[String,String] = Right(right)
An extension method on boolean that delegates to whenA - runs the provided effect when true, unit otherwise.
scala> import ltd.k1nd.pets.dog.syntax.BooleanOps._
import ltd.k1nd.pets.dog.syntax.BooleanOps._
scala> import cats.Id
import cats.Id
scala> def runEffect(): Id[Unit] = println("I'm a side effect!")
runEffect: ()cats.Id[Unit]
scala> val left = false.whenA(runEffect())
left: cats.Id[Unit] = ()
scala> val right = true.whenA(runEffect())
I'm a side effect!
right: cats.Id[Unit] = ()
Converts a Future to an IO without starting the Future
scala> import ltd.k1nd.pets.dog.syntax.FutureOps._
import ltd.k1nd.pets.dog.syntax.FutureOps._
scala> import scala.concurrent.Future
import scala.concurrent.Future
scala> Future.successful(123).toIO
res0: cats.effect.IO[Int] = IO$147326788
Transforms an option into an OptionT for some context (Applicative) F[_]
scala> import ltd.k1nd.pets.dog.syntax.OptionOps._
import ltd.k1nd.pets.dog.syntax.OptionOps._
scala> import cats.Id
import cats.Id
scala> Option(123).toOptionT[Id]
res0: cats.data.OptionT[cats.Id,Int] = OptionT(Some(123))
scala> None.toOptionT[Id]
res1: cats.data.OptionT[cats.Id,Nothing] = OptionT(None)