A boilerplate-free Scala library for loading configuration files
Loading configurations has always been a tedious and error-prone procedure. A common way to do it consists in writing code to deserialize each fields of the configuration. The more fields there are, the more code must be written (and tested and maintained...) and this must be replicated for each project.
This kind of code is boilerplate because most of the times the code can be automatically generated by
the compiler based on what must be loaded. For instance, if you are going to load an Int
for a field
named foo
, then probably you want some code that gets the values associated with the key foo
in
the configuration and assigns it to the proper field after converting it to Int
.
The goal of this library is to create at compile-time the boilerplate necessary to load a configuration of a certain type. In other words, you define what to load and PureConfig provides how to load it.
PureConfig is not a configuration library in the sense that it doesn't search for files or parse them. It can be seen as a better front-end for the existing libraries. It uses typesafe config library for loading raw configurations and then uses the raw configurations to do its magic.
In the sbt configuration file:
use scala 2.10
or 2.11
:
scalaVersion := "2.11.7" // or "2.10.5"
Add the library. For scala 2.11
libraryDependencies ++= Seq(
"com.github.melrief" %% "pureconfig" % "0.1.5"
)
For scala 2.10
you need also the scala macro paradise plugin:
libraryDependencies ++= Seq(
"com.github.melrief" %% "pureconfig" % "0.1.5",
compilerPlugin("org.scalamacros" % "paradise" % "2.0.1" cross CrossVersion.full)
)
For a full example of build.sbt
you can have a look at this build.sbt
used for the example.
In the example directory there is an example of usage of pureconfig. In the example, the idea is to load a configuration for a directory watcher service. The configuration file (a real one is available here) for this program will look like
dirwatch.path="/path/to/observe"
dirwatch.filter="*"
dirwatch.email.host=host_of_email_service
dirwatch.email.port=port_of_email_service
dirwatch.email.message="Dirwatch new path found report"
dirwatch.email.recipients="recipient1,recipient2"
dirwatch.email.sender="sender"
To load it, we define some classes that have proper fields and names
case class Config(dirwatch: DirWatchConfig)
case class DirWatchConfig(path: Path, filter: String, email: EmailConfig)
case class EmailConfig(host: String, port: Int, message: String, recipients: Set[String], sender: String)
And then we just load the configuration
val config = loadConfig[Config].get // loadConfig returns a Try
And that's it.
You can then use the configuration as you want:
println("dirwatch.path: " + config.dirwatch.path)
println("dirwatch.filter: " + config.dirwatch.filter)
println("dirwatch.email.host: " + config.dirwatch.email.host)
println("dirwatch.email.port: " + config.dirwatch.email.port)
println("dirwatch.email.message: " + config.dirwatch.email.message)
println("dirwatch.email.recipients: " + config.dirwatch.email.recipients)
println("dirwatch.email.sender: " + config.dirwatch.email.sender)
Mozilla Public License, version 2.0
To the Shapeless and to the Typesafe config developers.