dictknifeのdiffに変更部分見比べられるような機能を追加した。ある意味昨日の以下の記事の続き。
例えば以下の様な2つのJSONがあるとする
00.json
{ "name": "foo", "age": 20 }
01.json
{ "name": "bar", "age": 21 "nickname": "B" }
これを普通にdiffを取ると考えると、通常のdiffコマンドと同様の形式での出力ということになる。
$ dictknife diff 00.json 01.json
--- 00.json
+++ 01.json
@@ -1,4 +1,5 @@
{
- "name": "foo",
- "age": 20
+ "name": "bar",
+ "age": 21,
+ "nickname": "B"
}
今回欲しいのはこれじゃなかった気がした。
例えば、 left, right, right - left と言うような表記
2つのファイル中の項目の数値的な差分が知りたいと言うことがある。例えば、年齢に着目したい場合。このような時に通常の文字列ベースのdiffでは見づらい。そこで --output-format で別のフォーマットで出力できるようにした。
$ dictknife diff 00.json 01.json -o dict
[
{
"name": "name",
"00.json": "foo",
"01.json": "bar",
"diff": "- f- o- o+ b+ a+ r"
},
{
"name": "age",
"00.json": 20,
"01.json": 21,
"diff": 1
},
{
"name": "nickname",
"00.json": null,
"01.json": "B",
"diff": null
}
]
元の値それぞれと比較後の値の3つのデータをそれぞれの項目(dictで言えばkey)毎に表示してくれるようにしたdiff。
加えて比較は以下の様に動く
- int,floatの場合には数値的な差をとる
- noneが含まれていたらnone(NA)
- それ以外はdifflib.ndiff
この表現に昨日のmarkdownでの出力を組み合わせると良い感じに併記して表現ができるようになる。
$ dictknife diff 00.json 01.json -o dict | dictknife cat -i json -o md
結果(比較の表)
| name | 00.json | 01.json | diff |
|---|---|---|---|
| name | foo | bar | - f- o- o+ b+ a+ r |
| age | 20 | 21 | 1 |
| nickname | null | B | null |
文字列の比較が見慣れたunified diff(udiff)の形式ではない理由は1単語毎のdiffを見たい場合にはどのような差分があったか分かりづらかったため。ちなみに完全一致の場合には比較結果は空白文字列としている。
これはこれで処理毎にコマンドがわかれていて、パイプでつなげれば望みの表現が手に入るという形できれい。ただ、めんどくさいのでoutput formatにmdを渡せるようにした。以下でも良い。
$ dictknife diff 00.json 01.json -o md
nestした表現
nestした表現にも対応している。例えば以下の様な表現。motherは共通でfatherが異なるような関係。
$ dictknife diff 020*.json 021*.json -o md
結果(比較の表)。
| name | 020person.json | 021person.json | diff |
|---|---|---|---|
| type | person | person | |
| name | foo | bar | - f- o- o+ b+ a+ r |
| age | 20 | 21 | 1 |
| father/type | rel | rel | |
| father/name | X | Z | - X+ Z |
| mother/type | rel | rel | |
| mother/name | Y | Y |
nestした構造の部分は"/"で繋げた形で表記されている(listの場合はfoo/0/nameみたいな形になる)。
差分が存在しない行は省略するようなオプションを用意しても良いかもしれない。
このときの020person.jsonと021person.jsonはそれぞれ以下の様な形。
020person.json
{ "type": "person", "name": "foo", "age": 20, "father": { "type": "rel", "name": "X" }, "mother": { "type": "rel", "name": "Y" } }
021person.json
{ "type": "person", "name": "bar", "age": 21, "father": { "type": "rel", "name": "Z" }, "mother": { "type": "rel", "name": "Y" } }
別の例
各教科のテストの点数を比べるみたいな時に便利
$ dictknife diff -S -o md xxx.json yyy.json
| name | xxx.json | yyy.json | diff |
|---|---|---|---|
| A | 70 | 60 | -10 |
| B | 70 | 60 | -10 |
| C | 70 | 45 | -25 |
| D | 70 | 70 | 0 |
| E | 70 | 80 | 10 |