vim-users.jp

Vim Advent Calendar 2012 ujihisa 6

Posted at 2013/03/18
このエントリーをはてなブックマークに追加

Vim Advent Calendar 2012 の 108 日目の記事です。 昨日はrcmdnkさんによるVim以外でVimする: Windows編でした。SimCityを無事入手し、それをGentoo Linux上のWineで動作させるため数日間悪戦苦闘し、結局諦めてWindowsを購入しました。しかしオンボードのIntel HD 3000では動作速度が遅く、いまはグラフィックボードの購入を真剣に検討しています。Gentoo Linuxとデュアルブートする予定なので、LinuxからちゃんとGPGPUに使えるようなものにしたいですね。

vitalのData.List.take_while

つい本日、vitalData.List.take_whileという、あるべきはずがなぜかこれまでなかった関数が追加されました。

L.take_while('v:val < 5', [1, 3, 5, 2, 1, 7])
" => [1, 3]

HaskellやClojureなどVim script以外の言語一般に登場する関数で、これは特に無限長のシーケンスをデータ構造としてサポートしている言語で便利です。 上記の例の場合、1 < 5が評価され、3 < 5が評価され、5 < 5が評価され、1と3を集めたものを返すわけですが、ここで大事なのは、2 < 5以降はそもそも計算されないという点です。ですので、安心して重い処理を任せることができます。

Vim scriptでもぜひ活用しましょう。具体的なユースケースとしては、「前半に欲しい情報があって後半に不要な情報があるような出力をする外部プロセスの結果をパースする」ようなときに強さを発揮します。

vital開発方法

今回のData.List.take_whileはいま僕が開発中のプラギンがまさにこの機能を必要としているから実装しました。vitalコミッタに限らず、vimプラギンやvimrcを記述している際に汎用的な処理を見つけた場合、なるべくvitalに委ねるようにしましょう。vital開発チームはpull requestを常に受け付けています。みんなで汎用的な処理を共有し、Vim業界全体に幸福と平穏をもたらしましょう。

vitalの関数はテストコードを記述することがドキュメントを書くことと同程度に推奨されています。テストコードを含む、vital用の関数の追加方法について簡単に説明しましょう。ちょうど先ほど追加したばかりのData.List.take_whileが例になりますね。

まず最初にテストを書きます。このテストは簡単なドキュメントにもなります。

spec/data/list.vim

Context data.list.take_while()
  It creates a list from another one, it inspects the original list and takes from its elements to the moment when the condition fails, then it stops processing
    Should [1, 3] == g:L.take_while('v:val < 5', [1, 3, 5, 2])
    Should [] == g:L.take_while('v:val > 3', [1, 2, 3, 4, 5])
    Should [1, 2] == g:L.take_while('v:val < 3', [1, 2, 3, 4, 5])
  End

  It of course handles list of list.
    should [[1], [2, 3]] ==
          \ g:L.take_while('len(v:val) > 0', [[1], [2, 3], [], [4]])
  End
End

テストを実行し、失敗することを確認します。テストの実行方法についてはvitalのspec/README.mdを参照してください。

つづいて本体を実装します。とりあえず最も単純で、とにかく動作すればよかろうで書きます。

autoload/vital/__latest__/data/list.vim

function! s:take_while(f, xs)
  return s:span(a:f, a:xs)[0]
endfunction

テストが通ることを確認します。

そして

さて、上記実装は大事な要素である「条件を満たさなくなったときは処理を継続せず即座に中断する」という大事な処理が抜けていることに気づかれることと思います。これだと重い処理を安心して任せることができません。

  • 「条件を満たさなくなったときは処理を継続せず即座に中断する」のテストを書く
  • その実装を書く

のpull requestを送ることは、読者への課題とします。

ujihisa

もどる
blog comments powered by Disqus