原です。

以下のコードを実行してみると、

-------------^ test.rb
#!/usr/local/bin/ruby
class FooError < Exception
end

class BarError < Exception
end

def foo
  fail FooError, "foo failed."
end

def bar
  begin
    foo
  rescue
    fail BarError, $!
#    fail BarError, "bar->" + $!
#    fail "bar->" + $!
  end
end

begin
  bar
rescue FooError
  print "FooError: #$!\n"
rescue BarError
  print "BarError: #$!\n"
rescue
  print "RuntimeError: #$!\n"
end
-------------$ test.rb

結果は、

FooError: foo failed.

となります。本来は

BarError: foo failed.

ですよね。ちなみに下にコメントしてある

    fail BarError, "bar->" + $!

に替えるとちゃんと

BarError: bar->foo failed.

と出ます。


ついでに一つ提案なんですが、rescue 節の

fail

は、直前の例外の再発生ですよね。現在

fail "string"

では、RuntimeError を発生しますが、これを直前の error_type の
再発生(でメッセージを "string" にしたもの)にする手もあるか
と思うのですがいかがでしょう。