はじめまして、山本です。

このたび、File.fnmatch を改良してみたのですが、ruby-talk でも ruby-dev でもあまりレスがありませんでした。
(ruby-talk ではGavinからレスをいただきました。SUSv3準拠に好意的でした)
(ruby-dev ではまつもとさんからレスをいただきました。
  SUSv3準拠はまだ理解できるが、FNM_SEPMATCH(後述)の導入には抵抗があるそうです)

二人の意見しか聞けないのでは、あきらめることも採用を主張することも難しいので、ruby-listに投稿することに
しました。よろしくお願いします。

CVS-HEAD の dir.c(Rev1.109) に置き換えて試せるものを

  http://www.ccsnet.ne.jp/~ocean/23115/dir.c

に、CVS-HEAD がなくても挙動を試せるものを

  http://www.ccsnet.ne.jp/~ocean/23030/fnmatch.c

に用意しています。

仕様は次のとおりです。

  ・パターンマッチは SUSv3 (Single Unix Specification ver3) に準拠している

  ・パスセパレータは '/' だけ受け入れる。これは DOSISH のとき、パターンで、エスケープ文字とパス区切りの
    競合が起きていたための措置で、次のようにすることはできます。
    => File.fnmatch(pattern, string) で pattern では '/' だけしか使えないが、string ではプラットホーム依存の
       パス区切りを使えるようにする

  ・FNM_PATHNAME を廃止して、逆の意味の FNM_SEPMATCH を導入する。理由は、シェルやDir.globとデフォルトの動作を
    あわせるため。FNM_DOTMATCH との対比もよい。

  > [ruby-dev:16555]
  >
  >* 利用者は、シェルのパターンマッチの挙動をまず意図しそう。
  >
  >    p File.fnmatch("a*/c", "a/b/c")
  >    => true
  >
  >    あれ?っとなりそう。

  ・FNM_SEPMATCH が指定されていないとき、'**/' が File.fnmatch でも使えるようになった


この変更について、ご意見をお寄せください。

//-----------------------------------------------------------------------------------
// FNM_SEPMATCH がないときのパターンマッチルール
//-----------------------------------------------------------------------------------

  ・ワイルドカードが '/' にマッチしない

    File.fnmatch('*', 'a/b')   #=> false
    File.fnmatch('a?b', 'a/b') #=> false

  ・'/' を領域指定に含むことはできない。'[a/c]' は '[a' ディレクトリの下の 'c]' と解釈される。

    File.fnmatch('[a/c]', 'a')     #=> false
    File.fnmatch('[a/c]', '/')     #=> false
    File.fnmatch('[a/c]', 'c')     #=> false
    File.fnmatch('[a/c]', '[a/c]') #=> true

  ・'**/'が使えるようになった

    File.fnmatch('**/c', 'a/b/c') #=> true

  ・File::FNM_DOTMATCH がないと、ワイルドカードが「文字列の先頭の '.'」と「'/' の直後の '.'」にマッチしない

    File.fnmatch('*', '.b')                         #=> false
    File.fnmatch('*', '.b', File::FNM_DOTMATCH)     #=> true
    File.fnmatch('a/*', 'a/.b')                     #=> false
    File.fnmatch('a/*', 'a/.b', File::FNM_DOTMATCH) #=> true

//-----------------------------------------------------------------------------------
// FNM_SEPMATCH があるときのパターンマッチルール
//-----------------------------------------------------------------------------------

  ・ワイルドカードは '/' にもマッチする

    File.fnmatch('*', 'a/b', File::FNM_SEPMATCH)   #=> true
    File.fnmatch('a?b', 'a/b', File::FNM_SEPMATCH) #=> true

  ・'/' も領域指定に含むことができる。'[a/c]' は 'a' or '/' or 'c' と解釈される。

    File.fnmatch('[a/c]', 'a', File::FNM_SEPMATCH)     #=> true
    File.fnmatch('[a/c]', '/', File::FNM_SEPMATCH)     #=> true
    File.fnmatch('[a/c]', 'c', File::FNM_SEPMATCH)     #=> true
    File.fnmatch('[a/c]', '[a/c]', File::FNM_SEPMATCH) #=> false

  ・File::FNM_DOTMATCH がないと、ワイルドカードが「文字列の先頭の '.'」にマッチしない

    File.fnmatch('*', '.b', File::FNM_SEPMATCH)                          #=> false
    File.fnmatch('*', '.b', File::FNM_SEPMATCH | File::FNM_DOTMATCH)     #=> true
    File.fnmatch('a/*', 'a/.b', File::FNM_SEPMATCH)                      #=> true

//-----------------------------------------------------------------------------------
// 領域指定について ('[' と ']')
//-----------------------------------------------------------------------------------

  ・'[' と ']' の間では、FNM_NOESCAPE の有無にかかわらず、エスケープは効かない。
    '[\*]' は、常に '\' or '*' となる

  ・領域指定に ']' を含めたい場合は、先頭に置く
    '[]ab]' は ']' or 'a' or 'b' となる

  ・領域指定に '-' を含めたい場合は、先頭か最後に置く
    '[-ab]' と '[ab-]' は 'a' or 'b' or '-' となる

  ・'[a-b-c]' のように '-' でつなぐパターンは SUSv3 では未定義
    この実装では '[a-bb-c]' と解釈している

  ・FNM_DOTMATCH がないときに、明示的に '.' を含む領域指定が '.' にマッチすべきかは SUSv3 では未定義
    この実装ではマッチしない