/pureconfig

A boilerplate-free library for loading configuration files

Primary LanguageScalaMozilla Public License 2.0MPL-2.0

PureConfig

A boilerplate-free Scala library for loading configuration files

Build Status Maven Central

Why

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.

Not yet another configuration library

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.

Add PureConfig to your project

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.9"
)

For scala 2.10 you need also the scala macro paradise plugin:

libraryDependencies ++= Seq(
  "com.github.melrief" %% "pureconfig" % "0.1.9",
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.

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

import java.nio.file.Path

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)

The use of Path gives us a chance to use a custom converter

import pureconfig._

import java.nio.file.Paths
import scala.util.Try

implicit val deriveStringConvertForPath = new StringConvert[Path] {
  override def from(str: String): Try[Path] = Try(Paths.get(str))
  override def to(path: Path): String = path.toString
}

And then we 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)

License

Mozilla Public License, version 2.0

Special Thanks

To the Shapeless and to the Typesafe config developers.