YAMLの読み書き

そういえばちょっと前に作ったものがありましたので紹介しておきます。libyamlを使うYAMLマッパーです。

必要なもの。

.dfm*3の読み書きをしようとしたときの副産物ですので余計なものが入ってますが気にしてはいけません。

さて、次のようなデータ構造があったとします。

type t = {
	x: float;
	y: string list;
	z: char option};;

これに対して次のようにマッピング関数を定義します。camlp4……はて……どこかで聞いたことがあるような無いような……。手動です。

let io_t ?key v s = Serialize.io_record (fun v s -> {
	x = Serialize.io_float ~key:"x" v.x s;
	y = Serialize.io_list Serialize.io_string "" ~key:"y" v.y s;
	z = Serialize.io_option Serialize.io_char '\x00' ~key:"z" v.z s}) ?key v s;;

機械的な対応ですので見ればわかりますね。
io_listやio_optionの第2引数は中身のダミー値です。なんでこんなものが必要かといいますとO'Camlは初期値無しで変数宣言できないからでありましてまあ中身の都合はどうでもいいです省略。
このマッピング関数で、YAMLの読み書きができます。.dfmが主目的ですが省略。

読み書きの例です。

let data1 = {x = 1.0; y = ["hello, world!"; "ping"; "pong"]; z = Some 'A'};;

let yaml = (
	let buf = Buffer.create 1024 in
	let w = Serialize_yaml.Writer.create "!TEST" (Buffer.add_string buf) in
	ignore (io_t data1 w);
	Buffer.contents buf
);;
print_string yaml;;

let read data cursor dest index length = (
	let really_length = (
		if !cursor + length <= String.length data then length else
		String.length data - !cursor
	) in
	String.blit data !cursor dest index really_length;
	cursor := !cursor + really_length;
	really_length
);;

let r = Serialize_yaml.Reader.create "!TEST" (read yaml (ref 0)) in
let result = io_t {x = 0.0; y = []; z = None} r in
assert (result = data1);;

マッピング関数に、Writerを通せばWriterに渡した出力関数にYAMLが出力され、Readerを通せばReaderに渡した入力関数*4から読み込んだデータが構築されます。Writer時の返値は引数と同値です。Reader時に渡すデータはダミーというかデフォルトです。YAMLテキストの中にx:が無かったりしますとここで渡した値のxが残ったまま出てきます。
実行例。

# ocaml bigarray.cma unicode.cma dfm.cma yaml.cma a.ml
--- !TEST
x: 1.
y:
- "hello, world!"
- "ping"
- "pong"
z: 'A'

めでたしめでたし。

おまけ。プリティプリンタとしての使用。

let pp = Serialize_pp.create Format.std_formatter;;
ignore (io_t data1 pp);;

出力例。

{x = 1.; y = ["hello, world!"; "ping"; "pong"]; z = Some 'A'}

*1:普通にconfigureからインストール。OSXならsudo port install libyamlでOK

*2:中のlib/unicode-ocaml, lib/dfm-ocaml, sourceの各ディレクトリでmake install DESTDIR=...

*3:Delphiシリアライズフォーマット。

*4:入力関数のシグネチャはPervasives.inputに揃えてます。例ではstringから読もうとしてますので面倒くさいことになってます。