Docscribe

Gem Version RubyGems Downloads CI License Ruby

Docscribe before/after demo

Generate inline, YARD-style documentation comments for Ruby methods by analyzing your code's AST.

Docscribe inserts doc headers before method definitions, infers parameter and return types (including rescue-aware returns), and respects Ruby visibility semantics — without using YARD to parse.

  • No AST reprinting. Your original code, formatting, and constructs (like class << self, heredocs, %i[]) are preserved.
  • Inline-first. Comments are inserted before method headers without reprinting the AST. For methods with a leading Sorbet sig, new docs are inserted above the first sig.
  • Heuristic type inference for params and return values, including conditional returns in rescue branches.
  • Safe and aggressive update modes:
    • safe mode inserts missing docs, merges existing doc-like blocks, and normalizes sortable tags;
    • aggressive mode rebuilds existing doc blocks.
  • Ruby 3.4+ syntax supported using Prism translation (see "Parser backend" below).
  • Optional external type integrations:
    • RBS via --rbs / --sig-dir;
    • Sorbet via inline sig declarations and RBI files with --sorbet / --rbi-dir.
  • Optional @!attribute generation for:
    • attr_reader / attr_writer / attr_accessor;
    • Struct.new declarations in both constant-assigned and class-based styles.

Common workflows:

  • Inspect what safe doc updates would be applied: docscribe lib
  • Apply safe doc updates: docscribe -a lib
  • Apply aggressive doc updates: docscribe -A lib
  • Use RBS gem collection signatures: docscribe -a --rbs-collection lib
  • Use RBS signatures when available: docscribe -a --rbs --sig-dir sig lib
  • Use Sorbet signatures when available: docscribe -a --sorbet --rbi-dir sorbet/rbi lib

Contents

Installation

Add to your Gemfile:

gem "docscribe"

Then:

bundle install

Or install globally:

gem install docscribe

Requires Ruby 2.7+.

Quick start

Given code:

class Demo
  def foo(a, options: {})
    42
  end

  def bar(verbose: true)
    123
  end

  private

  def self.bump
    :ok
  end

  class << self
    private

    def internal; end
  end
end

Run:

echo "...code above..." | docscribe --stdin

Output:

class Demo
  # +Demo#foo+ -> Integer
  #
  # Method documentation.
  #
  # @param [Object] a Param documentation.
  # @param [Hash] options Param documentation.
  # @return [Integer]
  def foo(a, options: {})
    42
  end

  # +Demo#bar+ -> Integer
  #
  # Method documentation.
  #
  # @param [Boolean] verbose Param documentation.
  # @return [Integer]
  def bar(verbose: true)
    123
  end

  private

  # +Demo.bump+ -> Symbol
  #
  # Method documentation.
  #
  # @return [Symbol]
  def self.bump
    :ok
  end

  class << self
    private

    # +Demo.internal+ -> Object
    #
    # Method documentation.
    #
    # @private
    # @return [Object]
    def internal; end
  end
end

[!NOTE]

  • The tool inserts doc headers before method headers and preserves everything else.
  • For methods with a leading Sorbet sig, docs are inserted above the first sig.
  • Class methods show with a dot (+Demo.bump+, +Demo.internal+).
  • Methods inside class << self under private are marked @private.

CLI

docscribe [options] [files...]

Docscribe has three main ways to run:

  • Inspect mode (default): checks what safe doc updates would be applied and exits non-zero if files need changes.
  • Safe autocorrect (-a, --autocorrect): writes safe, non-destructive updates in place.
  • Aggressive autocorrect (-A, --autocorrect-all): rewrites existing doc blocks more aggressively.
  • STDIN mode (--stdin): reads Ruby source from STDIN and prints rewritten source to STDOUT.

If you pass no files and don’t use --stdin, Docscribe processes the current directory recursively.

Options

  • -a, --autocorrect
    Apply safe doc updates in place.

  • -A, --autocorrect-all
    Apply aggressive doc updates in place.

  • --rbs-collection
    Auto-discover the RBS collection directory from rbs_collection.lock.yaml.
    Reads the path: field written by bundle exec rbs collection install and adds
    it to the signature search path automatically. Implies --rbs.

  • --stdin
    Read source from STDIN and print rewritten output.

  • --verbose
    Print per-file actions.

  • --explain
    Show detailed reasons for each file that would change.

  • --rbs
    Use RBS signatures for @param/@return when available (falls back to inference).

  • --sig-dir DIR
    Add an RBS signature directory (repeatable). Implies --rbs.

  • --include PATTERN
    Include PATTERN (method id or file path; glob or /regex/).

  • --exclude PATTERN
    Exclude PATTERN (method id or file path; glob or /regex/). Exclude wins.

  • --include-file PATTERN
    Only process files matching PATTERN (glob or /regex/).

  • --exclude-file PATTERN
    Skip files matching PATTERN (glob or /regex/). Exclude wins.

  • -C, --config PATH
    Path to config YAML (default: docscribe.yml).

  • -v, --version
    Print version and exit.

  • -h, --help
    Show help.

Examples

  • Inspect a directory:

    docscribe lib
    
  • Apply safe updates:

    docscribe -a lib
    
  • Apply aggressive updates:

    docscribe -A lib
    
  • Preview output for a single file via STDIN:

    cat path/to/file.rb | docscribe --stdin
    
  • Use RBS signatures:

    docscribe -a --rbs --sig-dir sig lib
    
  • Use RBS signatures with auto-discovered gem collection:

    docscribe -a --rbs-collection lib
    
  • Combine collection auto-discovery with a custom sig directory:

    docscribe -a --rbs-collection --sig-dir sig lib
    
  • Show detailed reasons for files that would change:

    docscribe --verbose --explain lib
    

Update strategies

Docscribe supports two update strategies: safe and aggressive.

Safe strategy

Used by:

  • default inspect mode: docscribe lib
  • safe write mode: docscribe -a lib

Safe strategy:

  • inserts docs for undocumented methods
  • merges missing tags into existing doc-like blocks
  • normalizes configurable tag order inside sortable tag runs
  • preserves existing prose and comments where possible

This is the recommended day-to-day mode.

Aggressive strategy

Used by:

  • aggressive write mode: docscribe -A lib

Aggressive strategy:

  • rebuilds existing doc blocks
  • replaces existing generated documentation more fully
  • is more invasive than safe mode

Use it when you want to rebaseline or regenerate docs wholesale.

Output markers

In inspect mode, Docscribe prints one character per file:

  • . = file is up to date
  • F = file would change
  • E = file had an error

In write modes:

  • . = file already OK
  • C = file was updated
  • E = file had an error

With --verbose, Docscribe prints per-file statuses instead.

With --explain, Docscribe also prints detailed reasons, such as:

  • missing @param
  • missing @return
  • missing module_function note
  • unsorted tags

Parser backend (Parser gem vs Prism)

Docscribe internally works with parser-gem-compatible AST nodes and Parser::Source::* objects (so it can use Parser::Source::TreeRewriter without changing formatting).

  • On Ruby <= 3.3, Docscribe parses using the parser gem.
  • On Ruby >= 3.4, Docscribe parses using Prism and translates the tree into the parser gem's AST.

You can force a backend with an environment variable:

DOCSCRIBE_PARSER_BACKEND=parser bundle exec docscribe lib
DOCSCRIBE_PARSER_BACKEND=prism  bundle exec docscribe lib

External type integrations (optional)

Docscribe can improve generated @param and @return types by reading external signatures instead of relying only on AST inference.

[!IMPORTANT] When external type information is available, Docscribe resolves signatures in this order:

  • inline Sorbet sig declarations in the current Ruby source;
  • Sorbet RBI files;
  • RBS files;
  • AST inference fallback.

If an external signature cannot be loaded or parsed, Docscribe falls back to normal inference instead of failing.

RBS

Docscribe can read method signatures from .rbs files and use them to generate more accurate parameter and return types.

CLI:

docscribe -a --rbs --sig-dir sig lib

You can pass --sig-dir multiple times:

docscribe -a --rbs --sig-dir sig --sig-dir vendor/sigs lib

Config:

rbs:
  enabled: true
  sig_dirs:
    - sig
  collapse_generics: false

Example:

# Ruby source
class Demo
  def foo(verbose:, count:)
    "body says String"
  end
end
# sig/demo.rbs
class Demo
    def foo: (verbose: bool, count: Integer) -> Integer
end

Generated docs will prefer the RBS signature over inferred Ruby types:

class Demo
  # +Demo#foo+ -> Integer
  #
  # Method documentation.
  #
  # @param [Boolean] verbose Param documentation.
  # @param [Integer] count Param documentation.
  # @return [Integer]
  def foo(verbose:, count:)
    'body says String'
  end
end

RBS collection auto-discovery

If your project uses rbs collection, Docscribe can discover the installed gem signatures automatically without requiring you to pass --sig-dir manually.

Setup:

# 1. Initialize the collection config (one-time)
bundle exec rbs collection init

# 2. Install gem signatures
bundle exec rbs collection install

This produces rbs_collection.lock.yaml and .gem_rbs_collection/ in your project root.

Usage:

docscribe -a --rbs-collection lib

Docscribe reads the path: field from rbs_collection.lock.yaml and adds the resolved directory to the signature search path. If no path: is set, it falls back to .gem_rbs_collection.

You can combine --rbs-collection with --sig-dir to mix gem signatures with your own:

docscribe -a --rbs-collection --sig-dir sig lib

[!NOTE] --rbs-collection only improves types for methods defined in gems that ship RBS signatures. For your own classes, provide a sig/ directory with hand-written or generated .rbs files.

[!IMPORTANT] If rbs_collection.lock.yaml is missing or the collection directory does not exist on disk, Docscribe will print a warning and skip the collection. Run bundle exec rbs collection install first.

Sorbet

Docscribe can also read Sorbet signatures from:

  • inline sig declarations in Ruby source
  • RBI files

CLI:

docscribe -a --sorbet lib

With RBI directories:

docscribe -a --sorbet --rbi-dir sorbet/rbi lib

You can pass --rbi-dir multiple times:

docscribe -a --sorbet --rbi-dir sorbet/rbi --rbi-dir rbi lib

Config:

sorbet:
  enabled: true
  rbi_dirs:
    - sorbet/rbi
    - rbi
  collapse_generics: false

Inline Sorbet example

class Demo
  extend T::Sig

  sig { params(verbose: T::Boolean, count: Integer).returns(Integer) }
  def foo(verbose:, count:)
    'body says String'
  end
end

Docscribe will use the Sorbet signature instead of the inferred body type:

class Demo
  extend T::Sig

  # +Demo#foo+ -> Integer
  #
  # Method documentation.
  #
  # @param [Boolean] verbose Param documentation.
  # @param [Integer] count Param documentation.
  # @return [Integer]
  sig { params(verbose: T::Boolean, count: Integer).returns(Integer) }
  def foo(verbose:, count:)
    'body says String'
  end
end

Sorbet RBI example

# Ruby source
class Demo
  def foo(verbose:, count:)
    'body says String'
  end
end
# sorbet/rbi/demo.rbi
class Demo
  extend T::Sig

  sig { params(verbose: T::Boolean, count: Integer).returns(Integer) }
  def foo(verbose:, count:); end
end

With:

docscribe -a --sorbet --rbi-dir sorbet/rbi lib

Docscribe will use the RBI signature for generated docs.

Sorbet comment placement

For methods with a leading Sorbet sig, Docscribe treats the signature as part of the method header.

That means:

  • new docs are inserted above the first sig
  • existing docs above the sig are recognized and merged
  • existing legacy docs between sig and def are also recognized

Example input:

# demo.rb
class Demo
  extend T::Sig

  sig { returns(Integer) }
  def foo
    1
  end
end

Example output:

# demo.rb
class Demo
  extend T::Sig

  # +Demo#foo+ -> Integer
  #
  # Method documentation.
  #
  # @return [Integer]
  sig { returns(Integer) }
  def foo
    1
  end
end

Generic type formatting

Both RBS and Sorbet integrations support collapse_generics.

When disabled:

rbs:
  collapse_generics: false

sorbet:
  collapse_generics: false

Docscribe preserves generic container details where possible, for example:

  • Array<String>
  • Hash<Symbol, Integer>

When enabled:

rbs:
  collapse_generics: true

sorbet:
  collapse_generics: true

Docscribe simplifies container types to their outer names, for example:

  • Array
  • Hash

Notes and fallback behavior

  • External signature support is the best effort.
  • If a signature source cannot be loaded or parsed, Docscribe falls back to AST inference.
  • RBS and Sorbet integrations are used only to improve generated types; Docscribe still rewrites Ruby source directly.
  • Sorbet support does not require changing your documentation style — it only improves generated @param and @return tags when signatures are available.

Type inference

Heuristics (best-effort).

Parameters:

  • *args -> Array
  • **kwargs -> Hash
  • &block -> Proc
  • keyword args:
    • verbose: true -> Boolean
    • options: {} -> Hash
    • kw: (no default) -> Object
  • positional defaults:
    • 42 -> Integer, 1.0 -> Float, 'x' -> String, :ok -> Symbol
    • [] -> Array, {} -> Hash, /x/ -> Regexp, true/false -> Boolean, nil -> nil

Return values:

  • For simple bodies, Docscribe looks at the last expression or explicit return.
  • Unions with nil become optional types (e.g. String or nil -> String?).
  • For control flow (if/case), it unifies branches conservatively.
  • RBS core type inference: when --rbs is enabled, Docscribe resolves return types for method calls on core types from their RBS definitions:
    • arg.positive? (arg = 1) -> Boolean (from Integer#positive?)
    • arg.to_i (arg = "") -> Integer (from String#to_i)
    • arg.to_s.length (arg = 1) -> Integer (chained: Integer -> String -> Integer)
    • arg.upcase (arg = "") -> String (from String#upcase)
    • Rescue branches are also resolved (e.g. "default" -> String)

Rescue-aware returns and @raise

Docscribe detects exceptions and rescue branches:

  • Rescue exceptions become @raise tags:

    • rescue Foo, Bar -> @raise [Foo] and @raise [Bar]
    • bare rescue -> @raise [StandardError]
    • explicit raise/fail also adds a tag (raise Foo -> @raise [Foo], raise -> @raise [StandardError])
  • Conditional return types for rescue branches:

    • Docscribe adds @return [Type] if ExceptionA, ExceptionB for each rescue clause

Visibility semantics

We match Ruby's behavior:

  • A bare private/protected/public in a class/module body affects instance methods only.
  • Inside class << self, a bare visibility keyword affects class methods only.
  • def self.x in a class body remains public unless private_class_method is used, or it's inside class << self under private.

Inline tags:

  • @private is added for methods that are private in context.
  • @protected is added similarly for protected methods.

[!IMPORTANT] module_function: Docscribe documents methods affected by module_function as module methods (M.foo) rather than instance methods (M#foo), because that is usually the callable/public API. If a method was previously private as an instance method, Docscribe will avoid marking the generated docs as @private after it is promoted to a module method.

module M
  private

  def foo; end

  module_function :foo
end

API (library) usage

require "docscribe/inline_rewriter"

code = <<~RUBY
  class Demo
    def foo(a, options: {}); 42; end
    class << self; private; def internal; end; end
  end
RUBY

# Basic insertion behavior
out = Docscribe::InlineRewriter.insert_comments(code)
puts out

# Safe merge / normalization of existing doc-like blocks
out2 = Docscribe::InlineRewriter.insert_comments(code, strategy: :safe)

# Aggressive rebuild of existing doc blocks (similar to CLI -A)
out3 = Docscribe::InlineRewriter.insert_comments(code, strategy: :aggressive)

Plugin system

Docscribe ships a plugin system that lets you extend documentation generation without modifying the gem itself.

There are two extension points:

Type When it runs What it produces
TagPlugin After a method is collected and its doc block is being built Extra YARD tags appended to the block
CollectorPlugin Before doc building, alongside the standard AST collector New insertion targets for non-standard constructs

TagPlugin

A TagPlugin receives a snapshot of everything known about a method at generation time and returns zero or more additional YARD tags to append to the doc block.

class SincePlugin < Docscribe::Plugin::Base::TagPlugin
  def initialize(version:)
    @version = version
  end

  # @param [Docscribe::Plugin::Context] context
  # @return [Array<Docscribe::Plugin::Tag>]
  def call(context)
    [Docscribe::Plugin::Tag.new(name: 'since', text: @version)]
  end
end

The Context struct provides:

Attribute Type Description
node Parser::AST::Node The :def or :defs AST node
container String e.g. "MyModule::MyClass"
scope Symbol :instance or :class
visibility Symbol :public, :protected, or :private
method_name Symbol Method name
inferred_params Hash{String => String} Name -> inferred type
inferred_return String Inferred return type
source String Raw method source text

The Tag struct:

# Simple tag
Docscribe::Plugin::Tag.new(name: 'since', text: '1.3.0')
# => # @since 1.3.0

# Tag with types
Docscribe::Plugin::Tag.new(name: 'raise', types: ['ArgumentError'], text: 'if name is nil')
# => # @raise [ArgumentError] if name is nil

CollectorPlugin

A CollectorPlugin receives the raw AST and source buffer for each file. It walks the tree itself and returns insertion targets that Docscribe will document according to the selected strategy.

class DefineMethodPlugin < Docscribe::Plugin::Base::CollectorPlugin
  # @param [Parser::AST::Node] ast
  # @param [Parser::Source::Buffer] buffer
  # @return [Array<Hash>]
  def collect(ast, buffer)
    results = []

    Docscribe::Infer::ASTWalk.walk(ast) do |node|
      next unless node.type == :send

      _recv, meth, name_node, *_rest = *node
      next unless meth == :define_method
      next unless name_node&.type == :sym

      meth_name = name_node.children.first

      results << {
        anchor_node: node,
        doc: "# Dynamic method: #{meth_name}\n# @return [Object]\n"
      }
    end

    results
  end
end

Each result hash must have:

Key Type Description
:anchor_node Parser::AST::Node Node above which to insert the doc block
:doc String Complete doc block text including newlines

[!NOTE] You do not need to handle indentation manually. Docscribe reads the indentation from anchor_node and applies it to every line of :doc automatically.

Registering plugins

Plugins are registered at load time. The recommended pattern is to put registrations in a dedicated file and reference it from docscribe.yml.

docscribe_plugins.rb (in your project root or lib/):

require 'docscribe/plugin'

# Tag plugin
class SincePlugin < Docscribe::Plugin::Base::TagPlugin
  def call(context)
    [Docscribe::Plugin::Tag.new(name: 'since', text: '1.3.0')]
  end
end

# Collector plugin
class DefineMethodPlugin < Docscribe::Plugin::Base::CollectorPlugin
  def collect(ast, buffer)
    # ...
  end
end

Docscribe::Plugin::Registry.register(SincePlugin.new)
Docscribe::Plugin::Registry.register(DefineMethodPlugin.new)

docscribe.yml:

plugins:
  require:
    - ./docscribe_plugins

Each entry is passed to require. The path is expanded relative to the current working directory.

Duck typing is also supported — any object responding to #call is treated as a TagPlugin, any object responding to #collect is treated as a CollectorPlugin:

# Lambda as a TagPlugin
Docscribe::Plugin::Registry.register(
  ->(context) { [Docscribe::Plugin::Tag.new(name: 'api', text: 'public')] }
)

Idempotency

Docscribe handles idempotency for plugins automatically.

TagPlugin: before appending a tag, Docscribe checks whether a tag with that name already exists in the current doc block. If it does, the tag is skipped.

CollectorPlugin: idempotency depends on the selected strategy.

Strategy Behaviour
:safe Skips insertion if any comment block already exists immediately above anchor_node
:aggressive Removes the existing comment block above anchor_node and inserts a fresh doc block

This means a CollectorPlugin-generated block will not be duplicated on repeated safe runs, and will be fully rebuilt on aggressive runs.

Plugin examples

Sample plugin available at examples

Configuration

Docscribe can be configured via a YAML file (docscribe.yml by default, or pass --config PATH).

Filtering

Docscribe can filter both files and methods.

File filtering (recommended for excluding specs, vendor code, etc.):

filter:
  files:
    exclude: [ "spec" ]

Method filtering matches method ids like:

  • MyModule::MyClass#instance_method
  • MyModule::MyClass.class_method

Example:

filter:
  exclude:
    - "*#initialize"

CLI overrides are available too:

# Method filtering (matches method ids like A#foo / A.bar)
docscribe --exclude '*#initialize' lib
docscribe --include '/^MyModule::.*#(foo|bar)$/' lib

# File filtering (matches paths relative to the project root)
docscribe --exclude-file 'spec' lib spec
docscribe --exclude-file '/^spec\//' lib

[!NOTE] /regex/ passed to --include/--exclude is treated as a method-id pattern. Use --include-file / --exclude-file for file regex filters.

Enable attribute-style documentation generation with:

emit:
  attributes: true

When enabled, Docscribe can generate YARD @!attribute docs for:

  • attr_reader
  • attr_writer
  • attr_accessor
  • Struct.new declarations

attr_* example

[!NOTE]

  • Attribute docs are inserted above the attr_* call, not above generated methods (since they don’t exist as def nodes).
  • If RBS is enabled, Docscribe will try to use the RBS return type of the reader method as the attribute type.
class User
  attr_accessor :name
end

Generated docs:

class User
  # @!attribute [rw] name
  #   @return [Object]
  #   @param [Object] value
  attr_accessor :name
end

Struct.new examples

Docscribe supports both common Struct.new declaration styles.

Constant-assigned struct

User = Struct.new(:name, :email, keyword_init: true)

Generated docs:

# @!attribute [rw] name
#   @return [Object]
#   @param [Object] value
#
# @!attribute [rw] email
#   @return [Object]
#   @param [Object] value
User = Struct.new(:name, :email, keyword_init: true)

Class-based struct

class User < Struct.new(:name, :email, keyword_init: true)
end

Generated docs:

# @!attribute [rw] name
#   @return [Object]
#   @param [Object] value
#
# @!attribute [rw] email
#   @return [Object]
#   @param [Object] value
class User < Struct.new(:name, :email, keyword_init: true)
end

Docscribe preserves the original declaration style and does not rewrite one form into the other.

Merge behavior

Struct member docs use the same attribute documentation pipeline as attr_* macros, which means they participate in the normal safe/aggressive rewrite flow.

In safe mode, Docscribe can:

  • insert full @!attribute docs when no doc-like block exists
  • append missing struct member docs into an existing doc-like block

Param tag style

Generated writer-style attribute docs respect doc.param_tag_style.

For example, with:

doc:
  param_tag_style: "type_name"

writer params are emitted as:

#   @param [Object] value

With:

doc:
  param_tag_style: "name_type"

they are emitted as:

#   @param value [Object]

Create a starter config

Create docscribe.yml in the current directory:

docscribe init

Write to a custom path:

docscribe init --config config/docscribe.yml

Overwrite if it already exists:

docscribe init --force

Print the template to stdout:

docscribe init --stdout

Generate a plugin skeleton

Docscribe can scaffold a plugin file so you don't have to write boilerplate by hand.

Generate a TagPlugin:

docscribe generate tag MyPlugin
# Created: my_plugin.rb

Generate a CollectorPlugin:

docscribe generate collector MyCollector
# Created: my_collector.rb

Write to a specific directory:

docscribe generate tag SincePlugin --output lib/plugins
# Created: lib/plugins/since_plugin.rb

Print to STDOUT instead of writing a file:

docscribe generate tag SincePlugin --stdout

The generated file contains:

  • the correct base class (Base::TagPlugin or Base::CollectorPlugin)
  • inline comments describing every available Context attribute (TagPlugin) or the expected return shape (CollectorPlugin)
  • TODO markers showing exactly where to add your logic
  • registration and next-steps instructions printed to the terminal

[!NOTE] The class name must be a valid Ruby constant (MyPlugin, My::Plugin). The output filename is the snake_case equivalent (my_plugin.rb, my/plugin.rb).

CI integration

Fail the build if files would need safe updates:

- name: Check inline docs
  run: docscribe lib

Apply safe fixes before the test stage:

- name: Apply safe inline docs
  run: docscribe -a lib

Aggressively rebuild docs:

- name: Rebuild inline docs
  run: docscribe -A lib

Comparison to YARD's parser

Docscribe and YARD solve different parts of the documentation problem:

  • Docscribe inserts/updates inline comments by rewriting source.
  • YARD can generate HTML docs based on inline comments.

Recommended workflow:

  • Use Docscribe to seed and maintain inline docs with inferred tags/types.
  • Optionally use YARD (dev-only) to render HTML from those comments:
yard doc -o docs

Limitations

  • Safe mode only merges into existing doc-like comment blocks. Ordinary comments that are not recognized as documentation are preserved and treated conservatively.
  • Type inference is heuristic. Complex flows and meta-programming will fall back to Object or best-effort types.
  • Aggressive mode (-A) replaces existing doc blocks and should be reviewed carefully.

Roadmap

  • Method behavior inference from AST;
  • YAML-based plugin configuration;
  • Effective config dump;
  • JSON output;
  • Overload-aware signature selection;
  • Manual @!attribute merge policy;
  • Richer inference for common APIs;
  • Editor integration.

Contributing

bundle exec rspec
bundle exec rubocop

Discussion & Community

License

MIT