ruby-list の regexp difference with perl のスレッドを読んでいて思いつ
いたのですが、Perlのt/regexp.tをrubyに移植してみました。

これで、Perlの正規表現のテストケース($PERLSRC/t/op/re_tests)をrubyで使
うことができます。

このスクリプトにperl5.004_65のre_testsを入力として以下のようなrubyの正
規表現のバグが見つかりました。(明確にバグのもののみ)

not ok 186 'ab{4,5}?bc'i:ABBBBC:n:"-":- => -
not ok 307 a(?:b|c|d){2}(.):acdbcdbe:y:$1.to_s:b

バグをみつけるという本来の目的の他に、以下のバグ/悪仕様?がみつかり
ました。

1. 以下のスクリプトでは、GC.disableを各所に入れてあります。これがない
と実行時にSEGVしてしまいます。正規表現の評価中にGCが走るとまずいような
気がします。

2. Perlと違い、rubyでは$.への代入は無視されます。IOのmethodにlineno
とlineno=があると良いと思うのですが、どうでしょう?

--
			   稲葉 浩人 (inaba / st.rim.or.jp)

-----------------------------------------------------------------------------
#!/usr/local/bin/ruby 

# The tests are in a separate file 't/op/re_tests'.
# Each line in that file is a separate test.
# There are five columns, separated by tabs.
#
# Column 1 contains the pattern, optionally enclosed in C<''>.
# Modifiers can be put after the closing C<'>.
#
# Column 2 contains the string to be matched.
#
# Column 3 contains the expected result:
# 	y	expect a match
# 	n	expect no match
# 	c	expect an error
#
# Columns 4 and 5 are used only if column 3 contains C<y> or C<c>.
#
# Column 4 contains a string, usually C<$&>.
#
# Column 5 contains the expected result of double-quote
# interpolating that string after the match.

tfile = ARGV[0] || "re_tests"
tests = open(tfile)

numtests = 0
numtests+=1 while tests.gets

# assign to $. does not work
tests.close
tests = File.open(tfile)

$stdout.sync = true
print "1..#{numtests}\n"

while (tests.gets)
  GC.disable #
  pat, subject, result, repl, expect = $_.split(/[\t\n]/)
  repl.gsub!(/\$(\W|\d+)/) {
    if $` == "" || $`[-2,2] == "\\\\" || $`[-1] != ?\\ 
      '"+' + $& + '.to_s+"' 
    else 
      $& 
    end
  }
  repl.gsub!(/^|$/, '"'); repl.gsub!(/""\+/, ''); repl.sub!(/\+""$/, '')
  input = [pat,subject,result,repl,expect].join(':')
  pat = "'#{pat}'" unless pat =~ /^[:']/
  GC.enable  #

  begin
    match = got = nil # need local vars in eval accessible.
    GC.disable #
    eval "match = (subject =~ %r#{pat}); got = #{repl}"
    GC.enable  #
    case result
    when 'c'
      GC.disable # 1.1b9_21 GC bug!
      print "not ok #{$.} #{input} => #{got}\n"
      GC.enable  #
    when 'n'
      if match
	print "not ok #{$.} #{input} => #{got}\n"
	next
      end
    else
      if (!match || got != expect)
	print "not ok #{$.} #{input} => #{got}\n"
	next
      end
    end
  rescue
    print $!, "\n"
    if result == 'c'
      print "ok? #{$.} #{input}\n"; next
    else
      print "not ok #{$.} #{input}\n"; next
    end
  end
  print "ok #{$.}\n"
end

tests.close

-----------------------------------------------------------------------------