{"id":33914867,"url":"https://github.com/unurgunite/docscribe","last_synced_at":"2026-04-02T16:25:28.276Z","repository":{"id":194077088,"uuid":"646836929","full_name":"unurgunite/docscribe","owner":"unurgunite","description":"Automated code documentation tool","archived":false,"fork":false,"pushed_at":"2026-03-23T22:09:10.000Z","size":356,"stargazers_count":1,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-03-24T14:35:02.290Z","etag":null,"topics":["ast","autodoc","ruby","yard"],"latest_commit_sha":null,"homepage":"https://rubygems.org/gems/docscribe","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/unurgunite.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-05-29T12:59:48.000Z","updated_at":"2026-03-23T16:59:13.000Z","dependencies_parsed_at":"2023-09-11T15:20:18.640Z","dependency_job_id":null,"html_url":"https://github.com/unurgunite/docscribe","commit_stats":null,"previous_names":["unurgunite/stingray_docs_internal","unurgunite/docscribe"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/unurgunite/docscribe","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unurgunite%2Fdocscribe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unurgunite%2Fdocscribe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unurgunite%2Fdocscribe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unurgunite%2Fdocscribe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/unurgunite","download_url":"https://codeload.github.com/unurgunite/docscribe/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unurgunite%2Fdocscribe/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31309834,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ast","autodoc","ruby","yard"],"created_at":"2025-12-12T06:43:08.970Z","updated_at":"2026-04-02T16:25:28.237Z","avatar_url":"https://github.com/unurgunite.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Docscribe\n\n[![Gem Version](https://img.shields.io/gem/v/docscribe.svg)](https://rubygems.org/gems/docscribe)\n[![RubyGems Downloads](https://img.shields.io/gem/dt/docscribe.svg)](https://rubygems.org/gems/docscribe)\n[![CI](https://github.com/unurgunite/docscribe/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/unurgunite/docscribe/actions/workflows/ci.yml)\n[![License](https://img.shields.io/github/license/unurgunite/docscribe.svg)](https://github.com/unurgunite/docscribe/blob/master/LICENSE.txt)\n[![Ruby](https://img.shields.io/badge/ruby-%3E%3D%202.7-blue.svg)](#installation)\n\nGenerate inline, YARD-style documentation comments for Ruby methods by analyzing your code's AST.\n\nDocscribe inserts doc headers before method definitions, infers parameter and return types (including rescue-aware\nreturns), and respects Ruby visibility semantics — without using YARD to parse.\n\n- No AST reprinting. Your original code, formatting, and constructs (like `class \u003c\u003c self`, `heredocs`, `%i[]`) are\n  preserved.\n- Inline-first. Comments are inserted before method headers without reprinting the AST. For methods with a leading\n  Sorbet `sig`, new docs are inserted above the first `sig`.\n- Heuristic type inference for params and return values, including conditional returns in rescue branches.\n- Safe and aggressive update modes:\n    - safe mode inserts missing docs, merges existing doc-like blocks, and normalizes sortable tags;\n    - aggressive mode rebuilds existing doc blocks.\n- Ruby 3.4+ syntax supported using Prism translation (see \"Parser backend\" below).\n- Optional external type integrations:\n    - RBS via `--rbs` / `--sig-dir`;\n    - Sorbet via inline `sig` declarations and RBI files with `--sorbet` / `--rbi-dir`.\n- Optional `@!attribute` generation for:\n    - `attr_reader` / `attr_writer` / `attr_accessor`;\n    - `Struct.new` declarations in both constant-assigned and class-based styles.\n\nCommon workflows:\n\n- Inspect what safe doc updates would be applied: `docscribe lib`\n- Apply safe doc updates: `docscribe -a lib`\n- Apply aggressive doc updates: `docscribe -A lib`\n- Use RBS signatures when available: `docscribe -a --rbs --sig-dir sig lib`\n- Use Sorbet signatures when available: `docscribe -a --sorbet --rbi-dir sorbet/rbi lib`\n\n## Contents\n\n* [Docscribe](#docscribe)\n    * [Contents](#contents)\n    * [Installation](#installation)\n    * [Quick start](#quick-start)\n    * [CLI](#cli)\n        * [Options](#options)\n        * [Examples](#examples)\n    * [Update strategies](#update-strategies)\n        * [Safe strategy](#safe-strategy)\n        * [Aggressive strategy](#aggressive-strategy)\n        * [Output markers](#output-markers)\n    * [Parser backend (Parser gem vs Prism)](#parser-backend-parser-gem-vs-prism)\n    * [External type integrations (optional)](#external-type-integrations-optional)\n        * [RBS](#rbs)\n        * [Sorbet](#sorbet)\n        * [Inline Sorbet example](#inline-sorbet-example)\n        * [Sorbet RBI example](#sorbet-rbi-example)\n        * [Sorbet comment placement](#sorbet-comment-placement)\n        * [Generic type formatting](#generic-type-formatting)\n        * [Notes and fallback behavior](#notes-and-fallback-behavior)\n    * [Type inference](#type-inference)\n    * [Rescue-aware returns and @raise](#rescue-aware-returns-and-raise)\n    * [Visibility semantics](#visibility-semantics)\n    * [API (library) usage](#api-library-usage)\n    * [Configuration](#configuration)\n        * [Filtering](#filtering)\n        * [`attr_*` example](#attr_-example)\n        * [`Struct.new` examples](#structnew-examples)\n            * [Constant-assigned struct](#constant-assigned-struct)\n            * [Class-based struct](#class-based-struct)\n        * [Merge behavior](#merge-behavior)\n        * [Param tag style](#param-tag-style)\n        * [Create a starter config](#create-a-starter-config)\n    * [CI integration](#ci-integration)\n    * [Comparison to YARD's parser](#comparison-to-yards-parser)\n    * [Limitations](#limitations)\n    * [Roadmap](#roadmap)\n    * [Contributing](#contributing)\n    * [License](#license)\n\n## Installation\n\nAdd to your Gemfile:\n\n```ruby\ngem \"docscribe\"\n```\n\nThen:\n\n```shell\nbundle install\n```\n\nOr install globally:\n\n```shell\ngem install docscribe\n```\n\nRequires Ruby 2.7+.\n\n## Quick start\n\nGiven code:\n\n```ruby\n\nclass Demo\n  def foo(a, options: {})\n    42\n  end\n\n  def bar(verbose: true)\n    123\n  end\n\n  private\n\n  def self.bump\n    :ok\n  end\n\n  class \u003c\u003c self\n    private\n\n    def internal; end\n  end\nend\n```\n\nRun:\n\n```shell\necho \"...code above...\" | docscribe --stdin\n```\n\nOutput:\n\n```ruby\nclass Demo\n  # +Demo#foo+ -\u003e Integer\n  #\n  # Method documentation.\n  #\n  # @param [Object] a Param documentation.\n  # @param [Hash] options Param documentation.\n  # @return [Integer]\n  def foo(a, options: {})\n    42\n  end\n\n  # +Demo#bar+ -\u003e Integer\n  #\n  # Method documentation.\n  #\n  # @param [Boolean] verbose Param documentation.\n  # @return [Integer]\n  def bar(verbose: true)\n    123\n  end\n\n  private\n\n  # +Demo.bump+ -\u003e Symbol\n  #\n  # Method documentation.\n  #\n  # @return [Symbol]\n  def self.bump\n    :ok\n  end\n\n  class \u003c\u003c self\n    private\n\n    # +Demo.internal+ -\u003e Object\n    #\n    # Method documentation.\n    #\n    # @private\n    # @return [Object]\n    def internal; end\n  end\nend\n```\n\n\u003e [!NOTE]\n\u003e - The tool inserts doc headers before method headers and preserves everything else.\n\u003e - For methods with a leading Sorbet `sig`, docs are inserted above the first `sig`.\n\u003e - Class methods show with a dot (`+Demo.bump+`, `+Demo.internal+`).\n\u003e - Methods inside `class \u003c\u003c self` under `private` are marked `@private`.\n\n## CLI\n\n```shell\ndocscribe [options] [files...]\n```\n\nDocscribe has three main ways to run:\n\n- **Inspect mode** (default): checks what safe doc updates would be applied and exits non-zero if files need changes.\n- **Safe autocorrect** (`-a`, `--autocorrect`): writes safe, non-destructive updates in place.\n- **Aggressive autocorrect** (`-A`, `--autocorrect-all`): rewrites existing doc blocks more aggressively.\n- **STDIN mode** (`--stdin`): reads Ruby source from STDIN and prints rewritten source to STDOUT.\n\nIf you pass no files and don’t use `--stdin`, Docscribe processes the current directory recursively.\n\n### Options\n\n- `-a`, `--autocorrect`  \n  Apply safe doc updates in place.\n\n- `-A`, `--autocorrect-all`  \n  Apply aggressive doc updates in place.\n\n- `--stdin`  \n  Read source from STDIN and print rewritten output.\n\n- `--verbose`  \n  Print per-file actions.\n\n- `--explain`  \n  Show detailed reasons for each file that would change.\n\n- `--rbs`  \n  Use RBS signatures for `@param`/`@return` when available (falls back to inference).\n\n- `--sig-dir DIR`  \n  Add an RBS signature directory (repeatable). Implies `--rbs`.\n\n- `--include PATTERN`  \n  Include PATTERN (method id or file path; glob or `/regex/`).\n\n- `--exclude PATTERN`  \n  Exclude PATTERN (method id or file path; glob or `/regex/`). Exclude wins.\n\n- `--include-file PATTERN`  \n  Only process files matching PATTERN (glob or `/regex/`).\n\n- `--exclude-file PATTERN`  \n  Skip files matching PATTERN (glob or `/regex/`). Exclude wins.\n\n- `-C`, `--config PATH`  \n  Path to config YAML (default: `docscribe.yml`).\n\n- `-v`, `--version`  \n  Print version and exit.\n\n- `-h`, `--help`  \n  Show help.\n\n### Examples\n\n- Inspect a directory:\n  ```shell\n  docscribe lib\n  ```\n\n- Apply safe updates:\n  ```shell\n  docscribe -a lib\n  ```\n\n- Apply aggressive updates:\n  ```shell\n  docscribe -A lib\n  ```\n\n- Preview output for a single file via STDIN:\n  ```shell\n  cat path/to/file.rb | docscribe --stdin\n  ```\n\n- Use RBS signatures:\n  ```shell\n  docscribe -a --rbs --sig-dir sig lib\n  ```\n\n- Show detailed reasons for files that would change:\n  ```shell\n  docscribe --verbose --explain lib\n  ```\n\n## Update strategies\n\nDocscribe supports two update strategies: **safe** and **aggressive**.\n\n### Safe strategy\n\nUsed by:\n\n- default inspect mode: `docscribe lib`\n- safe write mode: `docscribe -a lib`\n\nSafe strategy:\n\n- inserts docs for undocumented methods\n- merges missing tags into existing **doc-like** blocks\n- normalizes configurable tag order inside sortable tag runs\n- preserves existing prose and comments where possible\n\nThis is the recommended day-to-day mode.\n\n### Aggressive strategy\n\nUsed by:\n\n- aggressive write mode: `docscribe -A lib`\n\nAggressive strategy:\n\n- rebuilds existing doc blocks\n- replaces existing generated documentation more fully\n- is more invasive than safe mode\n\nUse it when you want to rebaseline or regenerate docs wholesale.\n\n### Output markers\n\nIn inspect mode, Docscribe prints one character per file:\n\n- `.` = file is up to date\n- `F` = file would change\n- `E` = file had an error\n\nIn write modes:\n\n- `.` = file already OK\n- `C` = file was updated\n- `E` = file had an error\n\nWith `--verbose`, Docscribe prints per-file statuses instead.\n\nWith `--explain`, Docscribe also prints detailed reasons, such as:\n\n- missing `@param`\n- missing `@return`\n- missing module_function note\n- unsorted tags\n\n## Parser backend (Parser gem vs Prism)\n\nDocscribe internally works with `parser`-gem-compatible AST nodes and `Parser::Source::*` objects (so it can use\n`Parser::Source::TreeRewriter` without changing formatting).\n\n- On Ruby **\u003c= 3.3**, Docscribe parses using the `parser` gem.\n- On Ruby **\u003e= 3.4**, Docscribe parses using **Prism** and translates the tree into the `parser` gem's AST.\n\nYou can force a backend with an environment variable:\n\n```shell\nDOCSCRIBE_PARSER_BACKEND=parser bundle exec docscribe lib\nDOCSCRIBE_PARSER_BACKEND=prism  bundle exec docscribe lib\n```\n\n## External type integrations (optional)\n\nDocscribe can improve generated `@param` and `@return` types by reading external signatures instead of relying only on\nAST inference.\n\n\u003e [!IMPORTANT]\n\u003e When external type information is available, Docscribe resolves signatures in this order:\n\u003e - inline Sorbet `sig` declarations in the current Ruby source;\n\u003e - Sorbet RBI files;\n\u003e - RBS files;\n\u003e - AST inference fallback.\n\u003e\n\u003e If an external signature cannot be loaded or parsed, Docscribe falls back to normal inference instead of failing.\n\n### RBS\n\nDocscribe can read method signatures from `.rbs` files and use them to generate more accurate parameter and return\ntypes.\n\nCLI:\n\n```shell\ndocscribe -a --rbs --sig-dir sig lib\n```\n\nYou can pass `--sig-dir` multiple times:\n\n```shell\ndocscribe -a --rbs --sig-dir sig --sig-dir vendor/sigs lib\n```\n\nConfig:\n\n```yaml\nrbs:\n  enabled: true\n  sig_dirs:\n    - sig\n  collapse_generics: false\n```\n\nExample:\n\n```ruby\n# Ruby source\nclass Demo\n  def foo(verbose:, count:)\n    \"body says String\"\n  end\nend\n```\n\n```ruby.rbs\n# sig/demo.rbs\nclass Demo\n    def foo: (verbose: bool, count: Integer) -\u003e Integer\nend\n```\n\nGenerated docs will prefer the RBS signature over inferred Ruby types:\n\n```ruby\n\nclass Demo\n  # +Demo#foo+ -\u003e Integer\n  #\n  # Method documentation.\n  #\n  # @param [Boolean] verbose Param documentation.\n  # @param [Integer] count Param documentation.\n  # @return [Integer]\n  def foo(verbose:, count:)\n    'body says String'\n  end\nend\n```\n\n### Sorbet\n\nDocscribe can also read Sorbet signatures from:\n\n- inline `sig` declarations in Ruby source\n- RBI files\n\nCLI:\n\n```shell\ndocscribe -a --sorbet lib\n```\n\nWith RBI directories:\n\n```shell\ndocscribe -a --sorbet --rbi-dir sorbet/rbi lib\n```\n\nYou can pass `--rbi-dir` multiple times:\n\n```shell\ndocscribe -a --sorbet --rbi-dir sorbet/rbi --rbi-dir rbi lib\n```\n\nConfig:\n\n```yaml\nsorbet:\n  enabled: true\n  rbi_dirs:\n    - sorbet/rbi\n    - rbi\n  collapse_generics: false\n```\n\n### Inline Sorbet example\n\n```ruby\nclass Demo\n  extend T::Sig\n\n  sig { params(verbose: T::Boolean, count: Integer).returns(Integer) }\n  def foo(verbose:, count:)\n    'body says String'\n  end\nend\n```\n\nDocscribe will use the Sorbet signature instead of the inferred body type:\n\n```ruby\nclass Demo\n  extend T::Sig\n\n  # +Demo#foo+ -\u003e Integer\n  #\n  # Method documentation.\n  #\n  # @param [Boolean] verbose Param documentation.\n  # @param [Integer] count Param documentation.\n  # @return [Integer]\n  sig { params(verbose: T::Boolean, count: Integer).returns(Integer) }\n  def foo(verbose:, count:)\n    'body says String'\n  end\nend\n```\n\n### Sorbet RBI example\n\n```ruby\n# Ruby source\nclass Demo\n  def foo(verbose:, count:)\n    'body says String'\n  end\nend\n```\n\n```ruby\n# sorbet/rbi/demo.rbi\nclass Demo\n  extend T::Sig\n\n  sig { params(verbose: T::Boolean, count: Integer).returns(Integer) }\n  def foo(verbose:, count:); end\nend\n```\n\nWith:\n\n```shell\ndocscribe -a --sorbet --rbi-dir sorbet/rbi lib\n```\n\nDocscribe will use the RBI signature for generated docs.\n\n### Sorbet comment placement\n\nFor methods with a leading Sorbet `sig`, Docscribe treats the signature as part of the method header.\n\nThat means:\n\n- new docs are inserted **above the first `sig`**\n- existing docs **above the `sig`** are recognized and merged\n- existing legacy docs **between `sig` and `def`** are also recognized\n\nExample input:\n\n```ruby\n# demo.rb\nclass Demo\n  extend T::Sig\n\n  sig { returns(Integer) }\n  def foo\n    1\n  end\nend\n```\n\nExample output:\n\n```ruby\n# demo.rb\nclass Demo\n  extend T::Sig\n\n  # +Demo#foo+ -\u003e Integer\n  #\n  # Method documentation.\n  #\n  # @return [Integer]\n  sig { returns(Integer) }\n  def foo\n    1\n  end\nend\n```\n\n### Generic type formatting\n\nBoth RBS and Sorbet integrations support `collapse_generics`.\n\nWhen disabled:\n\n```yaml\nrbs:\n  collapse_generics: false\n\nsorbet:\n  collapse_generics: false\n```\n\nDocscribe preserves generic container details where possible, for example:\n\n- `Array\u003cString\u003e`\n- `Hash\u003cSymbol, Integer\u003e`\n\nWhen enabled:\n\n```yaml\nrbs:\n  collapse_generics: true\n\nsorbet:\n  collapse_generics: true\n```\n\nDocscribe simplifies container types to their outer names, for example:\n\n- `Array`\n- `Hash`\n\n### Notes and fallback behavior\n\n- External signature support is the **best effort**.\n- If a signature source cannot be loaded or parsed, Docscribe falls back to AST inference.\n- RBS and Sorbet integrations are used only to improve generated types; Docscribe still rewrites Ruby source directly.\n- Sorbet support does not require changing your documentation style — it only improves generated `@param` and `@return`\n  tags when signatures are available.\n\n## Type inference\n\nHeuristics (best-effort).\n\nParameters:\n\n- `*args` -\u003e `Array`\n- `**kwargs` -\u003e `Hash`\n- `\u0026block` -\u003e `Proc`\n- keyword args:\n    - `verbose: true` -\u003e `Boolean`\n    - `options: {}` -\u003e `Hash`\n    - `kw:` (no default) -\u003e `Object`\n- positional defaults:\n    - `42` -\u003e `Integer`, `1.0` -\u003e `Float`, `'x'` -\u003e `String`, `:ok` -\u003e `Symbol`\n    - `[]` -\u003e `Array`, `{}` -\u003e `Hash`, `/x/` -\u003e `Regexp`, `true`/`false` -\u003e `Boolean`, `nil` -\u003e `nil`\n\nReturn values:\n\n- For simple bodies, Docscribe looks at the last expression or explicit `return`.\n- Unions with `nil` become optional types (e.g. `String` or `nil` -\u003e `String?`).\n- For control flow (`if`/`case`), it unifies branches conservatively.\n\n## Rescue-aware returns and @raise\n\nDocscribe detects exceptions and rescue branches:\n\n- Rescue exceptions become `@raise` tags:\n    - `rescue Foo, Bar` -\u003e `@raise [Foo]` and `@raise [Bar]`\n    - bare rescue -\u003e `@raise [StandardError]`\n    - explicit `raise`/`fail` also adds a tag (`raise Foo` -\u003e `@raise [Foo]`, `raise` -\u003e `@raise [StandardError]`)\n\n- Conditional return types for rescue branches:\n    - Docscribe adds `@return [Type] if ExceptionA, ExceptionB` for each rescue clause\n\n## Visibility semantics\n\nWe match Ruby's behavior:\n\n- A bare `private`/`protected`/`public` in a class/module body affects instance methods only.\n- Inside `class \u003c\u003c self`, a bare visibility keyword affects class methods only.\n- `def self.x` in a class body remains `public` unless `private_class_method` is used, or it's inside `class \u003c\u003c self`\n  under `private`.\n\nInline tags:\n\n- `@private` is added for methods that are private in context.\n- `@protected` is added similarly for protected methods.\n\n\u003e [!IMPORTANT]\n\u003e `module_function`: Docscribe documents methods affected by `module_function` as module methods (`M.foo`) rather than\n\u003e instance methods (`M#foo`), because that is usually the callable/public API. If a method was previously private as an\n\u003e instance method, Docscribe will avoid marking the generated docs as `@private` after it is promoted to a module\n\u003e method.\n\n```ruby\nmodule M\n  private\n\n  def foo; end\n\n  module_function :foo\nend\n```\n\n## API (library) usage\n\n```ruby\nrequire \"docscribe/inline_rewriter\"\n\ncode = \u003c\u003c~RUBY\n  class Demo\n    def foo(a, options: {}); 42; end\n    class \u003c\u003c self; private; def internal; end; end\n  end\nRUBY\n\n# Basic insertion behavior\nout = Docscribe::InlineRewriter.insert_comments(code)\nputs out\n\n# Safe merge / normalization of existing doc-like blocks\nout2 = Docscribe::InlineRewriter.insert_comments(code, strategy: :safe)\n\n# Aggressive rebuild of existing doc blocks (similar to CLI -A)\nout3 = Docscribe::InlineRewriter.insert_comments(code, strategy: :aggressive)\n```\n\n## Configuration\n\nDocscribe can be configured via a YAML file (`docscribe.yml` by default, or pass `--config PATH`).\n\n### Filtering\n\nDocscribe can filter both *files* and *methods*.\n\nFile filtering (recommended for excluding specs, vendor code, etc.):\n\n```yaml\nfilter:\n  files:\n    exclude: [ \"spec\" ]\n```\n\nMethod filtering matches method ids like:\n\n- `MyModule::MyClass#instance_method`\n- `MyModule::MyClass.class_method`\n\nExample:\n\n```yaml\nfilter:\n  exclude:\n    - \"*#initialize\"\n```\n\nCLI overrides are available too:\n\n```shell\n# Method filtering (matches method ids like A#foo / A.bar)\ndocscribe --exclude '*#initialize' lib\ndocscribe --include '/^MyModule::.*#(foo|bar)$/' lib\n\n# File filtering (matches paths relative to the project root)\ndocscribe --exclude-file 'spec' lib spec\ndocscribe --exclude-file '/^spec\\//' lib\n```\n\n\u003e [!NOTE]\n\u003e `/regex/` passed to `--include`/`--exclude` is treated as a **method-id** pattern. Use `--include-file` /\n`--exclude-file` for file regex filters.\n\nEnable attribute-style documentation generation with:\n\n```yaml\nemit:\n  attributes: true\n```\n\nWhen enabled, Docscribe can generate YARD `@!attribute` docs for:\n\n- `attr_reader`\n- `attr_writer`\n- `attr_accessor`\n- `Struct.new` declarations\n\n### `attr_*` example\n\n\u003e [!NOTE]\n\u003e - Attribute docs are inserted above the `attr_*` call, not above generated methods (since they don’t exist as `def`\n    nodes).\n\u003e - If RBS is enabled, Docscribe will try to use the RBS return type of the reader method as the attribute type.\n\n```ruby\nclass User\n  attr_accessor :name\nend\n```\n\nGenerated docs:\n\n```ruby\nclass User\n  # @!attribute [rw] name\n  #   @return [Object]\n  #   @param [Object] value\n  attr_accessor :name\nend\n```\n\n### `Struct.new` examples\n\nDocscribe supports both common `Struct.new` declaration styles.\n\n#### Constant-assigned struct\n\n```ruby\nUser = Struct.new(:name, :email, keyword_init: true)\n```\n\nGenerated docs:\n\n```ruby\n# @!attribute [rw] name\n#   @return [Object]\n#   @param [Object] value\n#\n# @!attribute [rw] email\n#   @return [Object]\n#   @param [Object] value\nUser = Struct.new(:name, :email, keyword_init: true)\n```\n\n#### Class-based struct\n\n```ruby\nclass User \u003c Struct.new(:name, :email, keyword_init: true)\nend\n```\n\nGenerated docs:\n\n```ruby\n# @!attribute [rw] name\n#   @return [Object]\n#   @param [Object] value\n#\n# @!attribute [rw] email\n#   @return [Object]\n#   @param [Object] value\nclass User \u003c Struct.new(:name, :email, keyword_init: true)\nend\n```\n\nDocscribe preserves the original declaration style and does not rewrite one form into the other.\n\n### Merge behavior\n\nStruct member docs use the same attribute documentation pipeline as `attr_*` macros, which means they participate in the\nnormal safe/aggressive rewrite flow.\n\nIn safe mode, Docscribe can:\n\n- insert full `@!attribute` docs when no doc-like block exists\n- append missing struct member docs into an existing doc-like block\n\n### Param tag style\n\nGenerated writer-style attribute docs respect `doc.param_tag_style`.\n\nFor example, with:\n\n```yaml\ndoc:\n  param_tag_style: \"type_name\"\n```\n\nwriter params are emitted as:\n\n```ruby\n#   @param [Object] value\n```\n\nWith:\n\n```yaml\ndoc:\n  param_tag_style: \"name_type\"\n```\n\nthey are emitted as:\n\n```ruby\n#   @param value [Object]\n```\n\n### Create a starter config\n\nCreate `docscribe.yml` in the current directory:\n\n```shell\ndocscribe init\n```\n\nWrite to a custom path:\n\n```shell\ndocscribe init --config config/docscribe.yml\n```\n\nOverwrite if it already exists:\n\n```shell\ndocscribe init --force\n```\n\nPrint the template to stdout:\n\n```shell\ndocscribe init --stdout\n```\n\n## CI integration\n\nFail the build if files would need safe updates:\n\n```yaml\n- name: Check inline docs\n  run: docscribe lib\n```\n\nApply safe fixes before the test stage:\n\n```yaml\n- name: Apply safe inline docs\n  run: docscribe -a lib\n```\n\nAggressively rebuild docs:\n\n```yaml\n- name: Rebuild inline docs\n  run: docscribe -A lib\n```\n\n## Comparison to YARD's parser\n\nDocscribe and YARD solve different parts of the documentation problem:\n\n- Docscribe inserts/updates inline comments by rewriting source.\n- YARD can generate HTML docs based on inline comments.\n\nRecommended workflow:\n\n- Use Docscribe to seed and maintain inline docs with inferred tags/types.\n- Optionally use YARD (dev-only) to render HTML from those comments:\n\n```shell\nyard doc -o docs\n```\n\n## Limitations\n\n- Safe mode only merges into existing **doc-like** comment blocks. Ordinary comments that are not recognized as\n  documentation are preserved and treated conservatively.\n- Type inference is heuristic. Complex flows and meta-programming will fall back to `Object` or best-effort types.\n- Aggressive mode (`-A`) replaces existing doc blocks and should be reviewed carefully.\n\n## Roadmap\n\n- Effective config dump;\n- JSON output;\n- Overload-aware signature selection;\n- Manual `@!attribute` merge policy;\n- Richer inference for common APIs;\n- Editor integration.\n\n## Contributing\n\n```shell\nbundle exec rspec\nbundle exec rubocop\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funurgunite%2Fdocscribe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Funurgunite%2Fdocscribe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funurgunite%2Fdocscribe/lists"}