成瀬です。

Ruby スレッドで出ていた話題なのですが、現在の String#gsub がブロックを受
け取った時、ブロックには $& が渡されています。

"abcdefg".gsub(/(.).(.)/){|m|p m; m}
"abc"
"def"
=> "abcdefg"

これだと、事実上ブロックパラメータは使い物にならないので、MatchData を渡
すようにしませんか。

"abcdefg".gsub(/(.).(.)/){|m|p m; m}
#<MatchData "abc" 1:"a" 2:"c">
#<MatchData "def" 1:"d" 2:"f">
=> "abcdefg"

気になるのは互換性ですが m.to_s は 今までの $& と一致するので、
"abcdefg".gsub(/(.).(.)/){|m| m+","} はさすがにエラーが出ますが、
"abcdefg".gsub(/(.).(.)/){|m| "%s," % m} なら今まで通り動きますし、
そもそもおそらくほとんどの現在のコードは、
"abcdefg".gsub(/(.).(.)/){$&+","} でしょう。


--- string.c    (revision 15354)
+++ string.c    (working copy)
@@ -2739,7 +2739,7 @@ rb_str_sub_bang(int argc, VALUE *argv, V
            char *p = RSTRING_PTR(str); long len = RSTRING_LEN(str);

            rb_match_busy(match);
-           repl = rb_obj_as_string(rb_yield(rb_reg_nth_match(0, match)));
+           repl = rb_obj_as_string(rb_yield(match));
            str_mod_check(str, p, len);
            str_frozen_check(str);
            rb_backref_set(match);
@@ -2876,7 +2876,7 @@ str_gsub(int argc, VALUE *argv, VALUE st
        regs = RMATCH(match)->regs;
        if (iter) {
            rb_match_busy(match);
-           val = rb_obj_as_string(rb_yield(rb_reg_nth_match(0, match)));
+           val = rb_obj_as_string(rb_yield(match));
            str_mod_check(str, sp, slen);
            if (bang) str_frozen_check(str);
            if (val == dest) {  /* paranoid check [ruby-dev:24827] */

-- 
NARUSE, Yui  <naruse / airemix.com>
DBDB A476 FDBD 9450 02CD 0EFC BCE3 C388 472E C1EA