rrencode for 1.9

rrencode は指定された文字列を出力するプログラムを記号だけで合成するプログラム、ですが、Ruby 1.9 では ?. とかが文字列を返すようになってしまったので動きません。
そこで 1.9 用に別の実装を作ってみました。Hello, world! はこちら。

_=[*' '..?~]*'';$><<_[(___=_=~/@/).+_=~/\(/]+_[(__=_=~/_/).+_=~/&/]+_[
__+@@_=_=~/\-/]+_[__+@@_]+_[(@_=_=~/~/)-@@_=_=~/\//]+", "+_[@_.-_=~/'/
]+_[@_-@@_]+_[@_.-_=~/,/]+_[__.+_=~/\-/]+_[__.+_=~/%/]+?!+$/
$ ./ruby
_=[*' '..?~]*'';$><<_[(___=_=~/@/).+_=~/\(/]+_[(__=_=~/_/).+_=~/&/]+_[
__+@@_=_=~/\-/]+_[__+@@_]+_[(@_=_=~/~/)-@@_=_=~/\//]+", "+_[@_.-_=~/'/
]+_[@_-@@_]+_[@_.-_=~/,/]+_[__.+_=~/\-/]+_[__.+_=~/%/]+?!+$/
^D
Hello, world!

以下ソース。

str = "Hello, world!"

# translate
def base(s)
  r = s.dup
  s[/^.(.{2,3})=/] && s.replace($1)
  r
end
def offset(s)
  Regexp.quote([*" "..?~][s]).gsub("/", '\/')
end
b1 = "(__=_=~/_/)"
b2 = "(@_=_=~/~/)"
b3 = "(___=_=~/@/)"
b4 = "(@__=_=~/-/)"
ary = str.scan(/\G(?:[\dA-Za-z]|[^\dA-Za-z]+)/).map do |s|
  case s
  when "a".."n" then [base(b1), "+", offset(s.ord - "a".ord + 2)]
  when "o".."z" then [base(b2), "-", offset("z".ord - s.ord + 4)]
  when "A".."N" then [base(b3), "+", offset(s.ord - "A".ord + 1)]
  when "O".."Z" then [base(b1), "-", offset("Z".ord - s.ord + 5)]
  when "0".."9" then [base(b4), "+", offset(s.ord - "0".ord + 3)]
  else s
  end
end

# cache
table = { nil => [] }
ary.each do |s, o, x|
  if x && table[x]
    table = { x => table[x] + [false] }
  else
    h = table.values.first.dup
    table.values.each {|a| a << false }
    table[x] = h + [true] if x
  end
end

# emit
c = -1
ary = ary.zip(table.values.first).map do |(s, o, x), f|
  case
  when f then c = x; "_[#{ s }#{ o }@@_=_=~/#{ x }/]"
  when c == x then   "_[#{ s }#{ o }@@_]"
  when x then        "_[#{ s }.#{ o }_=~/#{ x }/]"
  else
    s2 = begin; eval("?" + s); rescue SyntaxError; end if s[0] != " "
    s == s2 ? "?" + s : s.dump
  end
end
puts("_=[*' '..?~]*'';$><<" + [*ary, "$/"].join("+"))