joとの比較で負けている気になったのでmkdictにblockを入れてみた
昨日の記事でjoと比較してみたのだけれど。ネストが深いJSONを作るのは楽でも、同じ階層の複数フィールドに値をもたせたJSONを作るのが大変だった。癪だったのでblockという概念を導入してみた。
同じ階層に複数のフィールド
例えば以下の様なJSONを作りたいとする。obの階層にname,ageという2つのフィールドがある。
{ "ob": { "age": 20, "name": "foo" } }
このとき今までのmkdictでは以下のように記述する必要があった。
$ dictknife mkdict ob/age 20 ob/name foo
joではシェル上で直接ネストして呼び出すことで以下の様に書ける。
$ jo -p ob=$(jo age=20 name=foo)
一方mkdictでは、深い階層のフィールドが単一であれば"/"で繋げていけば良いので ob/name foo みたいに手軽に記述できるのだけれど(よりネストした階層についても ob/father/name bar みたいに)、同じ階層に複数のフィールドをもたせたい時にちょっと不便だった。例えば今回はob/ageとob/nameと毎回共通のprefix(?)を書く必要が出てしまう。
block
そんなわけでblockという概念を導入した。blockは"{"と"}"で記述されるもの。例えば先程のコードをblockを使って記述すると以下の様になる。
# 先程のコード
$ dictknife mkdict ob/age 20 ob/name foo
# blockを使ったコード
$ dictknife mkdict ob { age 20 name foo }
注意点として、"{"と"}"と他の引数との間には必ず空白が必要。シェルのtestコマンドと同様のイメージ(if [ -z "foo" ]のようなもののこと)。
なので以下の様なコードはNG。ただし現状の実装では構文エラーにはならない。
$ dictknife mkdict ob {age 20 name foo }
dictknife mkdict ob { age 20 name foo}
複雑なネストも
もちろん複雑なネストにも対応している。
深いネストでも。
$ dictknife mkdict a/b/c/ob { name foo age 20 }
{
"a": {
"b": {
"c": {
"ob": {
"name": "foo",
"age": 20
}
}
}
}
}
blockの中にblockがあっても。
$ dictknife mkdict a/b { x/ob { name foo age 20 } y/ob { name boo } } id 1
{
"a": {
"b": {
"x": {
"ob": {
"name": "foo",
"age": 20
}
},
"y": {
"ob": {
"name": "boo"
}
}
}
},
"id": 1
}
変数の参照と組わせる
変数の参照と組み合わせると便利。
$ dictknife mkdict @father { name A age 20 } @mother { name B age 20 } { name X age 0 father "&father" mother "&mother" } ";" { name Y age 1 father "&father" mother "&mother" }
[
{
"name": "X",
"age": 0,
"father": {
"name": "A",
"age": 20
},
"mother": {
"name": "B",
"age": 20
}
},
{
"name": "Y",
"age": 1,
"father": {
"name": "A",
"age": 20
},
"mother": {
"name": "B",
"age": 20
}
}
]
ヒアドキュメントでも。
$ dictknife mkdict << EOS
@father { name A age 20 } @mother { name B age 20 }
name X age 0 father "&father" mother "&mother"
name Y age 1 father "&father" mother "&mother"
EOS
まぁヒアドキュメントを使えるような状況なら素直にJSONを書いたほうが良いかもしれない。
導入に伴い変数にスコープを導入
blockの導入に伴い変数にスコープを導入した。一応blockの内部で同名の変数はシャドウイングされるし、外側の環境の変数にアクセスできる。
$ dictknife mkdict @v 10 x0 "&v" x1 { v "&v" } x2 { @v 20 v "&v" } x3 { v "&v" } x4 { v "&v" @v 100 y { v "&v" } } @v 11 x5 "&v"
{
"x0": 10,
"x1": {
"v": 10
},
"x2": {
"v": 20
},
"x3": {
"v": 10
},
"x4": {
"v": 10,
"y": {
"v": 100
}
},
"x5": 11
}