CoffeeScriptとかjavascriptでワイルドカードを正規表現に書き換える

#続き書いた
下記で言及した[FileList作ってみた](http://qiita.com/mrpepper/items/349d8ff786c0a4fa8945)

#前置き
なんか、Grunt, Gulp界隈、「タスクランナー疲れ」みたいなポストがちらほらありますな。それに乗じて（笑）[rakeを勧めている人](http://qiita.com/doloopwhile/items/6088ad6c1753806da7c0)なんかもいらっしゃいますが、

「Perl, Ruby, Python はどれかひとつ覚えときゃいい」
「ほほう。じゃ、Perl分かるからスキップでいっか」

と何気なくRuby, Pythonをスルーしてしまったおじさんには悲しいのだ。と言うわけで、タスクランナーなんて使わずに、ちょっとした便利関数をrequireして、

forever start -c coffee /path/to/tools/automake.coffee

でいいんじゃね？（もちろん、automake.coffeeがタスクランナーっちゅうか、自製生書き監視＆タスク管理スクリプトだよ）

で、そういうことをしようとすると、その「ちょっとした便利関数」にrakeっぽいFileListとか、run(target, depedencyfiles, {watch: on}, func)みたいなのが欲しくなる。まあ、ちょろちょろと空き時間に書いてアップしようと思うが、それで良くないかい？

#そのための最初の「ちょっとした便利関数」
とりあえず、FileList作るんなら、ワイルドカード欲しいよね。asterisk, globstar, question, bracket, braceが使えればそれで良いよね。変換ルールは下記

<dl>
  <dt>正規表現と被る表記全部</dt>
  <dd>エスケープしといた</dd>
  <dt>*</dt>
  <dd>[^/]* パス区切り以外の全ての0回以上繰り返し</dd>
  <dt>**</dt>
  <dd>.* パス区切りを含めた全ての0回以上繰り返し</dd>
  <dt>?</dt>
  <dd>[^/] パス区切り以外の全て（1文字）</dd>
  <dt>{foo,bar}</dt>
  <dd>(foo|bar) 選択</dd>
  <dt>[a-z]</dt>
  <dd>[a-z] つーか、触ってない！</dd>
  <dt>文末</dt>
  <dd>$ ワイルドカードの意味って、後方一致だよね</dd>
</dl>

あれ？ どこぞのシェルとかツールに採用されてる globstar「\*\*」って、/path/\*\*/hoge と書いたら /path/hoge にマッチすんの？　するとしたらこれじゃ違うね。まあ、そこは突っ込みがあれば直す感じ。なんかシェルによって違うとかちらっと聞いたけどさ。

なんだかんだ言って直した方がよさげなので、/path/\*\*/hoge と書いたら /path/hoge にマッチするようにした。

とゆーわけで、こいつだ。一般性が高いので、Javascript版も載せとくよ。

```CoffeeScript:wildcard.coffee
y_combi = (func) ->
  return ((p) ->
    return () ->
      return func(p(p)).apply(this,arguments)
  )((p) ->
    return () ->
      return func(p(p)).apply(this,arguments)
  )


braces2parentheses = y_combi (func) ->
  return (str) ->
    dst = str
    result = str.match(/^([^\{]*)\{([^\}]*)\}(.*)$/)
    if result?
      dst = result[1]+'('+result[2].split(',').join('|')+')'+func(result[3])
    return dst


wildcard2regexstr = (str) ->
  str = str.replace /\\/g,'\\\\'
  str = str.replace /\+/g,'\\+'
  str = str.replace /\./g,'\\.'
  str = str.replace /\(/g,'\\('
  str = str.replace /\)/g,'\\)'
  str = str.replace /\^/g,'\\^'
  str = str.replace /\$/g,'\\\$'
  str = str.replace /\|/g,'\\|'
  str = braces2parentheses str
  str = str.replace /\?/g,'[^/]'
  str = str.replace /<</g,'<<2'
  str = str.replace /<<</g,'<<3'
  str = str.replace /\/\*\*\//g,'(/.<<</|/)'
  str = str.replace /\*/g,'[^/]+'
  str = str.replace /<<</g,'*'
  str = str.replace /<<2/g,'<<'
  str = str.replace /<<3/g,'<<<'
  str += '$'

wildcard2regex = (str) ->
  return new RegExp(wildcard2regexstr str)

#test

testtext = "src/*.{js,coffee}"
console.log testtext
regexstr = wildcard2regexstr testtext
regex = new RegExp(regexstr)
console.log regexstr
```

こっちがJavascript版。

```javascript:wildcard.js
  var y_combi = function(func) {
    return (function(p) {
      return function() {
        return func(p(p)).apply(this, arguments);
      };
    })(function(p) {
      return function() {
        return func(p(p)).apply(this, arguments);
      };
    });
  };

  var braces2parentheses = y_combi(function(func) {
    return function(str) {
      var dst, result;
      dst = str;
      result = str.match(/^([^\{]*)\{([^\}]*)\}(.*)$/);
      if (result != null) {
        dst = result[1] + '(' + result[2].split(',').join('|') + ')' + func(result[3]);
      }
      return dst;
    };
  });

  wildcard2regexstr = function(str) {
    str = str.replace(/\\/g, '\\\\');
    str = str.replace(/\+/g, '\\+');
    str = str.replace(/\./g, '\\.');
    str = str.replace(/\(/g, '\\(');
    str = str.replace(/\)/g, '\\)');
    str = str.replace(/\^/g, '\\^');
    str = str.replace(/\$/g, '\\\$');
    str = str.replace(/\|/g, '\\|');
    str = braces2parentheses(str);
    str = str.replace(/\?/g, '[^/]');
    str = str.replace(/<</g, '<<2');
    str = str.replace(/<<</g, '<<3');
    str = str.replace(/\/\*\*\//g, '(/.<<</|/)');
    str = str.replace(/\*/g, '[^/]+');
    str = str.replace(/<<</g, '*');
    str = str.replace(/<<2/g, '<<');
    str = str.replace(/<<3/g, '<<<');
    return str += '$';
  };

  var wildcard2regex = function(str) {
    return new RegExp(wildcard2regexstr(str));
  };

//test

  var testtext = "src/*.{js,coffee}";
  console.log(testtext);
  var regexstr = wildcard2regexstr(testtext);
  var regex = new RegExp(regexstr);
  console.log(regexstr);
```