新井です。

つい最近、ハマッたのですが"!"が付かないStringのメ
ソッドは、*変更がなされない場合に*レシーバそのもの
を返すんですね。

["foo", "BAR"].each {|src|
    dest = src.upcase
    printf "%x -> %x\n", src.id, dest.id
}

=>
2007de30 -> 2007de08	# 新しいオブジェクトを生成
2007de26 -> 2007de26	# 同じオブジェクト

! が付かないStringのメソッドの戻りは常にコピーだと
信じてたため、不用意に上記で言うところの dest に対
して、gsub! したときにsrc が変わってしまいました。

マニュアル:

| 						`!'のついていない同じ名
| 前のメソッドは文字列のコピーを作ってそちらを更新しますのでやや遅いです
| が,より安全です.例えば:


FAQ:

| 7.19 subとsub!はどう違うのですか 
| 
| subの場合はレシーバの状態は変化せず,コピーにsubが施されます. 

ドキュメント上は、str.dup.sub!() なイメージで書か
れてる(と私は受け取った)ので、結構現在の仕様に気が
付いてない人は多いのでは?と思いました。

で、仕様変更(常に新しいオブジェクトを生成)または
現仕様のドキュメントへの明記をお願いしたいのですが、
いかがでしょう?