タグジャンプ

久し振りに Ruby に触れていて、色々と Web で検索しているうちに、新たな情報を入手しました。
情報自体は随分と古いものなんですが。

■ Emacs 使いの方へ etags

こちらで、Ruby のコードの TAGS ファイルを作成するスクリプトが紹介されていました。
慌てて man を引いて読み直してみたところ、適切な正規表現を指定すれば何にでも対応できるんですね。これは知りませんでした。英語ドキュメントだとちゃんと読まない (読めない) んですよねえ……
;; 開き直りか ;-p

で、早速作ってみました。
実はこれまで、Ruby でもタグジャンプを使いたいと思いながら、etags コマンドが対応してくれないとダメだと思っていたので、migemo にお世話になりながらコードを書いていたもので。

しかし、etags の正規表現は、特に指定していなくとも行頭からのマッチングになる様 (に見える) で、紹介されているパターンでは、`def', `class' のキーワードが行頭にある定義、つまりトップレベルで定義される関数とクラスにしか合致しませんでした。
その方が良いという考えもあろうかと思いますが、私はモジュールや、入れ子のクラス、メソッド、更にモジュール内の各種定義にも合致して欲しいので、

--regex='/[ \t]*\(def\|class\|module\)[ \t]\([^ \t]+\)/\2/'

の様に指定することにしました。

通常、タグファイルはスクリプトがあるディレクトリに作れば良いのですが、異なるディレクトリごとに毎回タグファイルを作らなければなりません。
その度に shell buffer でコマンドを投入するのは面倒なので、

(defvar etags-tag-rebuild-command-ruby
      (concat "find ./ -name \\*.rb | xargs etags --language=none --regex="
              "'/[ \\t]*\\(def\\|class\\|module\\)[ \\t]\\([^ \\t]+\\)/\\2/'")
      "Ruby スクリプト用のタグファイル作成コマンド。")

としてコマンドラインを定義しておき、

(defun etags-tag-rebuild-ruby (command)
  (interactive
   (list (read-shell-command "Etags command: "
                             etags-tag-rebuild-command-ruby))
   (list etags-tag-rebuild-command-ruby))

  (shell-command command))

なんてコマンドを定義してみました。

M-x etags-tag-rebuild-ruby

とすると、ミニバッファに定義した etags のコマンドが表示されるので、そのままで良ければそのまま C-m します。何か変更を加えたい場合には、その場で変更すれば良いだけです。

本当は、cperl-etags の様に、内部でコマンドを生成して call-process とかしようかとも思ったんですが、これはこれ、その場でコマンドを編集できるのも良いですし、何より簡単なのでこうしてます。
実は、C の TAGS もこんな感じで作ってあり、そちらはもう少し手が込んでます。それを流用しようかとも思ったのですが、そちらはもう随分と昔に定義した関数で、それこそ from scratch で直さないとならない程の代物なもので諦めました。

実はちょっとしたポイントもありまして、XEmacs の etags (コマンドではなく Emacs Lisp パッケージの方) は、`find-etag' などを実行した際、`buffer-tag-table-list' という関数の中で、カレントディレクトリからルートディレクトリまで上位に向って遡り、TAGS ファイルを探してくれます。(FSF Emacs だとどうなんでしょうか。ちょっと違った様な気がしますが……)
そのため、どこかのディレクトリで TAGS ファイルを作成するときに、サブディレクトリまで再帰的に *.rb を探して指定しておくと、それらのファイルを開いたバッファで M-x find-tag するときには、上位ディレクトリで作った TAGS ファイルを勝手に利用してタグジャンプしてくれます。

その様な理由もあって、上の `etags-tag-rebuild-command-ruby' では、find コマンドで下位ディレクトリも含めて *.rb なファイルを探している訳です。