matchdata-highlight
正規表現のマッチ結果(Ruby の MatchData)に highlight メソッドを生やす小さな gem です。マッチした箇所の前後にマーカー文字列を挿し込んだ文字列を返します。マーカーを省略すると term/ansicolor の ANSI エスケープシーケンスが入り、ターミナル上でマッチ箇所が赤く表示されます。
ライブラリ本体は 1 ファイル約 40 行で、ソース末尾に呼び出し例がコメントで残っています。
puts "foobar foobar BAZ".match(/(foobar)/).highlight
puts /foobar/.match("foobar foobar BAZ").highlight("<B>", "</B>")
puts /foobar/.highlight("foobar foobar BAZ")
puts /foobar/.highlight("foobar foobar BAZ", :begin => '<B>', :end => '</B>')
puts /foobar/.highlight("foobar foobar BAZ", '<B>', '</B>')
内部設計
MatchData と Regexp の 2 クラスへのモンキーパッチだけでできています。処理の流れです。
- MatchData#highlight — 引数の形だけを判定する入口です。引数なしか Hash ならそのまま、位置引数 2 つなら
{:begin => args[0], :end => args[1]}に詰め替えて_highlightに渡します - MatchData#_highlight — 実体です。マーカーのデフォルトは
:beginがTerm::ANSIColor.red、:endがTerm::ANSIColor.clearで、渡されたオプションをmergeして上書きします - マーカーの挿入は、対象文字列(
MatchData#string)をdupした上で、buf[self.begin(0), 0] = marker_beginとマッチ開始位置への幅ゼロ代入で行います。終了マーカーの挿入位置はself.end(0) + marker_begin.sizeで、先に挿し込んだ開始マーカーの分だけ後ろにずらしています - 位置は
begin(0)/end(0)、つまりマッチ全体だけを対象にしていて、キャプチャグループ単位のハイライトや複数マッチの一括ハイライトはしません - Regexp#highlight(target, *args) —
self.match(target)を試して、マッチしたらMatchData#highlightに委譲、マッチしなければtargetをそのまま返します。マッチの有無を気にせず文字列が返ってくる形です - gem の骨組みは jeweler 生成の雛形です(gemspec は Rakefile から生成、バージョン 0.1.0)。README は雛形のままで、テストも shoulda の雛形が残っています