elixir-writing-docs について
ExDocの規約に沿ったElixirドキュメント作成スキルです。モジュールや公開関数の文書構成と検証を支援します。
主な機能
- 01冒頭段落の要約ルール
- 02モジュール・関数文書の構成
- 03doctestと相互参照の指針
- 04書式と注意書きのリファレンス
- 05ドキュメント完了チェック
活用シーン
- 01簡潔な@moduledocと@docの作成
- 02API文書への例とdoctestの追加
- 03公開APIの文書化状況の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ existential-birds/ beagle --skill elixir-writing-docsインストール後、Claude Code で/elixir-writing-docsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/admonitions-and-formatting.mdcross-references.mddoctests.md詳細
Elixir ドキュメントの作成
クイックリファレンス
| トピック | リファレンス |
|---|---|
| doctest:構文、注意点、使用するタイミング | references/doctests.md |
| 相互参照とリンクの構文 | references/cross-references.md |
| 注意書き、書式設定、タブ | references/admonitions-and-formatting.md |
1 行目の要約ルール
ExDoc や mix docs などのツールは、@moduledoc と @doc の最初の段落を要約として抽出します。冒頭の行は簡潔で、それだけで意味が通じるようにしてください。
# GOOD - first line works as a standalone summary
@moduledoc """
Handles payment processing through Stripe and local ledger reconciliation.
Wraps the Stripe API client and ensures each charge is recorded in the
local ledger before returning a confirmation to the caller.
"""
# BAD - first line is vague, forces reader to continue
@moduledoc """
This module contains various functions related to payments.
It uses Stripe and also updates the ledger.
"""
同じルールは @doc にも適用されます。
# GOOD
@doc """
Charges a customer's default payment method for the given amount in cents.
Returns `{:ok, charge}` on success or `{:error, reason}` when the payment
gateway rejects the request.
"""
# BAD
@doc """
This function is used to charge a customer.
"""
@moduledoc の構成
適切に構成された @moduledoc は、次のパターンに従います。
defmodule MyApp.Inventory do
@moduledoc """
Tracks warehouse stock levels and triggers replenishment orders.
This module maintains an ETS-backed cache of current quantities and
exposes functions for atomic stock adjustments. It is designed to be
started under a supervisor and will restore state from the database
on init.
## Examples
iex> {:ok, pid} = MyApp.Inventory.start_link(warehouse: :east)
iex> MyApp.Inventory.current_stock(pid, "SKU-1042")
{:ok, 350}
## Configuration
Expects the following in `config/runtime.exs`:
config :my_app, MyApp.Inventory,
repo: MyApp.Repo,
low_stock_threshold: 50
"""
end
重要なポイント:
- 最初の段落が要約です(1~2 文)。
## Examplesには現実的な使用例を記載します。実行可能な例には doctest を使用してください。## Configurationには必須の設定キーを記載します。モジュールが設定を受け取らない場合は、このセクションを省略してください。- 第 2 レベルの見出し(
##)のみを使用してください。第 1 レベル(#)は ExDoc の出力でモジュール名に予約されています。
ビヘイビアモジュールのドキュメント化
ビヘイビアを定義する場合は、期待されるコールバックをドキュメント化してください。
defmodule MyApp.PaymentGateway do
@moduledoc """
Behaviour for payment gateway integrations.
Implementations must handle charging, refunding, and status checks.
See `MyApp.PaymentGateway.Stripe` for a reference implementation.
## Callbacks
* `charge/2` - Initiate a charge for a given amount
* `refund/2` - Refund a previously completed charge
* `status/1` - Check the status of a transaction
"""
@callback charge(amount :: pos_integer(), currency :: atom()) ::
{:ok, transaction_id :: String.t()} | {:error, term()}
@callback refund(transaction_id :: String.t(), amount :: pos_integer()) ::
:ok | {:error, term()}
@callback status(transaction_id :: String.t()) ::
{:pending | :completed | :failed, map()}
end
@doc の構成
@doc """
Reserves the given quantity of an item, decrementing available stock.
Returns `{:ok, reservation_id}` when stock is available, or
`{:error, :insufficient_stock}` when the requested quantity exceeds
what is on hand.
## Examples
iex> MyApp.Inventory.reserve("SKU-1042", 5)
{:ok, "res_abc123"}
iex> MyApp.Inventory.reserve("SKU-9999", 1)
{:error, :not_found}
## Options
* `:warehouse` - Target warehouse atom. Defaults to `:primary`.
* `:timeout` - Timeout in milliseconds. Defaults to `5_000`.
"""
@spec reserve(String.t(), pos_integer(), keyword()) ::
{:ok, String.t()} | {:error, :insufficient_stock | :not_found}
def reserve(sku, quantity, opts \\ []) do
# ...
end
ガイドライン:
- 関数が何をするかを述べてから、何を返すかを説明します。
- 関数がキーワードリストを受け取る場合は、
## Optionsセクションに各オプションを箇条書きで記載します。 @specは@docとdefの間に配置します。これが慣例的な順序です。- 純粋関数には doctest を含めます。副作用のある関数では省略してください(references/doctests.md を参照)。
@typedoc
@type または @opaque で定義されたカスタム型をドキュメント化します。
@typedoc """
A positive integer representing an amount in the smallest currency unit (e.g., cents).
"""
@type amount :: pos_integer()
@typedoc """
Reservation status returned by `status/1`.
* `:held` - Stock is reserved but not yet shipped
* `:released` - Reservation was cancelled and stock restored
* `:fulfilled` - Items have shipped
"""
@type reservation_status :: :held | :released | :fulfilled
@typedoc """
Opaque handle returned by `connect/1`. Do not pattern-match on this value.
"""
@opaque connection :: %__MODULE__{socket: port(), buffer: binary()}
@opaque 型では、呼び出し側が構造を調べられないため、@typedoc が特に重要です。
メタデータ
@doc since と @doc deprecated
@doc since: "1.3.0"
@doc """
Transfers stock between two warehouses.
"""
def transfer(from, to, sku, quantity), do: # ...
@doc deprecated: "Use transfer/4 instead"
@doc """
Moves items between locations. Deprecated in favor of `transfer/4`
which supports cross-region transfers.
"""
def move_stock(from, to, sku, quantity), do: # ...
メタデータとドキュメント文字列は、1 つの属性にまとめることができます。
@doc since: "2.0.0", deprecated: "Use bulk_reserve/2 instead"
@doc """
Reserves multiple items in a single call.
"""
def batch_reserve(items), do: # ...
@moduledoc since: もモジュールに対して同様に機能します。
@moduledoc since: "1.2.0"
@moduledoc """
Handles webhook signature verification for Stripe events.
"""
@doc false / @moduledoc false を使用する場合
モジュールまたは関数がパブリック API の一部ではない場合は、ドキュメントを表示しないようにします。
# Private implementation module — internal to the application
defmodule MyApp.Inventory.StockCache do
@moduledoc false
# ...
end
# Protocol implementation — documented at the protocol level
defimpl String.Chars, for: MyApp.Money do
@moduledoc false
# ...
end
# Callback implementation — documented at the behaviour level
@doc false
def handle_info(:refresh, state) do
# ...
end
# Helper used only inside the module
@doc false
def do_format(value), do: # ...
本当に公開されている関数に @doc false を使用しないでください。 関数がエクスポートされ、呼び出し側が依存している場合は、ドキュメントを記載してください。外部から呼び出すべきでない場合は、defp でプライベートにしてください。
ドキュメントとコードコメントの違い
ドキュメント(@moduledoc、@doc) | コードコメント(#) | |
|---|---|---|
| 対象読者 | API のユーザー | ソースを読む開発者 |
| 目的 | 契約:何をするか、何を返すか | 特定の実装上の選択をした理由 |
| レンダリング | あり。ExDoc による HTML/epub | なし。ソース内でのみ表示 |
| 必須 | すべての公開モジュールと関数 | コードの意図が自明でない箇所のみ |
@doc """
Validates that the given coupon code is active and has remaining uses.
"""
@spec validate_coupon(String.t()) :: {:ok, Coupon.t()} | {:error, :expired | :exhausted}
def validate_coupon(code) do
# We query the read replica here to avoid adding load to the
# primary during high-traffic discount events.
Repo.replica().get_by(Coupon, code: code)
|> check_expiry()
|> check_remaining_uses()
end
@doc は、呼び出し側に validate_coupon/1 の動作と戻り値を伝えます。インラインコメントは、そうでなければ意外に思われる実装上の判断を説明します。
ドキュメントの完成(ゲート)
次のチェックを順番に行って完了してください。該当しないステップは省略します。
- doctest を追加または変更しましたか? プロジェクトの doctest 検証を実行します(通常は、影響を受けるモジュールを対象とした
mix test、またはテストスイート全体)。合格条件: doctest の失敗がないこと。 - 相互参照、バッククォート、または
m:リンクを追加または編集しましたか?mix docsを実行します。合格条件: コマンドが完了し、モジュール、コールバック、または不正なリンクに関する ExDoc の警告が解消されていること。 - 公開 API を新規追加または変更しましたか? 合格条件: エクスポートされたすべての
def/defmacroに意図的な@docまたは@doc falseがあり、すべての公開モジュールに、プロジェクトのポリシーに沿った@moduledocまたは@moduledoc falseがあること。
リファレンスを読み込むタイミング
- doctest の作成や doctest の失敗のデバッグ --> references/doctests.md
- モジュール、関数、型間のリンクの追加 --> references/cross-references.md
- ドキュメントでの注釈ブロック、タブ、書式設定の使用 --> references/admonitions-and-formatting.md