Created
March 28, 2012 04:27
-
-
Save jedws/2223613 to your computer and use it in GitHub Desktop.
config kit to make extracting configuration settings easy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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