openclaw 网盘下载
OpenClaw

技能详情(站内镜像,无评论)

首页 > 技能库 > Elixir Writing Docs

Guides writing Elixir documentation with @moduledoc, @doc, @typedoc, doctests, cross-references, and metadata. Use when adding or improving documentation in...

开发与 DevOps

作者:Kevin Anderson @anderskev

许可证:MIT-0

MIT-0 ·免费使用、修改和重新分发。无需归因。

版本:v1.2.0

统计:⭐ 0 · 21 · 0 current installs · 0 all-time installs

0

安装量(当前) 0

🛡 VirusTotal:Pending · OpenClaw :良性

Package:anderskev/elixir-writing-docs

安全扫描(ClawHub)

  • VirusTotal:Pending
  • OpenClaw :良性

OpenClaw 评估

This is an instruction-only skill that provides guidance for writing Elixir documentation and does not request credentials, install code, or perform actions outside its stated purpose.

目的

The name and description (Elixir documentation guidance) match the contents: a detailed SKILL.md and three reference markdown files about doctests, cross-references, and formatting. There are no unexpected requirements (no binaries, env vars, or config paths).

说明范围

The runtime instructions are purely editorial: examples, formatting rules, and advice for ExDoc and doctests. They do not instruct the agent to read arbitrary files, access credentials, call external endpoints, or perform system-level operations beyond authoring documentation in .ex files.

安装机制

No install spec and no code files beyond documentation. Nothing is downloaded or written to disk by the skill itself, so install risk is minimal.

证书

The skill requests no environment variables, credentials, or config paths. The advice references common Elixir tooling (ExDoc, mix) but does not require access to them or to any secrets.

持久

always is false and the skill is user-invocable. It does not attempt to modify other skills or system settings. Autonomous invocation is allowed by platform default but is not combined with any privileged access.

综合结论

This skill is instruction-only documentation for writing Elixir @moduledoc/@doc/@typedoc and doctests; it contains no code, no installs, and requests no credentials—so installation risk is low. As with any third-party guidance, verify recommendations against your project's policies (e.g., whether to include runnable doctests for your codebase) and be mindful that the skill itself cannot run tests or change your repository—it's a writing aid. I…

安装(复制给龙虾 AI)

将下方整段复制到龙虾中文库对话中,由龙虾按 SKILL.md 完成安装。

请把本段交给龙虾中文库(龙虾 AI)执行:为本机安装 OpenClaw 技能「Elixir Writing Docs」。简介:Guides writing Elixir documentation with @moduledoc, @doc, @typedoc, doctests, …。
请 fetch 以下地址读取 SKILL.md 并按文档完成安装:https://raw.githubusercontent.com/openclaw/skills/refs/heads/main/skills/anderskev/elixir-writing-docs/SKILL.md
(来源:yingzhi8.cn 技能库)

SKILL.md

打开原始 SKILL.md(GitHub raw)

---
name: elixir-writing-docs
description: Guides writing Elixir documentation with @moduledoc, @doc, @typedoc, doctests, cross-references, and metadata. Use when adding or improving documentation in .ex files.
---

# Elixir Writing Docs

## Quick Reference

| Topic | Reference |
|-------|-----------|
| Doctests: syntax, gotchas, when to use | [references/doctests.md](references/doctests.md) |
| Cross-references and linking syntax | [references/cross-references.md](references/cross-references.md) |
| Admonitions, formatting, tabs | [references/admonitions-and-formatting.md](references/admonitions-and-formatting.md) |

## First-Line Summary Rule

ExDoc and tools like `mix docs` extract the first paragraph of `@moduledoc` and `@doc` as a summary. Keep the opening line concise and self-contained.

```elixir
# 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.
"""
```

The same rule applies to `@doc`:

```elixir
# 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 Structure

A well-structured `@moduledoc` follows this pattern:

```elixir
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
```

**Key points:**

- First paragraph is the summary (one to two sentences).
- `## Examples` shows realistic usage. Use doctests when the example is runnable.
- `## Configuration` documents required config keys. Omit this section if the module takes no config.
- Use second-level headings (`##`) only. First-level (`#`) is reserved for the module name in ExDoc output.

### Documenting Behaviour Modules

When defining a behaviour, document the expected callbacks:

```elixir
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 Structure

```elixir
@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
```

**Guidelines:**

- State what the function does, then what it returns.
- Document each option in a bulleted `## Options` section when the function accepts a keyword list.
- Place `@spec` between `@doc` and `def`. This is the conventional ordering.
- Include doctests for pure functions. Skip them for side-effecting functions (see [references/doctests.md](references/doctests.md)).

## @typedoc

Document custom types defined with `@type` or `@opaque`:

```elixir
@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()}
```

For `@opaque` types, the `@typedoc` is especially important because callers cannot inspect the structure.

## Metadata

### @doc since and @doc deprecated

```elixir
@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: # ...
```

You can combine metadata and the docstring in one attribute:

```elixir
@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:` works the same way for modules:

```elixir
@moduledoc since: "1.2.0"
@moduledoc """
Handles webhook signature verification for Stripe events.
"""
```

## When to Use @doc false / @moduledoc false

Suppress documentation when the module or function is not part of the public API:

```elixir
# 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: # ...
```

**Do NOT use `@doc false` on genuinely public functions.** If a function is exported and callers depend on it, document it. If it should not be called externally, make it private with `defp`.

## Documentation vs Code Comments

| | Documentation (`@moduledoc`, `@doc`) | Code Comments (`#`) |
|---|---|---|
| **Audience** | Users of your API | Developers reading source |
| **Purpose** | Contract: what it does, what it returns | Why a particular implementation choice was made |
| **Rendered** | Yes, by ExDoc in HTML/epub | No, visible only in source |
| **Required** | All public modules and functions | Only where code intent is non-obvious |

```elixir
@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
```

The `@doc` tells the caller what `validate_coupon/1` does and returns. The inline comment explains an implementation decision that would otherwise be surprising.

## When to Load References

- Writing doctests or debugging doctest failures --> [references/doctests.md](references/doctests.md)
- Adding links between modules, functions, types --> [references/cross-references.md](references/cross-references.md)
- Using admonition blocks, tabs, or formatting in docs --> [references/admonitions-and-formatting.md](references/admonitions-and-formatting.md)