LoginSignup
1
0

More than 5 years have passed since last update.

Ratpack入門 (番外編) - Kotlinで書くRatpack

Last updated at Posted at 2018-05-14

RatpackはJavaおよびGroovy向けに作られていますが、JVMで動くということは当然、KotlinやScalaのようなほかの言語でも動作します。ここではKotlinでRatpackを書くとどんな感じなのか、ちょっとしたtipsを書いておきます。何かもっといいアイデアがありましたら、ぜひコメント欄でシェアしていただければ幸いです。

DSL風の記述

RatpackはGroovyのDSLを活用するため、多くの個所でラムダを引数に受け取るメソッドを持っています。例えば、サーバーにハンドラーを設定する部分は以下のように記述できます。

RatpackServer.start(spec -> {
    spec.handlers(chain -> {
        chain.get("index.html", ctx -> {
            ctx.render(ctx.file("index.html"));
        });
    });
});

Kotlinはメソッドの引数の最後がラムダを受け取るとき、そのラムダを丸括弧の外側に記述することができます。また、ラムダの引数のプレースホルダーとして、itを使用することができます。

RatpackServer.start {
    it.handlers {
        it.get("index.html") {
            it.render(it.file("index.html"))
        }
    }
}

さすがにGroovyには劣りますが、DSL風の見た目でコードを記述することができます。

オペレーター関数

Ratpackは多くの部分でActionという関数型インターフェースが用いられています。これはJava 8のConsumerに相当するもので、何かの設定を行うのによく使われます。例えばハンドラーをサーバーに設定するhandlers()メソッドは、Action<Chain>を引数に持ちます。このチェーンにURLとハンドラーのマッピングを設定していくわけですが、ある程度ハンドラーが増えてくると、このActionを分割したくなってきます。分割されたActionappend()メソッドを使って一つにまとめることができます。でも何度もappend()を繰り返すのは見た目が分かりづらくなります。出来れば中置記法を使いたいところです。
KotlinのOperator overloadingを使い、演算子で結合できるようにしましょう。

operator fun <T> Action<T>.plus(other: Action<in T>): Action<T> = this.append(other)

fun createHandlers() = AccountAction() + HistroyAction() + // ...

いうまでもなく、演算子オーバーロードの使い過ぎは厳禁です。

PairとDestructuring Declaration

PromiseflatRightなどのメソッドは、複数のPromiseをまとめる、比較的よく使う便利なメソッドです。戻り値の型はRatpackにおけるタプルであるPair型になります。
タプルは便利ではありますが、サポートのないプログラミング言語(つまりJava)ではleftrightのようなメソッドを使って値を取得しなければならず、アンチパターンとされる場合もあります。

Kotlinはタプルそのもののサポートはありませんが、代わりにDestructuring Declarationという機能で、疑似的なタプルを実現しています。これは各クラスにcomponentN()(Nは数字)メソッドを持っていると、それぞれのcomponentN()を分割して使用できる機能です。
RatpackのPairには当然component1()メソッドは持っていませんが、拡張メソッドとして実装することで、疑似的に分割代入できるようにします。

operator fun <T> Pair<T, *>.component1(): T = this.left
operator fun <T> Pair<*, T>.component2(): T = this.right

Pairを分割しているこのような古いコードが

authenticator.checkLoggedIn(ctx).flatRight {
    ctx.parse(ReportParameter::class.java)
}.nextOp { pair ->
    val user = pair.left
    val parameter = pair.right
    // (...)
}

このように書けるようになります。

authenticator.checkLoggedIn(ctx).flatRight {
    ctx.parse(ReportParameter::class.java)
}.nextOp { (user, parameter) ->
    // (...)
}

惜しいのはIDEの補完が利かず、拡張メソッドのimport文を自分で書かなければいけない点です。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0