CLOVER🍀

That was when it all began.

package-info.javaの一括生成

だいぶ遅れているのですが、こちらのお題に参加してみることにしました。
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]

結果は割愛。

う〜ん、いろいろ勉強になりました。