ハッシュを使ってString#gsubする

Rubyで書かれたTwitterクライアント「Earthquake」から。ext.rbを見ると、いろいろ標準クラスやライブラリを拡張してるのだけど、Stringのところで、へぇと思った。

class String
  def c(*codes)
    codes = codes.flatten.map { |code|
      case code
      when String, Symbol
        Earthquake.config[:color][code.to_sym] rescue nil
      else
        code
      end
    }.compact.unshift(0)
    "\e[#{codes.join(';')}m#{self}\e[0m"
  end

  def coloring(pattern, color = nil, &block)
    self.gsub(pattern) do |i|
      applied_colors = $`.scan(/\e\[[\d;]+m/)
      c = color || block.call(i)
      "#{i.c(c)}#{applied_colors.join}"
    end
  end

  t = {
    ?& => "&",
    ?< => "&lt;",
    ?> => "&gt;",
    ?' => "&apos;",
    ?" => "&quot;",
  }

  define_method(:u) do
    gsub(/(#{Regexp.union(t.values)})/o, t.invert)
  end

  define_method(:e) do
    gsub(/[#{t.keys.join}]/o, t)
  end
end

String#gsubの2つ目の引数にはハッシュが渡せて、もしマッチした文字列がハッシュのキーにあれば、それに対応するバリューを返すという仕様がある。知らんかった。Ruby便利だな。

なんで、わざわざ「def」じゃなくて、「define_method」で下の2つのメソッドを定義してるんだろうと思ったけど、これはtのスコープの問題か。でも、それならtじゃなくてString#TABLEとかの定数にすればいいような。