0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Kotlin DSL でパスの木構造を記述できるようにしてみた

Posted at

概要

Kotlin DSL で,パスをスラッシュ区切り(operator fun div)で書けるようにしてみました.
パスは単純に "path1" / "path2" / "path3" のように記述することもできますし,

"path1" / {
  - "path1-1" / "path1-1-1"
  - "path1-2" / {
    - "path1-2-1"
    - "path1-2-2"
  }
}

のように木構造を書くこともできます.

実装はこちらです.
https://github.com/hmiyado/kuri

背景

Kotlin Developers Meetup に参加しました.
そこで,Hadi 氏によるライブ Kotlin DSL 構築や,LT での有限オートマトンのDSLによる記述といった発表を見て,自分でも少し書いてみようと思いました.

何を書くかで思い当たったのが,パスの組み立てです.
普段は Android を書いていますが,URIを組み立てるために,パスの記述が各所に記述が散らばってしまっていました.
URI全体の一覧性がない,各所でタイプミスのリスクがある,等の問題があります.
まず,手始めに,一覧性がない問題を解決するため,木構造を持ったパスを記述できるようにしました.

実装

パスの連結の実装

最も重要な実装は operator fun div を用いた文字列の拡張です.

operator fun String.div(path: String): KPath

これで,文字列の後に / を置いてパスを連結することができます(KPath は木構造でないパスを保持するクラスです).
/ を連続して書いてパスを連結させるためには,KPath 自身も div を実装する必要があります.

operator fun KPath.div(path: String): KPath

木構造の実装

パスの連結の実装によって, / の後に文字列を書いてパスを連結していくことができるようになりました.
木構造を書くためには, / の後にラムダ式を取れるようにする必要があります.

"path" / { /* ラムダ式 */ }

木構造を保持するクラスを KNode ,そのビルダーを KNode.Builder としましょう.
以下の拡張関数を実装すれば,見た目を合わせることができます.

operator fun String.div(builder: KNode.Builder.()->Unit):KNode = KNode.Builder().apply(builder).build()

これで木構造自体は書けるようになりました.

次に,木構造の中身,子のパスを増やす部分を書くために,ラムダ式の中に目を向けてみましょう.

"path" / {
  - "subpath1"
  - "subpath2"
}

文字列の前に - がついています.
これは, 子のパスを追加するために付けざるを得なかった記号で,kotlinでいうところの operator fun unaryMinus を使っています.

operator fun String.unaryMinus(): KPath

この拡張関数の中で, KNode.Builder が内部的に保持するコレクションに,文字列を追加するという処理を行っています.
もしこれがなければ,以下のような書き方になりますが,

"path" / {
  "subpath1"
  "subpath2"
}

これだと単にラムダ式の中に文字列が2つあるというだけになってしまい,ビルダーに文字列をパスとして追加するタイミングがありません.
無理やり unaryMinus をつけることで,なるべくDSLの見た目に違和感を出さないようにしつつ,ビルダーにパスを登録できるようにしています.

感想

DSLの見た目から逆算して各演算子を実装したため,内部的な実装がきれいになりませんでした.
特に,木構造を記述するためにビルダーのプロパティに値をセットするのではなく,演算子(-)がついていればコレクションに追加するという実装になっています.
そのあたりの関係で,結構煩雑な実装を強いられる箇所がありました.
プロパティを明示せずにきれいに DSL を書く知見がありましたらぜひ教えてください.

今回の実装は,構造をパースできるようにしてみた,という状態で終わっており,まだ実用に耐えうる段階にはありません.
将来的には,上記DSLで定義したパスから,クラスファイルを自動生成する,パスの中にID等の変数を許容し,型安全にパスを生成できるようにする,等の発展的実装をしたいです.

0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?