だいぶ遅れているのですが、こちらのお題に参加してみることにしました。
http://npnl.hatenablog.jp/entry/2012/08/17/014930
もうちょっと、早く見つけておけばよかった…
なんか、Groovyが人気っぽいので、ScalaとClojureでいってみます。
ターゲットのディレクトリは、こんな感じ。
$ find src
src
src/jp
src/jp/co
src/jp/co/a
src/jp/co/a/a2
src/jp/co/a/a2/Bar.java
src/jp/co/a/a1
src/jp/co/a/a1/Foo.java
src/jp/co/a/Hoge.java
src/jp/co/a/a3
src/jp/co/a/a3/Fuga.java
Scala
Scalaだと標準では入出力が弱いので、これを機会にNIO.2を使ってみることにしました。
参考にしたのは、この辺りのサイトです。
http://itpro.nikkeibp.co.jp/article/COLUMN/20110830/367909/?ST=develop&P=6
http://itpro.nikkeibp.co.jp/article/COLUMN/20110725/362803/?ST=develop&P=8
http://docs.oracle.com/cd/E26537_01/tutorial/essential/io/pathOps.html
作成したコードは、こちら。
PackageInfoGen.scala
import scala.collection.JavaConverters._ import java.nio.charset.Charset import java.nio.file.{Files, FileVisitResult, Path, Paths, SimpleFileVisitor} import java.nio.file.attribute.BasicFileAttributes val fileName = "package-info.java" val template = """|/** | * %1$sパッケージ。 | * | * <pre> | * // TODO パッケージ内容の詳細を記述してください | * </pre> | * | */ |package %1$s; |""".stripMargin val srcDir = Paths.get(args.toList.headOption.getOrElse("./src")) val charset = Charset.forName("UTF-8") Files.walkFileTree(srcDir, new DirectoryWalker) class DirectoryWalker extends SimpleFileVisitor[Path] { override def preVisitDirectory(dir: Path, attrs: BasicFileAttributes): FileVisitResult = dir match { case `srcDir` => FileVisitResult.CONTINUE case _ => val packageName = srcDir .relativize(dir) .asScala .mkString(".") val packageInfoFile = dir.resolve(fileName) val contents = template.format(packageName) printf("Generating... [%s]%n", packageInfoFile) Files.write(packageInfoFile, contents.lines.toList.asJava, charset) FileVisitResult.CONTINUE } }
スクリプト形式になっているので、scalaコマンドで直接実行します。
$ scala PackageInfoGen.scala Generating... [./src/jp/package-info.java] Generating... [./src/jp/co/package-info.java] Generating... [./src/jp/co/a/package-info.java] Generating... [./src/jp/co/a/a2/package-info.java] Generating... [./src/jp/co/a/a1/package-info.java] Generating... [./src/jp/co/a/a3/package-info.java]
fscが起動していない場合、超重たいのが難点です…。
一応、結果。
$ cat src/jp/co/a/a2/package-info.java /** * jp.co.a.a2パッケージ。 * * <pre> * // TODO パッケージ内容の詳細を記述してください * </pre> * */ package jp.co.a.a2;
Clojure
続いて、Clojure。こちらは、標準関数とJavaのクラスで頑張ってみました。
package-info-gen.clj
(import '(java.io File)) (use '[clojure.java.io :only (file)] '[clojure.string :only (join)]) (def file-name "package-info.java") (def src-dir (if (> (count *command-line-args*) 0) (first *command-line-args*) "./src")) (def encoding "UTF-8") (def line-separator (System/lineSeparator)) ;; => JDK 7以上 (def template (reduce #(str %1 line-separator %2) '("/**" " * %1$sパッケージ。" " *" " * <pre>" " * // TODO パッケージ内容の詳細を記述してください" " * </pre>" " * " " */" "package %1$s;" ""))) (defn package-info-gen [src-dir] (let [path-delimiter-pattern (re-pattern "/|\\\\") ;; path-delimiter-pattern #"/|\\" branch? #(.isDirectory %) to-package-name #(join "." (drop (count (.split path-delimiter-pattern src-dir)) (.split path-delimiter-pattern (.getPath %)))) write-file (fn [dir] (println (format "Generating... [%s]" (str dir (File/separator) file-name))) (spit (file dir file-name) (format template (to-package-name dir)) :encoding encoding))] (for [dir (rest (filter branch? (file-seq (file src-dir))))] (write-file dir)))) (dorun (package-info-gen src-dir))
実行。
$ clj package-info-gen.clj Generating... [./src/jp/package-info.java] Generating... [./src/jp/co/package-info.java] Generating... [./src/jp/co/a/package-info.java] Generating... [./src/jp/co/a/a2/package-info.java] Generating... [./src/jp/co/a/a1/package-info.java] Generating... [./src/jp/co/a/a3/package-info.java]
結果は割愛。
う〜ん、いろいろ勉強になりました。