Skip to content

Instantly share code, notes, and snippets.

@jedws
Created March 28, 2012 04:27
Show Gist options
  • Select an option

  • Save jedws/2223613 to your computer and use it in GitHub Desktop.

Select an option

Save jedws/2223613 to your computer and use it in GitHub Desktop.
config kit to make extracting configuration settings easy
package whatever
import com.typesafe.config.{ Config, ConfigFactory, ConfigObject, ConfigValue }
import org.joda.time.DateTime
trait Factory[A] {
def create(c: Configuration): A
}
/**
* Simple user-friendly wrapper around Config.
*
* Provides a single type-safe apply method for getting values out from the configuration.
*
* Usage:
* {{{
* val config = Configuration.load("filename.conf").get[Configuration]("objectName")
* val intThing = config[Int]("intPropertyName")
* val strThing = config[String]("stringPropertyName")
* }}}
*
* The Accessor type-classes implement the glue to get the specific type configuration item.
*
* Details on the underlying configuration file specification can be found here:
* http://blog.ometer.com/2011/12/09/configuring-the-typesafe-stack/
*/
class Configuration(c: Config) {
import Configuration._
def apply[A: Accessor](s: String): A =
implicitly[Accessor[A]].apply(c, s)
def get[A: Accessor](s: String): A =
implicitly[Accessor[A]].apply(c, s)
def option[A: Accessor](s: String): Option[A] =
catcher.opt {
implicitly[Accessor[A]].apply(c, s)
}
def valid[A: Accessor](s: String): Either[Throwable, A] =
catcher.either {
implicitly[Accessor[A]].apply(c, s)
}
}
object Configuration {
def apply(c: Config) = new Configuration(c)
def load(file: String) = Configuration(ConfigFactory load file)
/**
* The type-class that is used to extract a config item of a particular type.
*/
trait Accessor[A] extends ((Config, String) => A)
//
// standard type-class instances
//
implicit object IntAccessor extends Accessor[Int] {
def apply(c: Config, s: String) = c getInt s
}
implicit object StringAccessor extends Accessor[String] {
def apply(c: Config, s: String) = c getString s
}
implicit object LongAccessor extends Accessor[Long] {
def apply(c: Config, s: String) = c getLong s
}
implicit object BooleanAccessor extends Accessor[Boolean] {
def apply(c: Config, s: String) = c getBoolean s
}
implicit object DateTimeAccessor extends Accessor[DateTime] {
def apply(c: Config, s: String) = new DateTime(c getMilliseconds s)
}
implicit object ConfigAccessor extends Accessor[Configuration] {
def apply(c: Config, s: String) = Configuration(c getConfig s)
}
implicit object ClassAccessor extends Accessor[Class[_]] {
def apply(c: Config, s: String) = Class.forName(c getString s)
}
implicit def FactoryAccessor[A](implicit m: Manifest[Factory[A]]): Accessor[A] = new Accessor[A] {
def apply(c: Config, s: String) =
withA(Configuration(c)) { config =>
objectNamed[Factory[A]](config[String](s)).create(config)
}
}
// utils
private[Configuration] val catcher = util.control.Exception.allCatch
/**
* Hack to get a named (FQN) object declaration as the specified type
*/
private[Configuration] def objectNamed[A](name: String)(implicit man: Manifest[A]): A =
Class.forName(name + "$").getField("MODULE$").get(man.erasure).asInstanceOf[A]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment