Combinators
The combinators defined in
ConfigReader
provide an easy way to create new ConfigReader
instances by transforming existing ones. They are the simplest solution
for supporting new simple types and for slightly modifying existing implementations, since the amount of boilerplate
required is very small. This section contains some examples of combinators and shows how to work with them in
PureConfig.
The simplest combinator is map
, which simply transforms the result of an existing reader:
import com.typesafe.config.ConfigFactory
import pureconfig._
import pureconfig.generic.auto._
case class Conf(bytes: Vector[Byte])
// reads an array of bytes from a string
implicit val byteVectorReader: ConfigReader[Vector[Byte]] =
ConfigReader[String].map(_.getBytes.toVector)
ConfigSource.string("""{ bytes = "Hello world" }""").load[Conf]
// res1: pureconfig.ConfigReader.Result[Conf] = Right(Conf(Vector(72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100)))
emap
allows users to validate the inputs and provide detailed failures:
import pureconfig.error._
case class Port(number: Int)
case class Conf(port: Port)
// reads a TCP port, validating the number range
implicit val portReader = ConfigReader[Int].emap {
case n if n >= 0 && n < 65536 => Right(Port(n))
case n => Left(CannotConvert(n.toString, "Port", "Invalid port number"))
}
ConfigSource.string("{ port = 8080 }").load[Conf]
// res3: pureconfig.ConfigReader.Result[Conf] = Right(Conf(Port(8080)))
ConfigSource.string("{ port = -1 }").load[Conf]
// res4: pureconfig.ConfigReader.Result[Conf] = Left(ConfigReaderFailures(ConvertFailure(CannotConvert(-1,Port,Invalid port number),None,port),List()))
orElse
can be used to provide alternative ways to load a config:
val csvIntListReader = ConfigReader[String].map(_.split(",").map(_.toInt).toList)
implicit val intListReader = ConfigReader[List[Int]].orElse(csvIntListReader)
case class Conf(list: List[Int])
ConfigSource.string("""{ list = [1,2,3] }""").load[Conf]
// res5: pureconfig.ConfigReader.Result[Conf] = Right(Conf(List(1, 2, 3)))
ConfigSource.string("""{ list = "4,5,6" }""").load[Conf]
// res6: pureconfig.ConfigReader.Result[Conf] = Right(Conf(List(4, 5, 6)))