ワイルドカードを正規表現に書き換えるやつの続き。
とゆーわけで、CoffeeScript や Javascript (node.js) で、グロブが使える FileList。rubyのrakeで使えるのがどんなやつかよく知らないけど、とりあえず、移植じゃないもーん。(って、ちょっとドキュメント覗いてみたら、遅延評価な感じで、しかもちょこざいな機能が色々あるのね。まねしないぞ。……しないぞ! 絶対にな!)
asterisk *, globstar **, question ?, bracket [a-zA-Z], brace {foo|bar} が使えます。
- 第1引数はグロブの文字列(か、正規表現オブジェクトもOK)
- 第2引数は探索のベースとなるパス(省略すれば、カレントです)
- 返値はマッチするファイルのフルパス文字列のArray
ま、よしなに。
arr = FileList("src/**/temp_*.{js,coffee}")
みたいな感じでさくっとディレクトリ走査。ま、GulpをCoffeeScriptに置き換える以外にも、これなら使い途がありましょう。
FileList.coffee
fs = require('fs')
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)
FileList_inside = y_combi (func) ->
return (srcpath, regex, pathregex) ->
arr = []
if not fs.existsSync srcpath
return -1
filearray = fs.readdirSync srcpath
for fileordir in filearray
fname = srcpath+'/'+fileordir
statresult = fs.statSync fname
if statresult.isFile()
if regex.test fname
if pathregex.test fname
arr.push(fname)
else if statresult.isDirectory()
arr = arr.concat func(fname,regex,pathregex)
return arr
FileList = (pathname, basepath = null) ->
judgetype = Object.prototype.toString.call(pathname).slice(8, -1)
if not basepath?
basepath = process.cwd()
else if basepath == '.'
basepath = process.cwd()
else if /^\.\//.test basepath
basepath = basepath.replace(/^\./,process.cwd())
else if /^\.\./.test basepath
basepath = process.cwd()+'/'+basepath
while(/\/\.\./.test basepath)
basepath = basepath.replace(/\/[^\/]+\/\.\./,'')
basepath = basepath.replace(/\/$/,'')
pathregex = basepath
basepath = basepath.replace(/[\*\?\[\{].*$/,'')
basepath = basepath.replace(/\/[^\/]*$/,'')
pathregex = '^'+(wildcard2regexstr pathregex).replace(/\$$/,'')+'/'
pathregex = new RegExp(pathregex)
switch judgetype
when 'RegExp'
regex = pathname
when 'String'
regex = wildcard2regex pathname
else
console.log 'error'
process.exit 1
FileList_inside basepath,regex,pathregex
# test
for fname in FileList("*.coffee",'../../**/a??')
console.log fname
JavaScript版。
FileList.js
var fs = require('fs');
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;
};
});
var 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));
};
var FileList_inside = y_combi(function(func) {
return function(srcpath, regex, pathregex) {
var arr, filearray, fileordir, fname, i, len, statresult;
arr = [];
if (!fs.existsSync(srcpath)) {
return -1;
}
filearray = fs.readdirSync(srcpath);
for (i = 0, len = filearray.length; i < len; i++) {
fileordir = filearray[i];
fname = srcpath + '/' + fileordir;
statresult = fs.statSync(fname);
if (statresult.isFile()) {
if (regex.test(fname)) {
if (pathregex.test(fname)) {
arr.push(fname);
}
}
} else if (statresult.isDirectory()) {
arr = arr.concat(func(fname, regex, pathregex));
}
}
return arr;
};
});
var FileList = function(pathname, basepath) {
var judgetype, pathregex, regex;
if (basepath == null) {
basepath = null;
}
judgetype = Object.prototype.toString.call(pathname).slice(8, -1);
if (basepath == null) {
basepath = process.cwd();
} else if (basepath === '.') {
basepath = process.cwd();
} else if (/^\.\//.test(basepath)) {
basepath = basepath.replace(/^\./, process.cwd());
} else if (/^\.\./.test(basepath)) {
basepath = process.cwd() + '/' + basepath;
}
while (/\/\.\./.test(basepath)) {
basepath = basepath.replace(/\/[^\/]+\/\.\./, '');
}
basepath = basepath.replace(/\/$/, '');
pathregex = basepath;
basepath = basepath.replace(/[\*\?\[\{].*$/, '');
basepath = basepath.replace(/\/[^\/]*$/, '');
pathregex = '^' + (wildcard2regexstr(pathregex)).replace(/\$$/, '') + '/';
pathregex = new RegExp(pathregex);
switch (judgetype) {
case 'RegExp':
regex = pathname;
break;
case 'String':
regex = wildcard2regex(pathname);
break;
default:
console.log('error');
process.exit(1);
}
return FileList_inside(basepath, regex, pathregex);
};
var i,len;
var ref = FileList("*.coffee", '../../**/a??');
for (i = 0, len = ref.length; i < len; i++) {
fname = ref[i];
console.log(fname);
}