Scalaで設定ファイルを使いたい時どうしたらいいの?
August 30, 2011 - Scala
2011.08.31 kmizushimaさんから頂いたコメントを元に、下記の記述を修正&追記しました。
- Twitterのutil-evalの一時ファイル生成について
- AkkaのConfigファイルのパース手法について
TwitterのOAuthの鍵やDB接続情報など、アプリを書く上で環境によって切り替える設定が大抵の場合あると思います。普段使っているPHPの場合、設定を外部ファイルに書きだす場合、ini,yaml,xml,phpのいずれかを使うことが多いのですが、Scalaの場合、設定ファイルってどうするのか気になりました。
ということで、適当に思いついたライブラリやフレームワークがどのように対応しているのか調査。
ライブラリ
propertiesファイル
- javaの古くから使われている
- キーと値のみ設定可能
- 依存関係がないので手軽。
- すべてが文字列
- 例えばこんな感じ
path/to/conf.properties
hoge = "moge"
val p = new java.util.Properties()
val config = p.load(new java.io.FileInputStream("path/to/conf.properties");
config.get("hoge") // "moge"
twitterのconfiggy
- https://github.com/robey/configgy
- 独自フォーマット
- オワコン
twitterのutil-eval
- http://twitter.github.com/util/
- Evalした値をそのまま利用
- Scalaのコンパイラに任せられる。つまりScalaコードがそのまま設定ファイルに。
- 型安全
- 詳しいことはこちらを参照
- 下記処理にて設定クラスインスタンスをapply経由で取り出せる
一時的にjarファイルを生成するので環境に制約あるとダメ(たぶん)- 一時ファイルを生成するのは、ローカルにcloneした古いままのバージョン(1.2.5)で動作確認していたためでした。
- 古いコード: com.twitter.util.EvaluatorのコメントにAll generated .scala and .class files are stored, by default, in System.getProperty(“java.io.tmpdir”)と書いてあったので、「一時ファイルが生成される」と認識し、実際の動作確認でもその一時ファイルが確認できていました。
- しかし、新しいコード: com.twitter.util.EvalのコメントにはIf target is None, the results are compiled to memory (and are therefore ephemeral)とある通り、パス指定がない場合はメモリ上の仮想ディレクトリに対して操作を行う模様です。
使い方
設定のtraitを定義
src/main/scala/com/restartr/utilSample/MyConfig.scala
package com.restartr.utilSample
trait MyConfig {
val num: Int
val str: String
}
実際の設定ファイルでは、設定のTraitを継承してインスタンス生成
※クラスインスタンスでなくても文字列やリストでもOK。
path/to/config/MyConfig.scala
import com.restartr.utilSample.MyConfig
new MyConfig {
val num = 1
val str = "san"
}
使いたい場所でEval。
val conf = Eval[MyConfig](new java.io.File("path/to/config/MyConfig.scala"))
conf.num // 1
conf.str // "san"
configrity
- https://github.com/paradigmatic/Configrity
- akkaのフォーマットと同等
- 設定のフォーマット
- Scala 2.9以上対象。
- configファイルの読み書きができる
- immutable, thread safe, allow functional design pattern
各種フレームワーク
以下のフレームワークはすべて独自実装でした。Propertiesじゃ役不足だし、かといってデファクトな設定用ライブラリがないからなのでしょうか。
akkaのconfig
- akka.confとかがそれ。
- 独自パーサーを使用
- 70行程度のシンプルなパーサー
- akka.config.ConfigParser
正規表現で定義されてるScalaのパーザコンビネータ(RegexParsersを継承)で定義されている- ”{“と”}“で階層構造を表現
akka {
cluster{
name = "test-cluster"
}
}
- 使える型
- 数値
- 文字列
- 真偽値(on/off , true/false)
- リスト [1,2,3] / [“hoge”,“moge”]
play!frameworkのconfig
- 独自パーサー
- java.util.propertiesを継承したもの。
- 環境ごとにIDを割り当てられる
- http://playdocja.appspot.com/documentation/1.2.1/production
- http://playdocja.appspot.com/documentation/1.2.1/guide11
- IDごとに%{ID}を頭につければ切り替えてくれるみたい
Lift
- LiftRulesが設定をもつ
ざっと調べて使ってみたところ、手軽にやるならProperties、フレームワークを使うならそれに則り、厳密にやるならTwitterのEvalや、設定ファイルを読み書きできる独特なConfigrityなんかがよさそうです。
XMLは…まぁないでしょうね。