docs: backfill TOC + decision trees, fix review findings

- Add ## Contents and ## Decision Tree to all 10 existing pattern files
- Fix embed_as/1 semantics inversion in types.md (:self → :dump)
- Fix fabricated __meta__.changes reference in changesets.md
- Fix default primary key type (:integer → :id) in schemas.md
- Combine @impl subsections into single "Minimal Callback Annotation"
This commit is contained in:
2026-05-01 22:13:35 -07:00
parent b33accf37c
commit 10218813d3
13 changed files with 356 additions and 87 deletions
+29
View File
@@ -2,6 +2,21 @@
Patterns extracted from the Elixir standard library source code.
## Contents
1. [Context-Aware Macros (__CALLER__.context)](#1-context-aware-macros-__caller__context)
2. [defguard — Macro for Guard-Safe Expressions](#2-defguard--macro-for-guard-safe-expressions)
3. [quote + unquote for Code Generation](#3-quote--unquote-for-code-generation)
4. [var! for Breaking Hygiene](#4-var-for-breaking-hygiene)
5. [Macro Expanding with Macro.expand](#5-macro-expanding-with-macroexpand)
6. [assert_no_match_or_guard_scope Pattern](#6-assert_no_match_or_guard_scope-pattern)
7. [Protocol Definition as a Macro (defprotocol)](#7-protocol-definition-as-a-macro-defprotocol)
8. [@fallback_to_any in Protocols](#8-fallback_to_any-in-protocols)
9. [use/2 as Macro Injection Point](#9-use2-as-macro-injection-point)
10. [Sigil Macros (Pattern for DSL Literals)](#10-sigil-macros-pattern-for-dsl-literals)
11. [Pipe Operator as a Macro](#11-pipe-operator-as-a-macro)
12. [Macro.generate_unique_arguments for Hygiene](#12-macrogenerate_unique_arguments-for-hygiene)
---
## 1. Context-Aware Macros (__CALLER__.context)
@@ -1105,4 +1120,18 @@ end
**Why:** Variables created in `quote` are already hygienic by default — they can't clash with caller variables. `generate_unique_arguments` is needed when you're generating *multiple* variables dynamically (e.g., function parameters for a generated clause) where you need distinct names that also interoperate correctly.
## Decision Tree
- If a macro must behave differently in guards vs normal code → check `__CALLER__.context` (Pattern 1)
- If you need a reusable, compile-time-validated guard expression → use `defguard` (Pattern 2)
- If a macro argument might have side effects or be expensive → use `quote bind_quoted:` to evaluate once (Pattern 3)
- If a macro must reference a variable in the caller's scope → use `var!` sparingly (Pattern 4)
- If the macro receives input that could be an alias or module attribute → expand with `Macro.expand` before branching (Pattern 5)
- If your macro defines module-level constructs and should never appear in guards → assert context at the top (Pattern 6)
- If you need open-ended type dispatch that external code can extend → use `defprotocol` (Pattern 7)
- If a protocol should handle any value rather than raising on unknown types → use `@fallback_to_any true` (Pattern 8)
- If a module needs injected behaviours, attributes, or compile hooks → use the `use/2` + `__using__/1` pattern (Pattern 9)
- If you have compile-time-known literals that benefit from validation → define a sigil macro (Pattern 10)
- If you need a zero-cost syntactic transformation (argument rewriting) → implement as a macro like `|>` (Pattern 11)
<!-- PATTERN_COMPLETE -->