3
0

More than 1 year has passed since last update.

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

Posted at

KotlinPoet

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

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

Hello World!
println("Hello, World!")を含むmain関数を持つ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)
}

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

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!"というメッセージを返す

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を生成。この関数は、文字列の末尾に"!"`を追加する

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を生成

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`を生成。

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!"`というメッセージを返す。

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`を生成

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`を返すカスタムゲッターを持つ

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)
}

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

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