2010/12/20

Rubyアプリケーションでの設定ファイルのフォーマット

Jabberクライアントを作成した時の設定ファイルにJSON形式を使いましたが、少し後悔しています。

それはJSON形式では、最後の要素の後ろに','(カンマ)を置くとエラーになってしまうからです。

エンドユーザ向けの設定ファイルであれば、1行1命令であるべきで、各行相互の関係性を把握させるのは難しいと思います。

今回はそんなアプリケーションで利用する設定ファイルの書式について考えてみました。

手動で '=' で区切られた要素を分解し、Hashオブジェクトにする

テキストファイルで書ける設定ファイルは便利で、YAMLやJSONなどいくつか候補はあります。

しかし適当に '=' で区切った文字列を受領するような形式も手軽で使い易かったりします。

# filename: config.txt
jabber.name = Foo bar
jabber.pass = xxxxxx
jabber.server = jabber.org
...

これをHashに分解するコードはすぐに書けます。

=で区切られた設定ファイルを読み込み conf変数を準備する

#!/usr/local/bin/ruby
# -*- coding: utf-8 -*-
conf = Hash.new
open("config.txt","r:utf-8").each_line do |line|
  next if line.empty? or line =~ /^#|^$/
  key,value = line.split(/=/,2) 
  conf[key.strip] = value.strip
end
p conf
出力:
{"jabber.name"=>"Foo bar", "jabber.pass"=>"xxxxxx", "jabber.server"=>"jabber.org"}

この処理の中で受け付ける設定ファイル名だけを確認するなどすれば、エラーハンドリングも手軽でユーザにも優しいスクリプトになるでしょう。

Structクラスを使った設定ファイルを使用する

もう少し柔軟性が必要なら、設定できる項目を指定してstructを使う事もできます。

# -*- coding: utf-8 -*-
# filename: config.txt
@conf.name = '漢字の名前'
@conf.current_date = DateTime.now.ctime

@confオブジェクトに設定できる内容はStructによって制限する事ができます。

設定ファイルを読み込み @conf変数を書き換える

#!/usr/local/bin/ruby
# -*- coding: utf-8 -*-
Config = Struct.new(:name, :current_date)
@conf = Config.new
require 'date'
load 'config.txt'
p @conf
出力:
#<struct Config name="漢字の名前", pass="Mon Dec 20 15:48:46 2010">

スコープが異なるので、変数名は@で始まるインスタンス変数にする必要があります。

loadlの代りにrequireを使うこともできますが、ファイル名のサフィックスが".rb"である事や$:変数を適切に設定するなどの手続きが必要になることから、設定ファイルの読み込みにはloadが最適です。

また、この方法だとconfig.txtは完全なRubyスクリプトになるので、名前空間が汚染されるなど、一定の危険性はあります。

常に使える方法ではありませんが、もっと制御をユーザに開放したければDSL(Domain Specific Language)の手法が参考になるでしょう。

まとめ

YAML形式とかJSON形式はプログラマには便利で、アプリケーション同士がやりとりするにはデバッグ含めて最適だと思います。

一般ユーザに設定ファイルを書いてもらう場合には、検証と適切なエラーメッセージが出せるかどうかがポイントになります。

その点ではJSONパーサに処理をまかせてしまうよりは、手動で一行を読み込みsplitで分割する手法が案外役に立つ場面が多いでしょう。

0 件のコメント: