2016-2-9 現在のところ Scala で YAML を扱うこなれた方法はないようです。ここでは SnakeYAML を利用します。
libraryDependencies += "org.yaml" % "snakeyaml" % "1.16"
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.16</version>
</dependency>
config.yaml (UTF-8)
--- !!myapp.Person
[
鈴木, # 名字
一郎, # 名前
123, # 年齢
]
Main.scala
package myapp
import org.yaml.snakeyaml.Yaml
import scala.beans.BeanProperty
import java.io.{File, FileInputStream}
class Person(
@BeanProperty var firstName: String,
@BeanProperty var lastName: String,
@BeanProperty var age: Int) {
override def toString: String = {
return firstName + ", " + lastName + ", " + age
}
}
object Main {
def main(args: Array[String]): Unit = {
val yaml = new Yaml
val input = new FileInputStream(new File("config.yaml"))
val obj = yaml.load(input)
val person = obj.asInstanceOf[Person]
println(person) //=> 鈴木, 一郎, 123
println(person.getAge()) //=> 123
}
}
設定ファイルとしての YAML を扱うことが難しい場合は、Scala コードを実行時に Eval することで代替できます。少し前までは Twitter 社が提供する util-eval を用いて Eval を実現していましたが、2.11 では Scala 公式のライブラリで Eval がサポートされています。sbt で依存関係を設定すると使用できるようになります。Scala 2.11.7 の場合は以下のようにします。Eval は重たい処理ですので頻繁に実行することは避けるようにします。
libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.11.7"
Main.scala
package myapp
import scala.tools.reflect.ToolBox
import scala.reflect.runtime.currentMirror
trait Config {
val hostname: String
val port: Int
}
object Main {
def main(args: Array[String]): Unit = {
val toolbox = currentMirror.mkToolBox()
// 簡単な例
val source: String = "List(1,2)"
val tree = toolbox.parse(source)
val result = toolbox.eval(tree).asInstanceOf[List[Int]]
println(result) //=> List(1, 2)
// 外部ファイルを利用する例
// 既存のクラス List[Int]
val listConfig = toolbox.eval(toolbox.parse(scala.io.Source.fromFile("./Config1.dat").mkString)).asInstanceOf[List[Int]]
println(listConfig) //=> List(1, 2, 3)
// 独自のクラス Config
val config: Config = toolbox.eval(toolbox.parse(scala.io.Source.fromFile("./Config2.dat").mkString)).asInstanceOf[Config]
println(config.hostname) //=> localhost
println(config.port) //=> 80
}
}
Config1.dat
List(1,2,3)
Config2.dat
文法としては、トレイトをミックスインした無名クラスです。
new myapp.Config {
val hostname = "localhost"
val port = 80
}