Reputation: 1125
This is an OO design Q. Im using typesafe Config in my App. The Config interface is very useful, however there are a couple of fields in my applications; config file that are mandatory. What I wanted to do was create a subInterface of Config and add these 2 top-level methods . Something like this
trait AppConfig extends Config{
def param1:String
def param2:String
}
However creating a real instance of AppConfig given an instance of Config doesnt seem feasible.( I dont want to create wrapper object and duplicate all the methods on the Config interface) . Ideally , Im looking for something that would achieve something close to this
val conf:Config = //get config object from somewhere
return conf with AppConfig { overrider def param1 = {"blah"} }
I do understand the last line is not valid . But Im looking for a pattern/construct with an equivalent functionality.
Upvotes: 4
Views: 1795
Reputation: 32729
What you are looking for is basically what some call a "dynamic mixin". This is not supported out of the box by scala. Someone developed a compiler plugin to support this: http://www.artima.com/weblogs/viewpost.jsp?thread=275588
However it's a bit old and the project does not seem active anymore.
A better alternative would be to implement this feature using scala macros (requires scala 2.10, which has no stable release yet).
All of this is probably overkill in your case though. Until some well tested library is available, I would advise to just create the proxy by hand (however dull that may look):
trait ConfigProxy extends Config {
def impl: Config
// Forward to the inner config
def root: ConfigObject = impl.root
def origin: ConfigOrigin = impl.origin
//... and so on
}
val conf:Config = //get config object from somewhere
val myConf: AppConfig = new AppConfig with ConfigProxy {
val impl = conf
val param1:String = "foo"
val param2:String = "bar"
}
Upvotes: 1
Reputation: 24047
How about using a combination of Dynamic and Reflection. Dynamic to handle your convenience methods and reflection to handle the methods on config.
Here's a stab:
class ConfigDynamic(val config: Config) extends Dynamic {
def selectDynamic(name: String)= {
name match {
case "field1" =>
config.getString("field1")
case x @ _ =>
// overly simplified here
val meth = configClass.getDeclaredMethod(x)
meth.invoke(config)
}
}
}
Upvotes: 1
Reputation: 13959
We've been using Configrity for things like this. Here's an example:
We keep our compiled defaults that we use for unit test/etc in objects
object DefaultConfigs {
val defaultConfig = Configuration(
"param1" -> "blah"
)
val otherConfig = Configuration(
"param2" -> "blah"
)
val appConfig = defaultConfig.include(otherConfig)
}
And then at run time we can include them or not
val appConfig = Configuration.load(pathToConfig) include DefaultConfigs.appConfig
Upvotes: 2