enhanced-ruby-modeの概説

  • 25
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

enhanced-ruby-modeはEmacsのメジャーモードのひとつ。標準で付属しているruby-modeの代替を目指して開発されている。Ripper(Rubyの標準添付ライブラリ)によって構文解析を行うのが特徴。

機能

  • インデント
  • シンタックスハイライト
  • リアルタイムの文法チェック

よいところ

Ripperを使っているので、厳密な構文解析を行わないruby-modeではパースに失敗するコードでも正しく扱うことができる。

わるいところ

  • たまにパースが止まる。

ruby-modeとの互換性

  • enh-ruby-forward-sexp, enh-ruby-backward-sexpなどのコマンドの振る舞いがruby-modeと異なる。
  • シンタックスハイライトの色の対応が一部異なる。

開発状況

2010年にGeoff Jacobsen氏によってjacott/Enhanced-Ruby-Modeで開発が始められ、2012年ごろまで同氏によってメンテナンスされていた。現在はRyan Davis氏によるforkを中心に開発が進められている。

インストール方法

Emacs 24以降ならパッケージマネージャーを使ってインストールできる。

package-archivesMELPAを追加していない場合は追加する。

(add-to-list 'package-archives
  '("melpa" . "http://melpa.milkbox.net/packages/") t)

M-x package-install enh-ruby-modeを実行するとインストールできる。

どういう仕組みなのか

ソースコードをerm_buffer.rbのErmBuffer::Parserで処理すると、インデントの開始・終了位置やハイライトの開始・終了位置を示すS式が出力される。EmacsはそのS式に従ってインデントやハイライトを施す。

ruby/erm_buffer.rbについて

Ripperを利用してRubyのコードをパースしている。

RipperはSAX風のイベントドリブン型インターフェイスを基本に構築されている(Ripper.sexpRipper.lexの出力結果もイベントドリブン型のインターフェースを利用して生成されている)。Ripperのイベントには、字句解析によって発生するscanner event(Ripper::PARSER_EVENTS)と、構文解析によって発生するparser event(Ripper::SCANNER_EVENTS)の二種類がある。

構文解析ベースのparser eventでは一部のトークンが捕捉できないので、enhanced-ruby-modeはparser eventではなくscanner eventを利用している。scanner eventの情報だけでは正確なシンタックスハイライトやインデントができないため、erm_buffer.rb側で部分的に構文解析を行なっている。

ErmBuffer::Parser#parseで初期化されているインスタンス変数は自前の構文解析のために使われているが、

  • 変数名から役割が推測しづらい
  • しばしば複数のメソッドから操作されていて全体像を理解しづらい
  • Ripperのscanner eventの挙動を把握していないとコードの意図を理解するのが難しい箇所がいくつかある
  • コメントがほとんどない

などの理由から、解読するのに手間が掛かる。以下で構文解析に関わる一部のインスタンス変数の役割を説明する。

@modeとは

Ripperのscanner eventを補正するために使われる。詳しくはRubyのコードをパースするライブラリのscanner eventについての説明を参照。

@blockとは

同じくscanner eventの補正のために使われる。ブロックの仮引数を囲む|on_opに分類される問題に対応するためのフラグ。

@statment_startとは

while, until, rescueなどのキーワードが後置修飾かどうかを確認するために使われる。while ok?; do(something); endのようにブロックを取る場合にはインデントを1つ深くし、do(something) while ok?のような後置修飾ではインデントはそのままにする。

現在の実装では、下記のように条件式の部分で入れ子になった場合には正常に検出できない。実用上は問題ないと思われる。

while until condition
      end
end

インデントの種類

  • d - do
  • e - end
  • c - method.chain