GeekFactory

int128.hatenablog.com

Categoryを使ってファイルパスを直感的に書く

GroovyのCategoryを使って、ファイルパスを直感的に書く仕組みを導入してみます。

Fileのコンストラクタには親ディレクトリとファイル名を渡すことができますが、ディレクトリの階層が深くなると読みづらくなります。 例えば、baseDirの下のinnerDirの下のfileNameというファイルにアクセスするコードは下記のようになります。

    def targetFile = new File(new File(baseDir, innerDir.name), fileName)

GroovyのCategoryを使うと、既存のクラスに新しいメソッドを追加できます。 この仕組みを応用すると、スラッシュ区切りで直感的にファイルパスが書けるようになります。 先ほどのコードは下記のように書けます。

  use(FileDivCategory) {
    def targetFile = baseDir / innerDir.name / fileName
  }

  @Category(File)
  static class FileDivCategory {
    File div(String child) {
      new File(this as File, child)
    }
  }

上記ではFileクラスに除算演算子を追加して、File(親)とString(ファイル名)から新しいFile(子)を生成するメソッドを追加しています。

ファイルアクセスのテストコードなど、ディレクトリ階層が深くなって読みづらくなりがちなコードはこの方法で可読性を改善できます。Spockを使う場合は、カテゴリクラスをFileのメタクラスにmixinするとテストしやすいです。@Useを使う方法が最も簡単です。

class FileTransferSpec extends Specification {
    @Rule
    TemporaryFolder temporaryFolder

    @Use(FileDivCategory)
    def "create directories"() {
        given:
        def baseDir = temporaryFolder.newFolder()
        def depth1Dir = baseDir / uuidgen()
        def depth2Dir = baseDir / uuidgen() / uuidgen()
        def depth3Dir = baseDir / uuidgen() / uuidgen() / uuidgen()

        when:
        // ...
    }

    private static uuidgen() { UUID.randomUUID().toString() }
}