山本です。

Dir.glob の '{ }' で、エスケープと、入れ子の '{ }' が正しく動いてないようです。

  E:\ruby-cvs>miniruby.exe -v
  ruby 1.9.0 (2004-04-08) [i386-bccwin32]

  E:\ruby-cvs>touch ,
  Touch  Version 4.2  Copyright (c) 1998 Borland International

  E:\ruby-cvs>miniruby.exe -e "puts Dir.glob('{\,}')"

  E:\ruby-cvs>miniruby.exe -e "puts Dir.glob('{mi{ni{ruby}.e}xe}')"

こうなるべきように思います。

  E:\ruby-cvs\ruby>touch ,
  Touch  Version 4.2  Copyright (c) 1998 Borland International

  E:\ruby-cvs\ruby>miniruby.exe -e "puts Dir.glob('{\,}')"
  ,

  E:\ruby-cvs\ruby>miniruby.exe -e "puts Dir.glob('{mi{ni{ruby}.e}xe}')"
  miniruby.exe

この解釈で間違いないでしょうか?

まだ十分な検証をしてませんが、一応動いているパッチを添付します。(少しリファクタリングもしました)

# あと、rb_glob と File.fnmatch は '{ }' をサポートしていませんが、サポートしたほうがいいでしょうか?

Index: dir.c
===================================================================
RCS file: /ruby/ruby/dir.c,v
retrieving revision 1.117
diff -u -w -b -p -r1.117 dir.c
--- dir.c	12 Apr 2004 01:45:08 -0000	1.117
+++ dir.c	12 Apr 2004 10:36:30 -0000
@@ -1392,82 +1392,73 @@ push_pattern(path, ary)
 }
 
 static int
-push_globs(ary, s, flags)
+push_glob(ary, s, flags)
     VALUE ary;
     const char *s;
     int flags;
 {
-    return rb_glob2(s, flags, push_pattern, ary);
-}
+    const int escape = !(flags & FNM_NOESCAPE);
 
-static int
-push_braces(ary, s, flags)
-    VALUE ary;
-    const char *s;
-    int flags;
-{
-    char *buf, *b;
-    const char *p, *t;
-    const char *lbrace, *rbrace;
+    const char *p = s;
+    const char *lbrace = 0, *rbrace = 0;
     int nest = 0;
     int status = 0;
 
-    p = s;
-    lbrace = rbrace = 0;
     while (*p) {
 	if (*p == '{') {
-	    lbrace = p;
-	    break;
-	}
-	Inc(p);
+	    if (!lbrace) lbrace = p;
+	    nest++;
     }
-    while (*p) {
-	if (*p == '{') nest++;
-	if (*p == '}' && --nest == 0) {
+	else if (*p == '}') {
+	    if (!lbrace) return status; /* invalid */
+	    if (--nest == 0) {
 	    rbrace = p;
 	    break;
 	}
+	}
+	else if (*p == '\\' && escape) {
+	    if (!*++p) break;
+	}
 	Inc(p);
     }
 
     if (lbrace && rbrace) {
-	int len = strlen(s);
-	buf = xmalloc(len + 1);
+	char *buf, *b;
+	buf = xmalloc(strlen(s) + 1);
 	memcpy(buf, s, lbrace-s);
 	b = buf + (lbrace-s);
 	p = lbrace;
-	while (*p != '}') {
-	    t = Next(p);
-	    for (p = t; *p!='}' && *p!=','; Inc(p)) {
-		/* skip inner braces */
-		if (*p == '{') while (*p!='}') Inc(p);
+	while (p < rbrace) {
+	    const char *t = ++p;
+	    nest = 0;
+	    while (p < rbrace && !(nest == 0 && *p == ',')) {
+		if (*p == '{') nest++;
+		else if (*p == '}') nest--;
+		else if (*p == '\\' && escape) {
+		    p++;
+		}
+		Inc(p);
 	    }
 	    memcpy(b, t, p-t);
-	    strcpy(b+(p-t), Next(rbrace));
-	    status = push_braces(ary, buf, flags);
+	    strcpy(b+(p-t), rbrace + 1);
+	    status = push_glob(ary, buf, flags);
 	    if (status) break;
 	}
 	free(buf);
     }
-    else {
-	status = push_globs(ary, s, flags);
+    else if (!lbrace && !rbrace) {
+	return rb_glob2(s, flags, push_pattern, ary);
     }
 
     return status;
 }
 
-#define isdelim(c) ((c)=='\0')
 static VALUE
-rb_push_glob(str, flags)
+rb_push_glob(str, flags) /* '\0' is delimiter */
     VALUE str;
     int flags;
 {
     const char *p, *pend;
-    char *buf;
-    const char *t;
-    int nest, maxnest;
-    int status = 0;
-    int escape = !(flags & FNM_NOESCAPE);
     VALUE ary;
 
     if (rb_block_given_p())
@@ -1476,39 +1467,18 @@ rb_push_glob(str, flags)
 	ary = rb_ary_new();
 
     FilePathValue(str);
-    buf = xmalloc(RSTRING(str)->len + 1);
 
     p = RSTRING(str)->ptr;
     pend = p + RSTRING(str)->len;
 
     while (p < pend) {
-	nest = maxnest = 0;
-	while (p < pend && isdelim(*p)) p++;
-	t = p;
-	while (p < pend && !isdelim(*p)) {
-	    if (*p == '{') nest++, maxnest++;
-	    if (*p == '}') nest--;
-	    if (escape && *p == '\\') {
-		p++;
-		if (p == pend || isdelim(*p)) break;
-	    }
-	    Inc(p);
-	}
-	memcpy(buf, t, p - t);
-	buf[p - t] = '\0';
-	if (maxnest == 0) {
-	    status = push_globs(ary, buf, flags);
-	    if (status) break;
-	}
-	else if (nest == 0) {
-	    status = push_braces(ary, buf, flags);
-	    if (status) break;
-	}
-	/* else unmatched braces */
-    }
-    free(buf);
-
+	const char *t;
+	int status;
+	for (t = p; t < pend && !*t; ++t);
+	for (p = t; p < pend &&  *p; ++p);
+	status = push_glob(ary, t, flags);
     if (status) rb_jump_tag(status);
+    }
 
     return ary;
 }