Ciris is very good. I am enjoying it!
I have run into some unexpected (to me) behavior regarding the interaction of missing properties and sequential vs. parallel composition. In the following code I have two configs that differ only in composition mode. I would expect that both will succeed or both will fail, the difference being only in the error message on failure. However this is not the case. config2
fails to load even though there is a default alternative provided. This seems like a bug to me.
import cats.effect._
import cats.implicits._
import ciris._
object CirisTest extends IOApp {
val config1 = (prop("a"), prop("b")).tupled or default(("foo", "bar"))
val config2 = (prop("a"), prop("b")).parTupled or default(("foo", "bar"))
def run(args: List[String]): IO[ExitCode] =
for {
_ <- IO(System.getProperties().put("a", "A"))
_ <- config1.load[IO].flatMap(c => IO(println(s"config1 is $c")))
_ <- config2.load[IO].flatMap(c => IO(println(s"config2 is $c")))
} yield ExitCode.Success
}
Output looks like this.
config1 is (foo,bar)
[E] ciris.ConfigException: configuration loading failed with the following errors.
[E]
[E] - Missing system property b.
[E]
[E] at ciris.ConfigException$.apply(ConfigException.scala:57)
[E] at ciris.ConfigError.throwable(ConfigError.scala:114)
[E] at ciris.ConfigValue.$anonfun$load$1(ConfigValue.scala:176)
[E] at cats.effect.Resource.$anonfun$fold$1(Resource.scala:118)
...