NeoBundleの依存関係を設定した際の挙動を調べた話

※2013/2/10 8:33 この記事の内容は誤りです。dependsにはNeoBundleコマンドと同じ内容を書くのが正しく、以下の例では'A/plugin_a'と書くのが正しいです。現在は修正されており、正常に依存先が読み込まれます。


Vimプラグインを管理するNeoBundleというプラグインがあります。
NeoBundleにはプラグインの依存関係を設定することが可能なのですが、いまいち思ったとおりに動いていなかったので色々調べてみました。

概要

まず前提。
・2人の開発者がVimプラグインを開発しているとします。
・開発者はそれぞれA、Bとします。
・Aさんが開発するプラグインは'plugin_a'、Bさんが開発するプラグインは'plugin_b'とします。
・それぞれのプラグインgithub上で公開されており、登録時にアドレスの省略が可能とします。
・読み込みは遅延します。
・plugin_bはplugin_aに依存しています。つまり、plugin_bを使うにはplugin_aを予め入れておく必要があります。
→ plugin_bを読み込むと、自動でplugin_aも読み込んでほしい。

これを設定しようとした場合、以下のように書いていました。

NeoBundleLazy 'A/plugin_a'
NeoBundleLazy 'B/plugin_b', {'depends' : 'A/plugin_a'}


vimrc読書会にある何人かのvimrcを見てもこう書いているので、ほとんどの方がこう書くのが正しいと認識しているのでしょう。*1
しかしこう書いてもdependsによってプラグインが読み込まれていなかったのです。


結論を先に書くと、'depands'には以下の様にプラグイン名を設定する必要があります。

NeoBundleLazy 'B/plugin_b', {'depends' : 'plugin_a' }

勘違い

その前に、調査中にした自分の勘違いも書いておきます。
兎にも角にもNeoBundleのソースコードを読まないことには始まりません。
そこで、以下の行を発見しました。(既に修正済みです。)

neobundle/config.vim の neobundle#config#source(names)

    call s:rtp_add(bundle)

    call neobundle#config#source_bundles(bundle.depends)

現在のプラグインをrtpに追加してから依存先を読み込んでいます。
たぶんこれが原因じゃないかという思い込みが入り、入れていた回避策をそのままに動作確認したおかげで、ここが原因だろうという勘違いをしてしまいました。
この部分は今回の件とは一切関係なく、変更しなくても今のところ特に問題は発生しません。
その点でShougoさんには余計な時間を取らせて申し訳なく思います。
ただ、rtpの設定後に依存先を読み込むのは想定した動作ではなかったらしく、その点に関してはよかったです。

改めて調査

vim力の低い自分はprintfデバッグ以外の方法は知らないので、ひたすらそれらしい所にechomsgを追加しました。


まずおおまかな処理の流れは以下のようになっています。
トリガーとして、あるプラグインを読み込む

あるプラグインをrtpに登録する前に、依存先の名前一覧('depends'の値)からプラグインを読み込む

読み込み処理において、依存先の名前から該当するプラグインの内部のデータ一覧を取得する

それぞれ依存先をrtpに登録する前に、依存先の依存先の名前一覧から ... 以下再帰的に繰り返し


3番目の"依存先の名前一覧から内部のデータを取得する"ですが、まずこのデータについて。
NeoBundle(Lazy|Fetch)コマンドで登録されたプラグインの名前、リポジトリへのURL、依存先の一覧等々を持っています。
そして、この処理は neobundle#config#search(bundle_names) という関数によって行われています。


この関数名からわかるように、登録されているプラグイン一覧から名前が一致するものを検索しています。
そう、名前です。


では、プラグインの名前とは何でしょうか。
決してリポジトリへのURLや省略形式ではなく、そのままプラグインです。
もう一度言いますがプラグインです。
改めて間違った方の設定を見てみましょう。

NeoBundleLazy 'A/plugin_a'
NeoBundleLazy 'B/plugin_b', {'depends' : 'A/plugin_a'}

plugin_bの'depends'に設定しているのは'A/plugin_a'です。
'A/plugin_a'とはプラグイン名ではなくリポジトリの省略形式です。
このため、neobundle#config#search(bundle_names)において名前が一致するわけがなく、もちろん読み込みも行われません。


正しく依存関係設定するには、先に書いた結論の通りです。

余談1

誰かvim scriptのデバッグのやりかたを教えてください。

余談2

間違った方の設定でも、どこかのタイミングでrtpには追加されているようで、plugin_aのコマンド等は実行可能でした。
ただ、なぜかhook.on_sourceは呼ばれません。
今回はhook.on_sourceで設定している部分が反映されていなかったため違和感があり気づいたのですが、
特に設定していない場合は違和感なく使えるのでほとんどの人が気付かないままだったのだろうと思います。
どのタイミングでrtpに追加され、なぜhook.on_sourceが呼ばれないのか気がかりですが、これ以上は調査する気力が湧かないです。はい。

*1:まぁ自分参加したことないですが