Kotlin Poetでコード生成するコードをいくつか書いてみよう

KotlinPoet

Kotlinのソースコードをプログラム的に生成するためのKotlinライブラリです。

https://square.github.io/kotlinpoet/


記法になれることと、よく使いそうな記法を書いておきたいと思います。


 **Hello World!**  
   `println("Hello, World!")`を含む`main`関数を持つKotlinファイルを生成
```kotlin
fun helloWorld() {
    val printValue = "Hello, World!"
    val fileName = "HelloWorld"
    val file = FileSpec.builder("", fileName)
        .addFunction(
            FunSpec.builder("main")
                .addParameter("args", String::class, KModifier.VARARG)
                .addStatement("println(%S)", printValue)

                .build()
        )
        .build()
    file.writeTo(System.out)
}
```

 **プロパティとコンストラクタの追加**  
   `name`と`age`の2つのプロパティと、それらのプロパティを初期化するコンストラクタを持つクラス`Person`を生成

```kotlin
fun personWithAge() {
    val fileName = "Person"
    val className = ClassName("", "Person")
    val file = FileSpec.builder("", fileName)
        .addType(
            TypeSpec.classBuilder(className)
                .primaryConstructor(
                    FunSpec.constructorBuilder()
                        .addParameter("name", String::class)
                        .addParameter("age", Int::class)
                        .build()
                )
                .addProperty(
                    PropertySpec
                        .builder("name", String::class)
                        .initializer("name")
                        .build()
                )
                .addProperty(
                    PropertySpec
                        .builder("age", Int::class)
                        .initializer("age")
                        .build()
                )
                .build()
        )
        .build()
    file.writeTo(System.out)
}
```

**関数の追加**  
   `greet`という名前の関数を持つクラス`Person`を生成。この関数は、`"Hello, $name!"`というメッセージを返す

```kotlin
fun personWithGreet() {
    val fileName = "PersonWithGreet"
    val returnValue = "Hello, " + "$" + "name"
    val className = ClassName("", fileName)
    val file = FileSpec.builder("", fileName)
        .addType(
            TypeSpec.classBuilder(className)
                .primaryConstructor(
                    FunSpec.constructorBuilder()
                        .addParameter("name", String::class)
                        .build()
                )
                .addProperty(
                    PropertySpec.builder("name", String::class)
                        .initializer("name")
                        .build()
                )
                .addFunction(
                    FunSpec.builder("greet")
                        .returns(String::class)
                        .addStatement("return %P", returnValue)
                        .build()
                )
                .build()
        )
        .build()
    file.writeTo(System.out)
}
```

**拡張関数の生成**  
  String`クラスの拡張関数`exclaim`を生成。この関数は、文字列の末尾に`"!"`を追加する

```kotlin
fun extensionFn() {
    val returnValue = "this" + "$" + "!"
    val func = FunSpec.builder(
        "exclaim"
    )
        .receiver(String::class)
        .returns(String::class)
        .addStatement("return this + %S", "!")
        .build()
    FileSpec.builder("", "extensionFn")
        .addFunction(func)
        .build()
        .writeTo(System.out)
}
```

**ジェネリクスの使用**  
   任意の型`T`のリストを受け取り、そのリストの最初の要素を返す関数`firstElement`を生成
```kotlin
fun generateFirstElementFunction() {
    val fileName = "GenericsExample"
    val file = FileSpec.builder("", fileName)
        .addFunction(
            FunSpec.builder("firstElement")
                .addTypeVariable(TypeVariableName("T"))
                .addParameter("list", List::class.asClassName().parameterizedBy(TypeVariableName("T")))
                .returns(TypeVariableName("T"))
                .addStatement("return list.first()")
                .build()
        )
        .build()
    file.writeTo(System.out)
}
```


**アノテーションの追加**  
  @Deprecated`アノテーションを持つ関数`oldFunction`を生成。

```kotlin
fun generateDeprecatedFunction() {
    val fileName = "DeprecatedExample"
    val file = FileSpec.builder("", fileName)
        .addFunction(
            FunSpec.builder("oldFunction")
                .addAnnotation(
                    AnnotationSpec.builder(Deprecated::class)
                        .addMember("%S", "This function is deprecated.")
                        .build()
                )
                .addStatement("println(%S)", "This is the old function.")
                .build()
        )
        .build()

    file.writeTo(System.out)
}
```

**インターフェースの実装**  
  Flyable`というインターフェースを持つクラス`Bird`を生成。このクラスは、`fly`という関数を持ち、`"I can fly!"`というメッセージを返す。

```kotlin
interface Flyable { fun fly() }
fun generateFlyable() {
    val fileName = "Bard"
    val file = FileSpec.builder("", fileName)
        .addType(
            TypeSpec.classBuilder(ClassName("", fileName))
                .addSuperinterface(Flyable::class)
                .addFunction(
                    FunSpec.builder("fly")
                        .addModifiers(KModifier.OVERRIDE)
                        .returns(String::class)
                        .addStatement("return %S", "I can fly!")
                        .build()
                )
                .build()
        )
        .build()

    file.writeTo(System.out)
}
```

**コンパニオンオブジェクトの追加**  
  DEFAULT_NAME`という名前の`String`型のコンパニオンオブジェクトを持つクラス`Person`を生成

```kotlin
fun generatePersonWithCompanionObject() {
    val fileName = "PersonWithCompanion"
    val file = FileSpec.builder("", fileName)
        .addType(
            TypeSpec.classBuilder("Person")
                .addType(
                    TypeSpec.companionObjectBuilder()
                        .addProperty(
                            PropertySpec.builder("DEFAULT_NAME", String::class)
                                .initializer("%S", "Default Name")
                                .build()
                        )
                        .build()
                )
                .build()
        )
        .build()

    file.writeTo(System.out)
}
```

**プロパティのカスタムゲッター**  
  isAdult`という名前の`Boolean`型のプロパティを持つクラス`Person`を生成。このプロパティは、`age`プロパティが18以上の場合に`true`を返すカスタムゲッターを持つ

```kotlin
fun generatePersonWithCustomGetter() {
    val fileName = "PersonWithCustomGetter"
    val file = FileSpec.builder("", fileName)
        .addType(
            TypeSpec.classBuilder("Person")
                .addProperty(
                    PropertySpec.builder("age", Int::class)
                        .initializer("0")
                        .build()
                )
                .addProperty(
                    PropertySpec.builder("isAdult", Boolean::class)
                        .getter(
                            FunSpec.getterBuilder()
                                .addStatement("return age >= 18")
                                .build()
                        )
                        .build()
                )
                .build()
        )
        .build()

    file.writeTo(System.out)
}
```

公式ドキュメント通りですね〜