mcpField
E
elixir-writing-docs

elixir-writing-docs

github.com/existential-birds开发85100 次安装11 周前更新
代码仓库

关于 elixir-writing-docs

面向 Elixir 开发者的文档编写 Skill,依据 ExDoc 约定讲解文档字符串、doctest、交叉引用与格式。帮助为模块和公开函数组织并检查文档。

主要功能

  1. 01首段摘要编写规则
  2. 02模块与函数文档结构
  3. 03doctest 与交叉引用指引
  4. 04格式与提示块参考
  5. 05文档完成检查

适用场景

  1. 01撰写简洁的 @moduledoc 和 @doc
  2. 02为 API 文档添加示例与 doctest
  3. 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.md
cross-references.md
doctests.md

详细介绍

Elixir 文档编写

快速参考

主题参考资料
Doctest:语法、注意事项、适用场景references/doctests.md
交叉引用和链接语法references/cross-references.md
提示框、格式设置、选项卡references/admonitions-and-formatting.md

首行摘要规则

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

要点:

  • 第一段是摘要(一到两句话)。
  • ## Examples 展示真实的用法。示例可运行时,使用 doctest。
  • ## Configuration 说明必需的配置键。如果模块不需要配置,则省略此部分。
  • 仅使用二级标题(##)。一级标题(#)保留给 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: # ...

你可以将元数据和文档字符串合并到同一个属性中:

@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 的功能和返回值。内联注释则解释一项可能令人意外的实现决策。

完成文档编写(检查关卡)

最后按顺序完成以下检查。不适用的步骤可以跳过。

  1. 添加或修改了 Doctest? 运行项目的 doctest 验证(通常是针对受影响模块运行 mix test,或运行完整测试套件)。**通过标准:**没有 doctest 失败。
  2. 添加或编辑了交叉引用、反引号或 m: 链接? 运行 mix docs。**通过标准:**命令顺利完成;解决 ExDoc 关于缺少模块、回调或错误链接的警告。
  3. 新增或修改了公共 API? **通过标准:**每个导出的 def / defmacro 都有明确的 @doc 或 @doc false,且每个公共模块都有 @moduledoc 或 @moduledoc false,并符合项目的策略。

何时加载参考资料

评论

支持 Markdown