typesafe configの設定パスをscalaのコードで表現する

ScalaMatsuriの感想ブログです

ScalaMatsuriでscala.metaの話を2つ聞いて面白そうと思ったので私もやってみました。 typesafe configをscala.metaとscalameta/paradiseのmacro annotationで設定パスを文字列ではなくscalaのコードで表現できるようにしたやつです。

github.com

こんな感じで使います。

// src/main/resources/application.conf
akka {
  actor {
    serializers {
      akka-containers = "akka.remote.serialization.MessageContainerSerializer"
    }
  }
}
import com.typesafe.config.ConfigFactory
import com.github.tototoshi.configpath.compile

@compile("src/main/resources/application.conf")
object path

object Example {

  def main(args: Array[String]): Unit = {
    val config = ConfigFactory.load()
    val serializer1 = config.getString(
      path.akka.actor.serializers.`akka-containers`.full)
    val serializer2 = config.getString(
      "akka.actor.serializers.akka-containers")
    assert(serializer1 == serializer2)
  }

}

objectかclassにcompileアノテーションをつけて、typesafe configの設定ファイルパスを渡すとmacroでコードを生成します。 上記のような設定ファイルがあった時、次のコードは

@compile("src/main/resources/application.conf")
object path

次のように展開されています。

object path {
  abstract class ConfigTree(val name: String, val full: String)
  object `akka` extends ConfigTree("akka", "akka") {
    object `actor` extends ConfigTree("actor", "akka.actor") {
      object `serializers` extends ConfigTree("serializers", "akka.actor.serializers") {
        object `akka-containers` extends ConfigTree("akka-containers", "akka.actor.serializers.akka-containers")
      }
    }
  }
}

これで設定の名前を間違えることがなくなりました。すごい。IntelliJがマクロに弱くて赤くなるけどね。IntelliJが追いついて補完が効くようになれば意外と便利かもしれない。