7日間で7つのgemをリリースした

https://github.com/ksss/kor

https://github.com/ksss/kor-input-json

https://github.com/ksss/kor-output-json

https://github.com/ksss/kor-input-ltsv

https://github.com/ksss/kor-output-ltsv

https://github.com/ksss/kor-input-yaml

https://github.com/ksss/kor-output-yaml

すべてkorとそのプラグイン

これでデフォルトを含め、6種類づつinput/output形式ができたので、 csv->csvなどの同形式変換をのぞいて、62 - 6 = 30パターンのテーブル形式変換が可能になった。

つまりこれだけのデータ変換プログラムをkorでまかなうことができる。

irb> puts %w(csv tsv markdown json ltsv yaml).permutation(2).map{|k,v| "#{k} => #{v}"}
#=>
csv => tsv
csv => markdown
csv => json
csv => ltsv
csv => yaml
tsv => csv
tsv => markdown
tsv => json
tsv => ltsv
tsv => yaml
markdown => csv
markdown => tsv
markdown => json
markdown => ltsv
markdown => yaml
json => csv
json => tsv
json => markdown
json => ltsv
json => yaml
ltsv => csv
ltsv => tsv
ltsv => markdown
ltsv => json
ltsv => yaml
yaml => csv
yaml => tsv
yaml => markdown
yaml => json
yaml => ltsv

例えば、一昔前にはやった、ltsvをyamlに変換して見やすくするようなプログラムも、korで実現できる。

tail -f access.log | kor --sync ltsv yaml

実装小話

いくつかkorプラグインを書いてみて、input pluginが重要になる設計になっていることがわかった。 例えば、jsonからcsvに変換する場合は、以下のようになることが期待される。

{"foo": 1}
{"bar": 2}
{"baz": 3}
foo,bar,baz
1,,
,2,
,,3

korでは中間形式として、ヘッダー部はヘッダーのみの配列、値部は値のみの配列。というようにして、 値は一行読み込んだら(input)一行出力(output)する。を基本にしている。*1

このようなjson列の場合、 csvの最初のキー列に、何を表示すればいいかは、json列を最後まで読んでみなければわからない。 ヘッダー部の配列が全データを読み込むまで決まらない状態になる。

全部読んでから全部変換するような単純な実装だと、 tail -fなどのパイプが繋がりっぱなしになるストリームでは延々と読み込み続け、変換できなくなってしまう。

そこで、kor-input-(json|ltsv|yaml)では、guess機能をつけた。*2 これによって、数行読み込んで登場してきたキーを、すべてのキーとして、移行のデータを順次処理できるようにした。

「毎行毎行、keyとvalueのセットを中間形式にすればいいんじゃ?」とも思いついたんだけど、 この場合はoutput部分で、やはりcsvのヘッダーが最後まで決まらず、問題がinput側からoutput側に移ってしまうだけということがわかってやめた。

guess機能があれば、とりあえずは大丈夫そうだ。

また、最初っから「キーはこれだよ」と教えてあげる機能を各pluginにつけているけど、毎回つけるのがめんどくさいので、kor本体でフィルター機能をつけるのもありかもしれない。もちろんguess機能も。

パフォーマンス面も手付かずなので改善の余地はたくさんある。たとえばoutputがI/O負荷でブロックされていても、変換処理は非同期で進めておければ時間短縮になりそう。

そんな感じでどんどんアイデアが出てくるので、しばらくはこれで遊べそう。*3

参考記事

http://www.embulk.org/docs/index.html

http://d.hatena.ne.jp/naoya/20130209/1360381374

*1:yamlが例外

*2:名前がembulk丸パクリなんだけど、embulkをさわったことはない……。

*3:あきやすいタイプ。