D言語でARGF
RubyのARGFが羨ましかったので,D言語で簡単に書いてみた.といってもLLみたいに特殊変数とかないので,ファイル名の配列渡せばそれっぽく動くというだけ.もっと凝ってもいいのだけど,単に今書いてるので欲しいってだけなので,それほど厳密ではなかったり^^;
/** * D like ARGF */ class ARGF { private: string[] argv; size_t argc; Stream stream; // current file bool dined; // true if opened stream is din public: /** * Shortcut for new. */ static ARGF opCall(string[] args) { return new ARGF(args); } this(string[] args) { if (args.length) { foreach_reverse (filename; args) argv ~= filename; argc = argv.length; setStream; } else { stream = din; dined = true; } } /** * Returns the current file path. */ pure string path() { if (dined) return null; return argv[argc]; } /** * Returns the current file. */ nothrow Stream file() { return stream; } /** * Skips current file and sets next file. */ ARGF skip() { if (!dined) { stream.close; setStream; } return this; } /** * Supports for foreach(iterate through the stream line-by-line). */ int opApply(int delegate(ref char[]) dg) { int result; while (true) { foreach (char[] line; stream) { result = dg(line); if (result) break; } if (dined || !argc) break; skip; } return result; } /** * Supports for foreach with line count(iterate through the stream line-by-line). */ int opApply(int delegate(ref size_t, ref char[]) dg) { int result; size_t lineno; while (true) { foreach (char[] line; stream) { lineno++; result = dg(lineno, line); if (result) break; } if (dined || !argc) break; skip; } return result; } /** * Reads the entire streams and returns joined it as a string */ string toString() { string result; while (true) { result ~= stream.toString; if (dined || !argc) break; skip; } return result; } private: void setStream() { if (argc) stream = new BufferedFile(argv[--argc], FileMode.In); } }