読者です 読者をやめる 読者になる 読者になる

TOMLというミニマル言語

設定ファイルをjsonからTOMLに移行

ツールなんかを作るときある程度は自由度持たせるために設定をjsonで書いていたが、最近どうしてもカッコが面倒になってきた。
パラメータが少ない時なんかは問題無いんだけど、データが増えてくるとどうしても書くのが手間。(コメントも書けないし)
そんなことを思っていたらTOMLという物を発見。

# コメント 
Key1 = "Value1"
Array = [1, 2, 3]
[Object]
Key3 = "Value2"
[ObjectInArray]
Array = ["a","b","c"]

キーバリューペアの形式で書いていく形になる。
jsonの様にArrayやObject型などがあるため移行もしやすそう。

コメント

ハッシュ記号(#)から改行までがコメントとなる。

# コメントだよ
Key = Value #こんなのも可能

文字列

文字列の記述は4種類の方法がある。

基本

ダブルクォートで囲むと文字列として扱われる。
クォート、バックスラッシュなどはエスケープをする必要がある。

エスケープシーケンスの短縮形も用意されている。

\b         - backspace       (U+0008)
\t         - tab             (U+0009)
\n         - linefeed        (U+000A)
\f         - form feed       (U+000C)
\r         - carriage return (U+000D)
\"         - quote           (U+0022)
\/         - slash           (U+002F)
\\         - backslash       (U+005C)
\uXXXX     - unicode         (U+XXXX)
\UXXXXXXXX - unicode         (U+XXXXXXXX)

複数行文字列

改行も文字列として扱いたい場合、ダブルクォート3つで囲むことで表現出来る。
文字列の頭にすぐ改行を入れた場合その改行は無視される。

string = """
TOML Test
TOML Test"""

リテラル文字

正規表現のパターンを書くような場合、エスケープをするケースが増えとても面倒なケースが多い。
TOMLはリテラル文字列をサポートしているので、利用することでエスケープを省略して利用することが可能となっている。
リテラル文字を利用する場合シングルクォート囲むことで利用できる。

regex = \`[\d]+\'

複数リテラル文字

リテラル文字ではエスケープを利用することができないため、シングルクォートを利用することができない。
TOMLではリテラル文字の複数行をサポートしているのでそちらを利用する。
シングルクォートを3つで囲むことでリテラル文字として扱われる。

整数

全ての数は整数として扱われる。
正の数は頭にプラスを付けても、つけなくても表現できる。
負の数は頭にマイナスを付けて表現する。
大きな数字を表現する場合、アンダースコアを数字の間に挟むことで区切り表現をすることができる。

1_000
123_456_789

整数の表記を0から始めることはできず、2進数8進数16進数の形式で表現することは出来ない。
精度は64bit(long)

小数

小数部と指数部で表現が可能。
マイナス、プラスやアンダースコアでの区切りは整数と同じルールで利用可能

123.456_790

精度は64bit(double)

ブーリアン

ブーリアンはただのトークン。
小文字のみ利用可能。

日付

日付型はRFC 3339に準じる。(この規格しらないけど)
年-月-日T時:分:秒-UTCオフセットの形式になる。
UTCオフセットを0にする場合"年-月-日T時:分:秒Z"と記述すればよい。
日本のUTCオフセットは09:00なので 2016-02-29T00:00:00-09:00 となる。
タイムゾーンを利用するような場合以外は使わないとは思うが。
ちなみに秒には小数表現が可能。

配列

配列は[]この括弧で囲まれたプリミティブ型の集まり。
空白は無視され、要素はカンマで句切られる。
データ型は共通である必要がある。

array = [1, 2, 3]
matrix = [[1, 2, 3],[4, 5, 6]]
arrayStr = ["aa", "bb", "cc"]

テーブル

キーとバリューのペアからなる集まり。(jsonのオブジェクト型と同じ扱いができる)
テーブルはで囲まれたテーブル名から始まる。
配列表現と同じ括弧を利用するが、区別はしやすい。
配列の場合必ず値として表現するが、テーブルは値である必要はなく [table name] この様に記載する。

テーブルはで開始され、次のテーブルの開始またはファイルの終端までこのテーブルに属する。
使える文字は英数字、アンダースコア、ダッシュのみ(a-zA-Z0-9_-)

[table]
key1 = "value1"

key2 = "value2"

[table2]
key1 = "value1"
key2 = "value2"

と書いた場合jsonでは以下の構造を表現する。

{
  "table": {
    "key1": "value1",
    "key2": "value2"
  },
  "table2": {
    "key1": "value1",
    "key2": "value2"
  }
}

ネストしたテーブルを表現する場合ドットを利用する。

[table]
key1 = "value1"

key2 = "value2"

[table.NestTable]
key1 = "value1"
key2 = "value2"

この場合jsonで以下の構造を表現する。

{
  "table": {
    "key1": "value1",
    "key2": "value2",
    "NestTable": {
      "key1": "value1",
      "key2": "value2"
    }
  }
}

上位のテーブルを記載する必要が無い(値が存在しない)なら省略することも可能。
上位のテーブルを省略しても、後の行で上位のテーブルの内容を書くことはできる。
ただ、キーやテーブルの再定義は出来ないため、各定義は必ず1つである必要がある。

[table]
kay1 = "value1"

[table] # これはNG
kay2 = "value2"

テーブル配列

テーブルの再定義は行えないが、テーブルの配列を定義することはできる。
テーブル名を [ [table name] ] 括弧2重で囲むことで同じ名前のテーブルは配列の要素となる。
テーブルは表記順番で挿入され、キーとバリューのペアを持たないテーブルはからのテーブルとして扱われる。

[[TableArray]]
Key1 = "Value1"
[[TableArray]]
Key2 = "Value2"

これは以下のjsonの構造となる。

{
    "TableArray":[
        { "Key1" : "Value1" },
        { "Key2" : "Value2" }
    ]
}

ネストしたテーブルの配列も定義することができる。
その場合子テーブルにも括弧2重で囲めばよい。

まとめ

自分が使いそうな表記はこのぐらい。
頭でも書いたがjsonから機能の置き換えとしては十分。(むしろこっちのが良く思える)
パーサーも自分が使う言語はほぼあるので困ることはなさそう。

ただ、javascriptを使う時だけはなんとも言えない。
jsonはそのままjavascriptで使うことが出来るのに対して、TOMLは一度パーサーを通さないといけないから悩みどころ。
でも、製品で使う様な機能でない限りTOML採用かな。

参考URL
https://github.com/toml-lang/toml

※まだバージョンは0.4.0と1.0になってない所だけ注意