倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

はじめての幻獣 Griffon 研 (21) : リソース・バンドルを生成するスクリプトを作る create-script

前回I18n プラグインを用いて国際化を行いましたが、リソース・バンドルの作成が面倒でした。 面倒なことはコンピュータにさせよう!ってことで、今回はリソース・バンドルを生成するスクリプトを作ってみます(参考 Griffon Guide 「4.1 Creating Gant Scripts」)(一覧)。

リソース・バンドルを生成するといっても(自動翻訳ソフトでもない限り)无から作ることはできないので、設定を書き込むファイルは必要。 Groovy ならこれに相応しいのは ConfigObject / ConfigSlurper でしょ!ってことで『GroovyのConfigSlurperがめっちゃ便利』をチラ見しながらコーディング。

目指すは

  • FunctionPlotter/griffon-app/i18n/messages_ja.groovy
app{
    title = '関数描画アプリケーション'

    menu{
        action = 'アクション (A)'
        laf = 'ルック&フィール (L)'
        help = 'ヘルプ (H)'
    }
}

controller.showAbout.message = '''倭マン日記「はじめての Griffon 研」にて
Griffon アプリケーションの例として作成した
『関数描画アプリケーション』です。

Groovy バージョン : {0}
Griffon バージョン : {1}
アプリケーション バージョン : {2}'''

というファイルを作成して、これから前回作成したようなリソース・バンドルを生成できるようにすることです。

スクリプトを生成する


まずは処理をコーディングするスクリプト(Gant スクリプト)を生成しましょう。 プロジェクトのルート・フォルダで以下のコマンドを実行します:

griffon create-script generate-resource-bundles

すると以下のファイルが生成されます:

  • FunctionPlotter/scripts/GenerateResourceBundles.groovy
  • FunctionPlotter/test/cli/GenerateResourceBundlesTests.groovy

テスト・スクリプトはスルーして:-9、スクリプトの方を見ていきましょう。

GenerateResourceBundles.groovy

GenerateResourceBundles.groovy の内容はこんな感じ:

includeTargets << griffonScript("Init")

target(main: "The description of the script goes here!") {
    // TODO: Implement script here
}
setDefaultTarget(main)

基本的に TODO の部分(と "The description of the script goes here!" の部分)以外は変えない方が良さそうです。 このスクリプトを実行するためには、プロジェクトのルートフォルダ下でコマンド

griffon gRB

を実行します*1。 ただし、Maven2/3 や Gradle でできる「gradle clean compile」のようなタスクを並べて実行する方法はできないようです(× 「griffon gRB run-app」)。

ConfigObject からリソース・バンドルを生成する


では設定ファイルからリソース・バンドルを生成するコード。 

includeTargets << griffonScript("Init")

target(main: "Generate Resource Bundles") {

    def slurper = new ConfigSlurper()

    fileset(dir:'griffon-app/i18n', includes:'*.groovy').each{ antFile ->

        def file = antFile.file    // Ant API の file オブジェクトから java.io.File オブジェクトへ変換
        def props = slurper.parse(file.text).toProperties()    // 設定ファイルを読み込んで Properties オブジェクトへ変換

        def filename = file.name.replace('.groovy', '.properties')
        new File("griffon-app/i18n/$filename").withOutputStream{ out ->
            props.store(out, null)    // Properties オブジェクトの内容をリソース・バンドルとして書き出し
        }
    }
}
setDefaultTarget(main)

コメントない方が読みやすいかな。 いくつか注意:

  • Gant スクリプトではタスクをメソッドのように使用できるようですね(fileset(...) みたいに)*2
  • Properties#store() を使えば、リソース・バンドルのエンコーディングなんて気にする必要なし!
  • 'griffon-app/i18n' のようなパスをハード・コーディングしてますが、Griffon なら問題ないでしょう。

引数でエンコーディングを指定できるようにする


リソース・バンドルのエンコーディングは気にする必要がなくなりましたが、ConfigObject の設定ファイルのエンコーディングは指定できる方が便利かと。 ってことで、スクリプト実行の際に以下のようにエンコーディングを指定できるようにしましょう:

griffon gRB UTF-8

スクリプトを指定する「gRB」以降は引数としてスクリプトに渡されます。 コードはこんな感じ:

includeTargets << griffonScript("Init")

encoding = System.getProperty('file.encoding')

target(main: "Generate Resource Bundles") {

    def params = argsMap['params']
    if(!params.isEmpty()) encoding = params[0]

    def slurper = new ConfigSlurper()

    fileset(dir:'griffon-app/i18n', includes:'*.groovy').each{ antFile ->

        def file = antFile.file
        def props = slurper.parse(file.getText(encoding)).toProperties()

        def filename = file.name.replace('.groovy', '.properties')
        new File("griffon-app/i18n/$filename").withOutputStream{ out ->
            props.store(out, null)
        }
    }
}
setDefaultTarget(main)
  • スクリプトに渡される引数は「argsMap['params']」によって取得できます(返り値は List)。
  • 引数が指定されていない場合はデフォルト・エンコーディングを使用します。
  • ここでは特に必須ではありませんが、encoding はスクリプト自体のプロパティとして定義しています。 値の設定(「encoding = System.getProperty('file.encoding')」)はタスクの実行前に行われます。

とりあえず目標は完了。 でも、今回の方法ではアプリケーションのビルドとは別にリソース・バンドルの生成を行わないといけないので、ちょっと面倒。 次回はここの改善を。

Ant 第2版

Ant 第2版

*1:「griffon GenerateResourceBundles」もしくは「griffon GRB」でも構いません。

*2:ant プロパティを介して AntBuilder オブジェクトを使うこともでるようですが(ant.fileset(...))。