Skip to content

Commit

Permalink
Merge pull request #3924 from massimosiani/feature/prop
Browse files Browse the repository at this point in the history
Add `SystemProperties`
  • Loading branch information
djspiewak authored Nov 21, 2024
2 parents 2d27493 + 3eaa25b commit 8c305d7
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 1 deletion.
4 changes: 3 additions & 1 deletion core/shared/src/main/scala/cats/effect/IO.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import cats.data.Ior
import cats.effect.instances.spawn
import cats.effect.kernel.CancelScope
import cats.effect.kernel.GenTemporal.handleDuration
import cats.effect.std.{Backpressure, Console, Env, Supervisor, UUIDGen}
import cats.effect.std.{Backpressure, Console, Env, Supervisor, SystemProperties, UUIDGen}
import cats.effect.tracing.{Tracing, TracingEvent}
import cats.effect.unsafe.IORuntime
import cats.syntax._
Expand Down Expand Up @@ -2154,6 +2154,8 @@ object IO extends IOCompanionPlatform with IOLowPriorityImplicits with TuplePara

implicit val envForIO: Env[IO] = Env.make

implicit val systemPropertiesForIO: SystemProperties[IO] = SystemProperties.make

// This is cached as a val to save allocations, but it uses ops from the Async
// instance which is also cached as a val, and therefore needs to appear
// later in the file
Expand Down
132 changes: 132 additions & 0 deletions std/shared/src/main/scala/cats/effect/std/SystemProperties.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* Copyright 2020-2024 Typelevel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package cats.effect.std

import cats.{~>, Applicative, Functor}
import cats.data.{EitherT, IorT, Kleisli, OptionT, ReaderWriterStateT, StateT, WriterT}
import cats.effect.kernel.Sync
import cats.kernel.Monoid

trait SystemProperties[F[_]] { self =>

/**
* Gets the system property indicated by `key`.
*/
def get(key: String): F[Option[String]]

/**
* Sets the system property indicated by `key`.
*/
def set(key: String, value: String): F[Option[String]]

/**
* Removes the system property indicated by `key`.
*/
def clear(key: String): F[Option[String]]

def mapK[G[_]](f: F ~> G): SystemProperties[G] = new SystemProperties[G] {
def get(key: String) = f(self.get(key))
def set(key: String, value: String) = f(self.set(key, value))
def clear(key: String) = f(self.clear(key))
}
}

object SystemProperties {

/**
* Summoner method for `SystemProperties` instances.
*/
def apply[F[_]](implicit ev: SystemProperties[F]): ev.type = ev

/**
* Constructs a `SystemProperties` instance for `F` data types that are
* [[cats.effect.kernel.Sync]].
*/
def make[F[_]](implicit F: Sync[F]): SystemProperties[F] = new SyncSystemProperties[F]

/**
* [[SystemProperties]] instance built for `cats.data.EitherT` values initialized with any `F`
* data type that also implements [[SystemProperties]].
*/
implicit def catsEitherTSystemProperties[F[_]: SystemProperties: Functor, L]
: SystemProperties[EitherT[F, L, *]] =
SystemProperties[F].mapK(EitherT.liftK)

/**
* [[SystemProperties]] instance built for `cats.data.Kleisli` values initialized with any `F`
* data type that also implements [[SystemProperties]].
*/
implicit def catsKleisliSystemProperties[F[_]: SystemProperties, R]
: SystemProperties[Kleisli[F, R, *]] =
SystemProperties[F].mapK(Kleisli.liftK)

/**
* [[SystemProperties]] instance built for `cats.data.OptionT` values initialized with any `F`
* data type that also implements [[SystemProperties]].
*/
implicit def catsOptionTSystemProperties[F[_]: SystemProperties: Functor]
: SystemProperties[OptionT[F, *]] =
SystemProperties[F].mapK(OptionT.liftK)

/**
* [[SystemProperties]] instance built for `cats.data.StateT` values initialized with any `F`
* data type that also implements [[SystemProperties]].
*/
implicit def catsStateTSystemProperties[F[_]: SystemProperties: Applicative, S]
: SystemProperties[StateT[F, S, *]] =
SystemProperties[F].mapK(StateT.liftK)

/**
* [[SystemProperties]] instance built for `cats.data.WriterT` values initialized with any `F`
* data type that also implements [[SystemProperties]].
*/
implicit def catsWriterTSystemProperties[
F[_]: SystemProperties: Applicative,
L: Monoid
]: SystemProperties[WriterT[F, L, *]] =
SystemProperties[F].mapK(WriterT.liftK)

/**
* [[SystemProperties]] instance built for `cats.data.IorT` values initialized with any `F`
* data type that also implements [[SystemProperties]].
*/
implicit def catsIorTSystemProperties[F[_]: SystemProperties: Functor, L]
: SystemProperties[IorT[F, L, *]] =
SystemProperties[F].mapK(IorT.liftK)

/**
* [[SystemProperties]] instance built for `cats.data.ReaderWriterStateT` values initialized
* with any `F` data type that also implements [[SystemProperties]].
*/
implicit def catsReaderWriterStateTSystemProperties[
F[_]: SystemProperties: Applicative,
E,
L: Monoid,
S
]: SystemProperties[ReaderWriterStateT[F, E, L, S, *]] =
SystemProperties[F].mapK(ReaderWriterStateT.liftK)

private[std] final class SyncSystemProperties[F[_]](implicit F: Sync[F])
extends SystemProperties[F] {

def get(key: String) = F.delay(Option(System.getProperty(key)))

def set(key: String, value: String) = F.blocking(Option(System.setProperty(key, value)))

def clear(key: String) = F.blocking(Option(System.clearProperty(key)))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2020-2024 Typelevel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package cats.effect
package std

class SystemPropertiesSpec extends BaseSpec {

"SystemProperties" should {
"retrieve a property just set" in real {
Random.javaUtilConcurrentThreadLocalRandom[IO].nextString(12).flatMap { key =>
SystemProperties[IO].set(key, "bar") *>
SystemProperties[IO].get(key).flatMap(x => IO(x mustEqual Some("bar")))
}
}
"return none for a non-existent property" in real {
SystemProperties[IO].get("MADE_THIS_UP").flatMap(x => IO(x must beNone))
}
"clear" in real {
Random.javaUtilConcurrentThreadLocalRandom[IO].nextString(12).flatMap { key =>
SystemProperties[IO].set(key, "bar") *> SystemProperties[IO].clear(key) *>
SystemProperties[IO].get(key).flatMap(x => IO(x must beNone))
}
}
}
}

0 comments on commit 8c305d7

Please sign in to comment.