KDoc 書き方メモ(Kotlin のドキュメンテーションコメント)

# 環境
## OS
Windows 10

## Kotlin
Kotlin version 1.2.10

## Gradle
Gradle 4.4

# KDoc とは
- Kotlin のソースコード上に書いたドキュメンテーションコメントから生成された API ドキュメント（またその仕組みのこと）
- Kotlin 版 Javadoc
- Javadoc と同じようなところもあれば、全然違うところもある

# Hello World
```text:フォルダ構成
|-build.gradle
|
`-src/main/kotlin/
  `-sample/kdoc/
    `-Hello.kt
```

```groovy:build.gradle
buildscript {
    ext {
        kotlin_version = '1.2.10'
    }

    repositories {
        mavenCentral() // kotlin 用
        jcenter() // dokka 用
    }

    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "org.jetbrains.dokka:dokka-gradle-plugin:0.9.15"
    }
}

apply plugin: 'kotlin'
apply plugin: 'org.jetbrains.dokka'
```

```kotlin:Hello.kt
package sample.kdoc

/**
 * クラスの説明.
 */
class TopLevelClass {
    /**
     * コンパニオンオブジェクトの説明.
     */
    companion object {
        /**
         * コンパニオンオブジェクトのプロパティの説明.
         */
        val value = "test"
    }

    /**
     * プロパティの説明.
     */
    var value: String? = null

    /**
     * メソッドの説明.
     * 
     * @args arg 引数の説明
     * @return return 戻り値の説明
     */
    fun method(arg: String = "default") = "method"
}

/**
 * トップレベルの関数の説明.
 */
fun topLevelFunction() {
}

/**
 * トップレベルのプロパティの説明.
 */
val topLevelProperty = "test"
```

**ドキュメント生成**

```bash
$ gradle dokka
```

**出力結果**

```text:出力先フォルダ
|-build.gradle
|-src/
| :
`-build/
  |-dokka/
  : |-style.css
    `-kdoc/
      |-index.html
      |-index-outline.html
      |-sample.kdoc/
      : |-index.html
        : 
```

**index.html**

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/10e35855-b41b-2297-ae7c-fa56b4072c84.jpeg)

**sample.kdoc/index.html**

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/4b32b843-49db-3200-4c91-012411023414.jpeg)

**説明**

```groovy:build.gradle
buildscript {
    ...

    repositories {
        ...
        jcenter() // dokka 用
    }

    dependencies {
        ...
        classpath "org.jetbrains.dokka:dokka-gradle-plugin:0.9.15"
    }
}

...
apply plugin: 'org.jetbrains.dokka'
```

- KDoc の出力には、 [Dokka](https://github.com/Kotlin/dokka) というツールを使用する
- Ant, Maven, Gradle のプラグインとして組み込んで利用することができる
    - jar ファイルを直接利用してコマンドラインで生成することも可能
    - ここでは、 Gradle を使った場合を前提にする
- Dokka プラグインを追加すると `dokka` というドキュメントを生成するタスクが追加される
- デフォルトでは、 `build/dokka` の下に簡素な HTML 形式で出力される

# 出力形式を変更する
## Javadoc 形式
```groovy:build.gradle
...

dokka {
    outputFormat = 'javadoc'
}
```

**出力結果**

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/16f1649e-7e24-027f-b1b8-5223d33d0987.jpeg)

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/d473a35d-cbe0-1c38-46d1-80bd6dc72845.jpeg)

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/4434eb85-2e31-283a-d495-9fc256d412f5.jpeg)

**説明**

- `dokka.outputFormat` で出力形式を指定できる
- `javadoc` を指定すると、本家 Javadoc 形式で出力される
- Kotlin 独自の言語仕様（プロパティやトップレベルの関数など）は、 Java から見たときの形式に置き換えられる
    - つまり、 Java から Kotlin のコードを使うときに見ると有用な形式になってる

## Markdown 形式
```groovy:build.gradle
...

dokka {
    outputFormat = 'markdown'
}
```

**出力結果**

```text:フォルダ構成
`-build/dokka/kdoc/
  |-alltypes/
  | :
  |-sample.kdoc
  |-index.md
  `-package-list
```

```md:index.md
[kdoc](.)

### Packages

| [sample.kdoc](sample.kdoc/index.md) |  |

### Index

[All Types](alltypes/index.md)
```

**説明**

- `outputFormat` に `markdown` を選択すると、出力が Markdown 形式のテキストファイルになる
- これをそのまま GitHub などの Markdown ファイルをプレビューしてくれるサービスに上げれば、ドキュメントの公開ができる
- `outputFormat` を `gfm` にすると、 GitHub Flavored Markdown 形式の Markdown が出力される
    - 実際にリポジトリにコミットして GitHub にあげると [こんな感じ](https://github.com/opengl-8080/Samples/blob/master/kotlin/kdoc/doc/gfm/sample.kdoc/-top-level-class/index.md) になる

# 基本文法
```kotlin:Hello.kt
package sample.kdoc

/**
 * 最初の空行までは
 * 概要として扱われる.
 * 
 * ## 見出し
 * クラス名とかは `<h1>` で出力されるので、見出しを使うならレベル２からにしたほうが良さげ.
 *
 * Markdown が普通に書ける.
 *
 * 空行を入れると、段落が分かれる.
 *
 * [リンクや](https://www.google.co.jp)
 * 
 * インラインコード `Hello().hello()` も可能.
 * 
 * ### リスト
 * - foo
 * - bar
 * 
 * 1. one
 * 1. two
 *
 * ### コードブロック
 * ```kotlin
 * fun main(args: Array<String>) {
 *     val hello = Hello()
 *     hello.hello()
 * }
 * ```
 * 
 * ### サポート対処外？
 * 任意の改行は(単純な改行)
 * いれることが(半角スペース２つ)  
 * できない(`<br>`タグ)<br>
 * ？？？？？
 *
 * > 引用文
 * 
 * |テーブルも|無理っぽい|
 * |---------|---------|
 * |foo      |bar    |
 * |fizz     |buzz   |
 *
 * <font color="red">任意の HTML タグも書くことができなさそう.</font>
 *
 * `&lt;` のようなエスケープ記法は、 &lt; のように単独なら大丈夫だけど、
 * &lt;html&gt; のように続けて書こうとするとなぜかうまくいかなくなるので、
 * `<html>` のようにインラインコードで書くのが無難そう...
 * 
 * -----------------------------------------------------------------------
 * 区切り線もだめっぽい？
 */
class Hello
```

**出力結果**

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/7f55c999-fb4f-74c4-f85d-5fa2e06dbb19.jpeg)

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/0ebbc7a7-a297-eb6d-b055-7a7dde5e3a84.jpeg)

**説明**

- Javadoc 同様、 `/**` から `*/` までがドキュメントコメントとして解釈される
- KDoc は、基本的に Markdown で記述する
- 見出し (`#`) も利用可能だが、クラス名とかがレベル１なので、自分で書くドキュメンテーションコメントはレベル２からにしたほうが良さげ
- 試した範囲だと、以下の記法は**使えなかった**
    - 任意の改行
    - テーブル
    - 区切り線
    - HTML の直書き
- また、 `&lt;` や `&gt;` のようなエスケープの記法は、単独で使用していると問題なく `<`, `>` と表示される
    - しかし、なぜか `&lt;html&gt;` のように文字を続けてしまうとそのまま表示されてしまう
    - とりあえずインラインコードにすれば回避はできるっぽいけどなんか変な気がする

# ブロックタグ
Javadoc でいうところの `@param` とかのこと。
Kotlin でも同じようなブロックタグが使えるが、 Kotlin の言語仕様に合わせて色々独自のブロックタグが用意されている。

## パラメータ
**書式**

```
@param パラメータ名 パラメータの説明
```

**例**

```kotlin
package sample.kdoc

/**
 * Hello クラス.
 * @param T 型引数
 */
class Hello<T> {
    /**
     * メソッド.
     * @param name 名前
     */
    fun method(name: String) = ""
}
```

**出力結果**

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/5317e3e1-e309-e6d0-beb3-86cbae516ac8.jpeg)

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/a11bb871-60e8-8b61-7166-956478c36554.jpeg)

**説明**

- クラスの型引数、またはメソッドのパラメータを説明するために使用する

## 戻り値
**書式**

```
@return 戻り値の説明
```

**例**

```kotlin
package sample.kdoc

/**
 * Hello クラス.
 */
class Hello {
    /**
     * メソッド.
     * @return 戻り値の説明
     */
    fun method() = ""
}
```

**出力結果**

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/9266d7cf-5205-5f41-a8c0-6ab58182a275.jpeg)

**説明**

- 戻り値の説明を記述するときに使用する

## プライマリコンストラクタ
**書式**

```
@constructor コンストラクタの説明
```

**例**

```kotlin
package sample.kdoc

/**
 * Hello クラス.
 * 
 * クラスの詳細な説明.
 * 
 * @param T 型引数の説明
 * 
 * @constructor
 * プライマリコンストラクタの説明.
 * 
 * 詳細な説明は空行を開けてから書ける.
 * @param value プライマリコンストラクタ引数の説明は `@constructor` の後に書く
 */
class Hello<T> (value: String) {
    /**
     * セカンダリコンストラクタの説明.
     *
     * セカンダリコンストラクタの詳細な説明
     * @param int セカンダリコンストラクタの引数の説明
     */
    constructor(int: Int): this("int=$int")
}
```

**出力結果**

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/22d90844-edc6-4d52-9aed-d7e6ec8a8603.jpeg)

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/649098d0-ce78-6107-9cc4-a05e8653d0bb.jpeg)

**説明**

- プライマリコンストラクタについてのドキュメントコメントを書きたい場合に使用する
    - `@constructor` を使わずに書くと、クラスのドキュメントコメントとして処理されてしまう
- 引数の説明を指定する場合は、 `@constructor` の後で `@param` を使う
    - 前に書くと、クラスの型引数の注釈と判断されてしまう
- 空行を入れれば詳細な説明も書ける

## レシーバー
**書式**

```
@receiver レシーバーの説明
```

**例**

```kotlin
package sample.kdoc

/**
 * Hello クラス.
 */
class Hello {
    /**
     * メソッドの説明.
     * @param lambda 引数の説明
     * @receiver レシーバの説明
     */
    fun method(lambda: String.() -> Unit) {
        "hello".lambda()
    }
}
```

**出力結果**

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/88f562ee-ec5b-9503-8470-bb2f3dbac1c8.jpeg)

**説明**

- レシーバについて説明を書くときに使用する

## プロパティ
**書式**

```
@property プロパティ名 プロパティの説明
```

**例**

```kotlin
package sample.kdoc

/**
 * Hello クラス.
 * 
 * @property foo
 * プライマリコンストラクタの場合、ドキュメントコメントが書きづらいので、
 * `@property` ブロックタグを使用することで、クラスのドキュメントコメント内に記述できる.
 */
class Hello (val foo: String) {
    /**
     * クラス内で宣言されているプロパティの場合は、普通にドキュメントコメントを書ける.
     */
    val bar = 1
}
```

**出力結果**

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/cb6c96ee-4b2b-dfe6-7ea0-8a869d2d442d.jpeg)

**説明**

- プライマリコンストラクタで定義したプロパティにドキュメントを書きたいときに使用する
- クラスのボディで宣言しているプロパティであれば、そのプロパティの前にドキュメントコメントを書けばいい
- しかし、プライマリコンストラクタで定義したプロパティの場合は、ドキュメントコメントが書きづらくなる
- そこで、クラスのドキュメントコメント内で `@property` を使用することで、プライマリコンストラクタで定義したプロパティのドキュメントを書ける

## 例外
**書式**

```
@throws 例外クラス 例外の説明
@exception 例外クラス 例外の説明
```

**例**

```kotlin
package sample.kdoc

/**
 * Hello クラス.
 */
class Hello {
    /**
     * メソッドの説明.
     * @throws IOException 例外の説明
     * @exception SQLException 例外の説明
     */
    fun method() = ""
}
```

**出力結果**

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/c356b628-8449-213b-07e8-61e16196c35a.jpeg)

**説明**

- メソッドがスローする例外について説明するときに使用する
- `@throws`, `@exception` のどちらを使っても、結果は同じ

## サンプル
**書式**

```
@sample 埋め込むサンプルの識別子
```

**例**

```text:フォルダ構成
|-build.gradle
|-samples/
| `-method-sample.kt
`-src/main/kotlin/
  `-sample/kdoc/
    `-Hello.kt
```

```groovy:build.gradle
...

dokka {
    outputFormat = 'html'
    samples = ["samples/method-sample.kt"]
}
```

```kotlin:method-sample.kt
package sample

fun sampleImplementation() {
    val hello = Hello()
    hello.method()
}
```

```kotlin:Hello.kt
package sample.kdoc

/**
 * Hello クラス.
 */
class Hello {
    /**
     * メソッドの説明.
     * @sample sample.sampleImplementation
     */
    fun method() = ""
}
```

**出力結果**

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/2689dcd2-fbff-32b2-1bf2-2b463bebbc86.jpeg)

**説明**

- 外部で用意したサンプル実装をドキュメント上に埋め込むときに使用する
- 任意の場所にサンプルコードを記述した Kotlin のソースコードを配置する
- `build.gradle` で、 `dokka.samples` にサンプルのファイルを置いた場所を設定する
    - `dokka.samples` は、ディレクトリの指定も可能
- サンプルコードを埋め込みたい場所のドキュメントコメントで `@sample <識別子>` と記述する
- 識別子は、サンプルコード（関数）を特定できる完全修飾名にする

## Author
**書式**

```
@author 作成者
```

**例**

```kotlin
package sample.kdoc

/**
 * Hello クラス.
 *
 * @author 作成者の名前
 */
class Hello
```

**出力結果**

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/224280a9-ca7f-8903-986a-44add6d9c65f.jpeg)

**説明**

- コードの作成者を明記するときに使用する

## Since
**書式**

```
@since バージョン
```

**例**

```kotlin
package sample.kdoc

/**
 * Hello クラス.
 *
 * @since 1.0
 */
class Hello
```

**出力結果**

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/f1e29fee-5983-75ef-e4c1-d29599d6bc19.jpeg)

**説明**

- 対象が導入されたバージョンを明記するときに使用する

## 出力対象から除外する
**書式**

```
@suppress
```

**例**

```kotlin
package sample.kdoc

/**
 * Hello クラス.
 */
class Hello {
    /**
     * メソッドの説明.
     */
    fun method() = ""

    /**
     * このメソッドの説明の出力は除外される.
     * @suppress
     */
    fun method2() = ""
}
```

**出力結果**

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/390b5246-395b-e4be-ce99-ea22f8a18821.jpeg)

**説明**

- ドキュメントの出力から除外したい場合に使用する
- 外部に公開しない API でドキュメントとしては出力しないが、内部的には残しておきたい、みたいなケースで使用するっぽい

# リンク
```text:フォルダ構成
`-src/main/kotlin/
  `-sample/kdoc/
    |-foo/
    | `-Foo.kt
    `-Hello.kt
```

```kotlin:Foo.kt
package sample.kdoc.foo

/**
 * Foo クラス.
 */
class Foo {
    companion object {
        /**
         * fuga プロパティ
         */
        val fuga = ""
    }

    /**
     * hoge プロパティ
     */
    val hoge = ""

    /**
     * fizz メソッド.
     */
    fun fizz() = ""

    /**
     * fizz(String) メソッド.
     */
    fun fizz(text: String, int: Int) = ""
}

/**
 * function 関数.
 */
fun function() = ""
```

```kotlin:Hello.kt
package sample.kdoc

import sample.kdoc.foo.Foo

/**
 * Hello クラス.
 *
 * - [Foo]
 * - [Foo.hoge]
 * - [Foo.fizz]
 * - [sample.kdoc.foo.function]
 * - [Foo.fuga]
 */
class Hello
```

**出力結果**

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/56e499cc-2fb5-c7d9-fee4-13c0e65fb9d2.jpeg)

**説明**

```kotlin:Hello.kt
 * - [Foo]
 * - [Foo.hoge]
 * - [Foo.fizz]
 * - [sample.kdoc.foo.function]
 * - [Foo.fuga]
```

- 他の要素（クラス、メソッド、プロパティ、関数など）へのリンクを指定するには、 `[]` を使用する
    - Javadoc の `{@link}` に該当
- リンクしたい要素を完全修飾名で記述する
- `import` している場合は省略して記述できる（Javadoc と同じ）

## オーバーロードしているメソッドの指定
オーバーロードしているメソッドたちは、 KDoc では次のように１つにまとめられて出力される。

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/8fdbe803-9f15-4a07-505b-6f1f8f39e9f4.jpeg)

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/8ac6dec7-5298-0d78-67eb-0ccd22d822ee.jpeg)

つまり、 Javadoc の `{@link}` のようにシグネチャを指定してオーバーロードしているメソッドごとにリンクを指定する、ということはしない。

## 表示テキストを変更する
```kotlin
package sample.kdoc

import sample.kdoc.foo.Foo

/**
 * Hello クラス.
 *
 * - [任意のテキスト][Foo]
 */
class Hello
```

**出力結果**

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/ad6ace5d-48e1-5cbd-fc68-b6676894e1df.jpeg)

**説明**

- リンクの表示テキストを任意のものに変更したい場合は、 `[表示するテキスト][リンク先の識別子]` と記述する

# モジュールとパッケージのドキュメント
```text:フォルダ構成
|-build.gradle
|-docs/
: `-module_package.md
```

```groovy:build.gradle
...

dokka {
    outputFormat = 'html'
    includes = ['docs/module_package.md']
}
```

```md:module_package.md
# Module モジュール名？
モジュールの説明

## 詳細な説明
モジュールの詳細な説明

# Package sample.kdoc
パッケージの説明１

## 詳細な説明
パッケージの詳細な説明１

# Package sample.kdoc.foo
パッケージの説明２

## 詳細な説明
パッケージの詳細な説明２
```

**出力結果**

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/c8f7114b-0a76-eebd-3231-a357ab62e32d.jpeg)

![kdoc.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/fe0fc8c6-be34-3819-8736-2648d0946f4c.jpeg)

**説明**

- モジュールやパッケージの説明は、別途 Markdown ファイルを作成して組み込む
- オプションの `dokka.includes` で Markdown ファイルを指定する
- レベル１の見出しでモジュールとパッケージのどちらを記述するか指定する
    - モジュールの場合は `# Module 【モジュール名】`
    - パッケージの場合は `# Package 【パッケージ名】`  
      と書くのがルール
    - ただ、モジュール名が何を指していて、どう使われているのかはよくわからない
- １つのファイルに複数のパッケージの説明を含めることが可能
    - パッケージ毎にファイルを分けることも可能（その場合は、 `dokka.includes` で複数ファイルを指定する）
- 仕様なのかバグなのかは分からないが、空行を入れてもなぜか全て1行にまとめられしまう
    - レベル２以上の見出しを挟めば、一応分けられるけども...

# 参考
- [Documenting Kotlin Code - Kotlin Programming Language](https://kotlinlang.org/docs/reference/kotlin-doc.html)