I am working through Scala For the Impatient by Horstman. I'm not doing this for a class. In the book, he has code that dynamically looks up and sets elements from an instance of java.util.Properties.
package dynamicProperties
import scala.language.dynamics
class DynamicProps(val props: java.util.Properties) extends Dynamic:
def updateDynamic(name: String)(value: String): AnyRef =
props.setProperty(name.replaceAll("_", ".'"), value)
def selectDynamic(name: String): String =
props.getProperty(name.replaceAll("_", "."))
def applyDynamicNamed(name: String)(args: (String, String)*): Any =
if name != "add" then throw IllegalArgumentException()
for (k, v) <- args do
props.setProperty(k.replaceAll("_", "."), v)
I wrote up some test code.
import dynamicProperties.DynamicProps
import org.scalatest.funsuite.AnyFunSuite
class DynamicPropsTest extends AnyFunSuite:
test("Set username") {
val sysProps = DynamicProps(System.getProperties)
sysProps.username = "Fred"
assert(sysProps.username == "Fred")
}
test("Assign java.home") {
val sysProps = DynamicProps(System.getProperties)
val home = sysProps.java_home
val javaHome = System.getProperty("java.home")
assert(home == javaHome)
}
test("Add key/value pairs") {
val sysProps = DynamicProps(System.getProperties)
sysProps.add(username="Fred", password="Secret")
assert(sysProps.username == "Fred")
assert(sysProps.password == "Secret")
}
In the book, the reader is supposed to figure out a way to select and set properties without an underscore. For example, you should be able to do this:
val sysProps = DynamicProps(System.getProperties)
val home = sysProps.java.home
I am not sure how to do this. I know if I remove the code that replaces underscores with periods in the class I get this error if run the above snippet.
value home is not a member of String
val home = sysProps.java.home
Any hints?
Since it's been a week since @DanGetz's hints, I guess now it's safe to share a partial solution. You can apply Dynamic
logic recursively:
class DynamicProps(
props: java.util.Properties,
propName: String = "",
prop: Option[String] = None,
) extends Dynamic:
def selectDynamic(name: String): DynamicProps =
val newName = if propName.isEmpty then name else propName + "." + name
val newProp = Option(props.getProperty(newName))
DynamicProps(props, newName, newProp)
override def toString: String = prop.getOrElse("n/a")
Then
val props = DynamicProps({
val p = java.util.Properties()
p.setProperty("xxx", "aaa")
p.setProperty("xxx.yyy", "bbb")
p
})
props.xxx // aaa
props.xxx.yyy // bbb
val sysProps = DynamicProps(System.getProperties)
sysProps.xxx // n/a
sysProps.java.home // /media/data/jdk1.8.0_351/jre
sysProps.java.runtime.name // Java(TM) SE Runtime Environment